├── .gitignore ├── .travis.yml ├── README.md ├── index.js ├── package-lock.json ├── package.json └── test └── mongoose-type-email.test.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | 30 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - node -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mongoose-type-email 2 | 3 | An email field-type for Mongoose schemas 4 | 5 | [![Code Climate](https://codeclimate.com/github/konsumer/mongoose-type-email/badges/gpa.svg)](https://codeclimate.com/github/konsumer/mongoose-type-email) 6 | 7 | [![npm](https://nodei.co/npm/mongoose-type-email.png)](https://www.npmjs.com/package/mongoose-type-email) 8 | 9 | ## usage 10 | 11 | This will validate email, correctly: 12 | 13 | ```js 14 | var mongoose = require('mongoose'); 15 | require('mongoose-type-email'); 16 | 17 | var UserSchema = new mongoose.Schema({ 18 | email: { 19 | work: mongoose.SchemaTypes.Email, 20 | home: mongoose.SchemaTypes.Email 21 | } 22 | }); 23 | ``` 24 | 25 | You can also use the stuff in `String` type: 26 | 27 | ```js 28 | var UserSchema = new mongoose.Schema({ 29 | email: { 30 | work: {type: mongoose.SchemaTypes.Email, required: true}, 31 | home: {type: mongoose.SchemaTypes.Email, required: true}, 32 | } 33 | }); 34 | ``` 35 | 36 | You can also use it as an array: 37 | 38 | 39 | ```js 40 | var UserSchema = new mongoose.Schema({ 41 | emails: [{type: mongoose.SchemaTypes.Email}] 42 | }); 43 | ``` 44 | 45 | You can add 'allowBlank: true' in order to allow empty string ('') when the field is not required 46 | 47 | ```js 48 | var mongoose = require('mongoose'); 49 | require('mongoose-type-email'); 50 | 51 | var UserSchema = new mongoose.Schema({ 52 | email: { 53 | work: { type: mongoose.SchemaTypes.Email, allowBlank: true }, // allows '' as a value 54 | home: mongoose.SchemaTypes.Email // throws when the value is '' 55 | } 56 | }); 57 | ``` 58 | 59 | You can specify a default custom error message by overriding `mongoose.SchemaTypes.Email.defaults.message` 60 | 61 | ```js 62 | var mongoose = require('mongoose'); 63 | require('mongoose-type-email'); 64 | mongoose.SchemaTypes.Email.defaults.message = 'Email address is invalid' 65 | 66 | var UserSchema = new mongoose.Schema({ 67 | email: { 68 | work: mongoose.SchemaTypes.Email, 69 | home: mongoose.SchemaTypes.Email 70 | } 71 | }); 72 | ``` 73 | 74 | By default, this library follows the same validation you see in the [html spec for `type=email`](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) which allows local email addresses, and other non-standard email types. If you want more complete TLD validation (eg `user@host.com`) you can use the `correctTld` options: 75 | 76 | ```js 77 | var UserSchema = new mongoose.Schema({ 78 | email: { 79 | work: {type: mongoose.SchemaTypes.Email, correctTld: true}, 80 | home: {type: mongoose.SchemaTypes.Email, correctTld: true}, 81 | } 82 | }); 83 | ``` -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | var isEmail = require('validator/lib/isEmail') 3 | 4 | // http://www.w3.org/TR/html5/forms.html#valid-e-mail-address 5 | var regEmail = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ 6 | 7 | function validateEmail (val, options) { 8 | var required = (typeof options.required === 'function') ? options.required() : options.required 9 | var passedAllowBlank = options.allowBlank && (val === '' || val === null) 10 | if (passedAllowBlank && !required) { 11 | return true 12 | } 13 | return options.correctTld ? isEmail(val) : regEmail.test(val) 14 | } 15 | 16 | function Email (path, options) { 17 | this.options = options 18 | this.path = path 19 | mongoose.SchemaTypes.String.call(this, path, options) 20 | this.validate(function (val) { return validateEmail(val, options) }, options.message || Email.defaults.message || 'invalid email address') 21 | } 22 | 23 | Email.defaults = {} 24 | 25 | Object.setPrototypeOf(Email.prototype, mongoose.SchemaTypes.String.prototype) 26 | 27 | Email.prototype.cast = function (val) { 28 | return val.toLowerCase() 29 | } 30 | 31 | Email.prototype.get = function (val) { 32 | return val.toLowerCase() 33 | } 34 | 35 | Email.prototype.checkRequired = function (val) { 36 | return typeof val === 'string' && validateEmail(val, this.options) 37 | } 38 | 39 | mongoose.SchemaTypes.Email = module.exports = Email 40 | mongoose.Types.Email = String 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongoose-type-email", 3 | "version": "1.1.2", 4 | "description": "An email field-type for Mongoose schemas", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "jest", 8 | "release": "release-it -p -n" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/konsumer/mongoose-type-email.git" 13 | }, 14 | "keywords": [ 15 | "mongoose", 16 | "types", 17 | "email", 18 | "schema" 19 | ], 20 | "author": "David Konsumer ", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/konsumer/mongoose-type-email/issues" 24 | }, 25 | "homepage": "https://github.com/konsumer/mongoose-type-email", 26 | "devDependencies": { 27 | "jest": "^24.7.1", 28 | "mockingoose": "^2.9.1", 29 | "mongoose": "^5.10.14", 30 | "release-it": "^14.2.1" 31 | }, 32 | "peerDependencies": { 33 | "mongoose": "*" 34 | }, 35 | "jest": { 36 | "testEnvironment": "node" 37 | }, 38 | "dependencies": { 39 | "validator": "^13.1.17" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/mongoose-type-email.test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, expect, beforeAll, afterAll */ 2 | require('mockingoose') 3 | var mongoose = require('mongoose') 4 | require('../') 5 | 6 | mongoose.Promise = Promise 7 | 8 | var UserSimple = mongoose.model('UserSimple', new mongoose.Schema({ 9 | email: mongoose.SchemaTypes.Email 10 | })) 11 | 12 | var UserAllowBlank = mongoose.model('UserAllowBlank', new mongoose.Schema({ 13 | email: { type: mongoose.SchemaTypes.Email, allowBlank: true } 14 | })) 15 | 16 | var UserRequired = mongoose.model('UserRequired', new mongoose.Schema({ 17 | email: { type: mongoose.SchemaTypes.Email, required: true } 18 | })) 19 | 20 | var UserNested = mongoose.model('UserNested', new mongoose.Schema({ 21 | email: { 22 | work: { type: mongoose.SchemaTypes.Email, required: true }, 23 | home: { type: mongoose.SchemaTypes.Email, required: true } 24 | } 25 | })) 26 | 27 | var UserCustomMessage = mongoose.model('UserCustomMessage', new mongoose.Schema({ 28 | email: { type: mongoose.SchemaTypes.Email, message: 'error.email' } 29 | })) 30 | 31 | var UserTld = mongoose.model('UserTld', new mongoose.Schema({ 32 | email: { type: mongoose.SchemaTypes.Email, correctTld: true } 33 | })) 34 | 35 | describe('mongoose-type-email', function () { 36 | it('should enable basic email field-type in schema', function (done) { 37 | var user = new UserSimple() 38 | user.save(done) 39 | }) 40 | 41 | it('should not enable blank value', function (done) { 42 | var user = new UserSimple() 43 | user.email = '' 44 | user.validate(function (err) { 45 | expect(err.errors.email.message).toEqual('invalid email address') 46 | done() 47 | }) 48 | }) 49 | 50 | it('should enable an empty string value when allowBlank', function (done) { 51 | var user = new UserAllowBlank() 52 | user.email = '' 53 | user.save(done) 54 | }) 55 | 56 | it('should enable a null value when allowBlank', function (done) { 57 | var user = new UserAllowBlank() 58 | user.email = null 59 | user.save(done) 60 | }) 61 | 62 | it('should require email', function (done) { 63 | var user = new UserRequired() 64 | user.validate(function (err) { 65 | expect(err.errors.email.message).toEqual('Path `email` is required.') 66 | done() 67 | }) 68 | }) 69 | 70 | it('should enable nested required email', function (done) { 71 | var user = new UserNested() 72 | user.validate(function (err) { 73 | expect(err.errors['email.home'].message).toEqual('Path `email.home` is required.') 74 | expect(err.errors['email.work'].message).toEqual('Path `email.work` is required.') 75 | done() 76 | }) 77 | }) 78 | 79 | it('should not enable blank value with custom message', function (done) { 80 | var user = new UserCustomMessage() 81 | user.email = '' 82 | user.validate(function (err) { 83 | expect(err.errors.email.message).toEqual('error.email') 84 | done() 85 | }) 86 | }) 87 | 88 | describe('Default error message', () => { 89 | var UserDefaultCustomMessage 90 | beforeAll(() => { 91 | mongoose.SchemaTypes.Email.defaults.message = 'Email address is invalid' 92 | UserDefaultCustomMessage = mongoose.model('UserDefaultCustomMessage', new mongoose.Schema({ 93 | email: { type: mongoose.SchemaTypes.Email } 94 | })) 95 | }) 96 | 97 | afterAll(() => { 98 | delete mongoose.SchemaTypes.Email.defaults.message 99 | }) 100 | 101 | it('should not enable blank value with custom default message', function (done) { 102 | var user = new UserDefaultCustomMessage() 103 | user.email = '' 104 | user.validate(function (err) { 105 | expect(err.errors.email.message).toEqual('Email address is invalid') 106 | done() 107 | }) 108 | }) 109 | 110 | it('should require correct tld', function (done) { 111 | var user = new UserTld() 112 | user.email = 'hansvon@vermine' 113 | user.validate(function (err) { 114 | expect(err.errors.email.message).toEqual('invalid email address') 115 | done() 116 | }) 117 | }) 118 | }) 119 | }) 120 | --------------------------------------------------------------------------------