From 83defd2d77203fa3b1d6303327778d6d93c9ff4f Mon Sep 17 00:00:00 2001 From: Joseph Thibeault Date: Tue, 23 May 2017 15:10:19 -0400 Subject: [PATCH] feat(*): handle required or empty string field if not required (#36) --- .babelrc | 3 - .editorconfig | 2 +- .gitignore | 1 + README.md | 2 - gulpfile.js | 57 +++--- index.js | 2 + lib/intl-phone-number.js | 164 ++++++++---------- lib/mongoose-intl-phone-number.js | 60 ++++--- .../mongoose-intl-phone-number.spec.js | 26 ++- package.json | 18 +- src-es6/intl-phone-number.js | 102 ----------- src-es6/mongoose-intl-phone-number.js | 102 ----------- 12 files changed, 155 insertions(+), 384 deletions(-) delete mode 100644 .babelrc rename {src-es6 => lib}/mongoose-intl-phone-number.spec.js (90%) delete mode 100644 src-es6/intl-phone-number.js delete mode 100644 src-es6/mongoose-intl-phone-number.js diff --git a/.babelrc b/.babelrc deleted file mode 100644 index c13c5f6..0000000 --- a/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["es2015"] -} diff --git a/.editorconfig b/.editorconfig index e65cd21..9203ffd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,4 +8,4 @@ indent_size = 4 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true -insert_final_newline = false +insert_final_newline = true \ No newline at end of file diff --git a/.gitignore b/.gitignore index 648ea07..83e1c34 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules coverage npm-debug.log +.DS_Store diff --git a/README.md b/README.md index 934fe03..6c62868 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ mongoose-intl-phone-number ==================== - -[![Greenkeeper badge](https://badges.greenkeeper.io/Dashride/mongoose-intl-phone-number.svg)](https://greenkeeper.io/) [![Build Status](https://travis-ci.org/Dashride/mongoose-intl-phone-number.svg?branch=master)](https://travis-ci.org/Dashride/mongoose-intl-phone-number) [![Coverage Status](https://coveralls.io/repos/Dashride/mongoose-intl-phone-number/badge.svg?branch=master&service=github)](https://coveralls.io/github/Dashride/mongoose-intl-phone-number?branch=master) [![Dependency Status](https://david-dm.org/Dashride/mongoose-intl-phone-number.svg)](https://david-dm.org/Dashride/mongoose-intl-phone-number) diff --git a/gulpfile.js b/gulpfile.js index a3a7390..a0ef820 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,40 +1,27 @@ 'use strict'; -require('babel-core/register'); +const fs = require('fs'); +const gulp = require('gulp'); +const gutil = require('gulp-util'); +const mocha = require('gulp-mocha'); +const istanbul = require('gulp-istanbul'); +const jshint = require('gulp-jshint'); +const jsdoc2md = require('gulp-jsdoc-to-markdown'); +const concat = require('gulp-concat'); +const isparta = require('isparta'); -var fs = require('fs'), - gulp = require('gulp'), - gutil = require("gulp-util"), - mocha = require('gulp-mocha'), - istanbul = require('gulp-istanbul'), - jshint = require('gulp-jshint'), - jsdoc2md = require('gulp-jsdoc-to-markdown'), - concat = require("gulp-concat"), - babel = require('gulp-babel'), - isparta = require('isparta'); - -var paths = { - es6: { - js: ['./src-es6/**/*.js', '!./**/*.spec.js'], - specs: ['./src-es6/**/*.spec.js'], - all: ['./src-es6/**/*.js', '!./coverage/**/*.js', '!./node_modules/**/*.js'] - }, +const paths = { js: ['./**/*.js', '!./**/*.spec.js', '!./coverage/**/*.js', '!./node_modules/**/*.js'], - specs: ['./**/*.spec.js'], + specs: ['./lib/*.spec.js'], + coverage: ['./lib/*.js', '!./lib/*spec.js'], all: ['./**/*.js', '!./coverage/**/*.js', '!./node_modules/**/*.js'] }; gulp.task('watch', ['test'], function (done) { - var glob = paths.es6.all; + const glob = paths.es6.all; return gulp.watch(glob, ['test']); }); -gulp.task('6to5', function () { - return gulp.src(paths.es6.js) - .pipe(babel()) - .pipe(gulp.dest('lib')); -}); - gulp.task('lint', function() { return gulp.src(paths.all) .pipe(jshint()) @@ -43,53 +30,53 @@ gulp.task('lint', function() { }); gulp.task('coveralls', function(done) { - return gulp.src(paths.es6.js) + return gulp.src(paths.coverage) .pipe(istanbul({ instrumenter: isparta.Instrumenter, includeUntested: true })) .pipe(istanbul.hookRequire()) .on('finish', function() { - return gulp.src(paths.es6.specs) + return gulp.src(paths.specs) .pipe(mocha({ reporter: 'spec' })) .pipe(istanbul.writeReports({ - reporters: [ 'lcovonly', 'text' ], + reporters: ['lcovonly', 'text'], })); }); }); gulp.task('coverage', function(done) { - return gulp.src(paths.es6.js) + return gulp.src(paths.coverage) .pipe(istanbul({ instrumenter: isparta.Instrumenter, includeUntested: false })) .pipe(istanbul.hookRequire()) .on('finish', function() { - return gulp.src(paths.es6.specs) + return gulp.src(paths.specs) .pipe(mocha({ reporter: 'spec' })) .pipe(istanbul.writeReports({ - reporters: [ 'text', 'html' ], + reporters: ['text', 'html'], })); }); }); gulp.task('test', [/*'lint'*/], function(done) { - return gulp.src(paths.es6.specs) + return gulp.src(paths.specs) .pipe(mocha({ reporter: 'spec' })); }); gulp.task('docs', function() { - return gulp.src(paths.es6.js) + return gulp.src(paths.js) .pipe(concat('README.md')) .pipe(jsdoc2md({template: fs.readFileSync('./readme.hbs', 'utf8')})) - .on('error', function(err){ + .on('error', function(err) { gutil.log('jsdoc2md failed:', err.message); }) .pipe(gulp.dest('.')); diff --git a/index.js b/index.js index aa576d6..ef8e62d 100644 --- a/index.js +++ b/index.js @@ -1 +1,3 @@ +'use strict'; + module.exports = require('./lib/mongoose-intl-phone-number').mongooseIntlPhoneNumber; diff --git a/lib/intl-phone-number.js b/lib/intl-phone-number.js index 1b0ebe4..2263926 100644 --- a/lib/intl-phone-number.js +++ b/lib/intl-phone-number.js @@ -1,46 +1,43 @@ 'use strict'; -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.IntlPhoneNumber = undefined; +const PhoneNumberUtil = require('google-libphonenumber').PhoneNumberUtil; -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); +const phoneUtil = PhoneNumberUtil.getInstance(); -var _googleLibphonenumber = require('google-libphonenumber'); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var phoneUtil = _googleLibphonenumber.PhoneNumberUtil.getInstance(); - -var PhoneNumberFormat = { +const PhoneNumberFormat = { E164: 0, INTERNATIONAL: 1, NATIONAL: 2, RFC3966: 3 }; -var PhoneNumberErrorCodes = { +// https://github.com/seegno/google-libphonenumber/blob/4a210137662fd1d4c2d9d37f54c3f6c366458985/src/phonenumberutil.js#L965 +const PhoneNumberErrorCodes = { IS_POSSIBLE: 0, INVALID_COUNTRY_CODE: 1, TOO_SHORT: 2, - TOO_LONG: 3 + TOO_LONG: 3, + IS_POSSIBLE_LOCAL_ONLY: 4, + INVALID_LENGTH: 5, }; -var PhoneNumberErrorReasons = ['Number is unknown.', 'Country code is invalid.', 'Number is too short.', 'Number is too long.']; +const PhoneNumberErrorReasons = [ + 'Number is unknown.', + 'Country code is invalid.', + 'Number is too short.', + 'Number is too long.', + 'Number is an unknown local number.', + 'Number length is invalid for this region.', +]; /** * @class IntlPhoneNumber */ - -var IntlPhoneNumber = function () { +class IntlPhoneNumber { /** * @param {string} phoneNumber */ - - function IntlPhoneNumber(phoneNumber) { - _classCallCheck(this, IntlPhoneNumber); - + constructor(phoneNumber) { this.phoneNumber = phoneNumber; this.number = phoneUtil.parseAndKeepRawInput(phoneNumber); } @@ -49,89 +46,66 @@ var IntlPhoneNumber = function () { * Determines if the number is valid. * @return {boolean} */ + get isValid() { + return phoneUtil.isValidNumber(this.number) && phoneUtil.isPossibleNumber(this.number); + } + /** + * Returns the country code for the parsed number. + * @return {string} + */ + get countryCode() { + return phoneUtil.getRegionCodeForNumber(this.number); + } - _createClass(IntlPhoneNumber, [{ - key: 'isValid', - get: function get() { - return phoneUtil.isValidNumber(this.number) && phoneUtil.isPossibleNumber(this.number); - } - - /** - * Returns the country code for the parsed number. - * @return {string} - */ - - }, { - key: 'countryCode', - get: function get() { - return phoneUtil.getRegionCodeForNumber(this.number); - } - - /** - * Returns the e164 format for the parsed number. - * @return {string} - */ - - }, { - key: 'e164Format', - get: function get() { - return phoneUtil.format(this.number, PhoneNumberFormat.E164); - } - - /** - * Returns the national format for the parsed number. - * @return {string} - */ - - }, { - key: 'nationalFormat', - get: function get() { - return phoneUtil.format(this.number, PhoneNumberFormat.NATIONAL); - } - - /** - * Returns the international format for the parsed number. - * @return {string} - */ + /** + * Returns the e164 format for the parsed number. + * @return {string} + */ + get e164Format() { + return phoneUtil.format(this.number, PhoneNumberFormat.E164); + } - }, { - key: 'internationalFormat', - get: function get() { - return phoneUtil.format(this.number, PhoneNumberFormat.INTERNATIONAL); - } + /** + * Returns the national format for the parsed number. + * @return {string} + */ + get nationalFormat() { + return phoneUtil.format(this.number, PhoneNumberFormat.NATIONAL); + } - /** - * Determines the proper error message based on the error code. - * @return {string} - */ + /** + * Returns the international format for the parsed number. + * @return {string} + */ + get internationalFormat() { + return phoneUtil.format(this.number, PhoneNumberFormat.INTERNATIONAL); + } - }, { - key: 'errorMsg', - get: function get() { - var message = 'Phone number is not valid.'; + /** + * Determines the proper error message based on the error code. + * @return {string} + */ + get errorMsg() { + let message = 'Phone number is not valid.'; - var errorCode = this.errorCode; - var reason = PhoneNumberErrorReasons[errorCode]; + const errorCode = this.errorCode; + const reason = PhoneNumberErrorReasons[errorCode]; + if (reason) { message += ' ' + reason; - - return message; } - /** - * Determines the error code for a number that was not able to be parsed. - * @return {number} - */ - - }, { - key: 'errorCode', - get: function get() { - return phoneUtil.isPossibleNumberWithReason(this.number); - } - }]); + return message; + } - return IntlPhoneNumber; -}(); + /** + * Determines the error code for a number that was not able to be parsed. + * @return {number} + */ + get errorCode() { + return phoneUtil.isPossibleNumberWithReason(this.number); + } +} -exports.IntlPhoneNumber = IntlPhoneNumber; \ No newline at end of file +exports.IntlPhoneNumber = IntlPhoneNumber; diff --git a/lib/mongoose-intl-phone-number.js b/lib/mongoose-intl-phone-number.js index 58cce08..6126b13 100644 --- a/lib/mongoose-intl-phone-number.js +++ b/lib/mongoose-intl-phone-number.js @@ -1,13 +1,7 @@ 'use strict'; -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.mongooseIntlPhoneNumber = undefined; - -var _intlPhoneNumber = require('./intl-phone-number'); - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +const IntlPhoneNumber = require('./intl-phone-number').IntlPhoneNumber; +const _ = require('lodash'); /** * @module mongooseIntlPhoneNumber @@ -63,44 +57,53 @@ Resulting document... * @param {string} [options.internationalFormatField=internationalFormat] * @param {string} [options.countryCodeField=countryCode] */ -function mongooseIntlPhoneNumber(schema) { - var _ref = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; +function mongooseIntlPhoneNumber(schema, options) { + if (_.isUndefined(options)) options = {}; - var _ref$hook = _ref.hook; - var hook = _ref$hook === undefined ? 'validate' : _ref$hook; - var _ref$phoneNumberField = _ref.phoneNumberField; - var phoneNumberField = _ref$phoneNumberField === undefined ? 'phoneNumber' : _ref$phoneNumberField; - var _ref$nationalFormatFi = _ref.nationalFormatField; - var nationalFormatField = _ref$nationalFormatFi === undefined ? 'nationalFormat' : _ref$nationalFormatFi; - var _ref$internationalFor = _ref.internationalFormatField; - var internationalFormatField = _ref$internationalFor === undefined ? 'internationalFormat' : _ref$internationalFor; - var _ref$countryCodeField = _ref.countryCodeField; - var countryCodeField = _ref$countryCodeField === undefined ? 'countryCode' : _ref$countryCodeField; + _.defaults(options, { + hook: 'validate', + phoneNumberField: 'phoneNumber', + nationalFormatField: 'nationalFormat', + internationalFormatField: 'internationalFormat', + countryCodeField: 'countryCode', + }); + const hook = options.hook; + const phoneNumberField = options.phoneNumberField; + const nationalFormatField = options.nationalFormatField; + const internationalFormatField = options.internationalFormatField; + const countryCodeField = options.countryCodeField; // If paths don't exist in schema add them - [phoneNumberField, nationalFormatField, internationalFormatField, countryCodeField].forEach(function (path) { + [phoneNumberField, nationalFormatField, internationalFormatField, countryCodeField].forEach(function(path) { if (!schema.path(path)) { - schema.add(_defineProperty({}, path, { type: String })); + schema.add({ + [path]: { type: String } + }); } }); schema.pre(hook, function parsePhoneNumber(next) { - // Only return validation errors if the document is new or phone number has been modified. - if (this.isNew || this.isDirectModified(phoneNumberField)) { - try { - var phoneNumber = this.get(phoneNumberField); - var intlPhoneNumber = new _intlPhoneNumber.IntlPhoneNumber(phoneNumber); + const isRequired = schema.path(phoneNumberField).isRequired; + const hasPhoneNumber = this.get(phoneNumberField).length > 0; + // Only return validation errors if the document is new or phone number has been modified + // and if the field is required. If not required, then only run it if the field has length. + if ((isRequired || hasPhoneNumber) && (this.isNew || this.isDirectModified(phoneNumberField))) { + try { + const phoneNumber = this.get(phoneNumberField); + const intlPhoneNumber = new IntlPhoneNumber(phoneNumber); if (intlPhoneNumber.isValid) { this.set(phoneNumberField, intlPhoneNumber.e164Format); this.set(nationalFormatField, intlPhoneNumber.nationalFormat); this.set(internationalFormatField, intlPhoneNumber.internationalFormat); this.set(countryCodeField, intlPhoneNumber.countryCode); next(); + } else { next(new Error(intlPhoneNumber.errorMsg)); } + } catch (e) { next(e); } @@ -108,6 +111,7 @@ function mongooseIntlPhoneNumber(schema) { next(); } }); + } -exports.mongooseIntlPhoneNumber = mongooseIntlPhoneNumber; \ No newline at end of file +exports.mongooseIntlPhoneNumber = mongooseIntlPhoneNumber; diff --git a/src-es6/mongoose-intl-phone-number.spec.js b/lib/mongoose-intl-phone-number.spec.js similarity index 90% rename from src-es6/mongoose-intl-phone-number.spec.js rename to lib/mongoose-intl-phone-number.spec.js index a1a6359..e2a54c0 100644 --- a/src-es6/mongoose-intl-phone-number.spec.js +++ b/lib/mongoose-intl-phone-number.spec.js @@ -1,8 +1,8 @@ 'use strict'; const mongoose = require('mongoose'); -const { expect } = require('chai'); -const { mongooseIntlPhoneNumber } = require('./mongoose-intl-phone-number'); +const expect = require('chai').expect; +const mongooseIntlPhoneNumber = require('./mongoose-intl-phone-number').mongooseIntlPhoneNumber; const Schema = mongoose.Schema; let connection; @@ -145,7 +145,7 @@ describe('Mongoose plugin: mongoose-intl-phone-number', function() { email: 'test@testing.com' }); - customer.save().then((customer) => { + return customer.save().then((customer) => { throw new Error('no error was thrown'); }).catch((err) => { expect(err.message).to.equal('Phone number is not valid. Number is too short.'); @@ -161,7 +161,7 @@ describe('Mongoose plugin: mongoose-intl-phone-number', function() { email: 'test@testing.com' }); - customer.save().then((customer) => { + return customer.save().then((customer) => { throw new Error('no error was thrown'); }).catch((err) => { expect(err.message).to.equal('Invalid country calling code'); @@ -177,12 +177,28 @@ describe('Mongoose plugin: mongoose-intl-phone-number', function() { email: 'test@testing.com' }); - customer.save().then((customer) => { + return customer.save().then((customer) => { throw new Error('no error was thrown'); }).catch((err) => { expect(err.message).to.equal('Phone number is not valid. Number is unknown.'); }); }); + + it('should throw an error if the number is an unknown local number', function() { + const customer = new Customer({ + firstName: 'test', + lastName: 'customer', + customerType: 'testing', + phoneNumber: '+1 2530000', + email: 'test@testing.com' + }); + + return customer.save().then((customer) => { + throw new Error('no error was thrown'); + }).catch((err) => { + expect(err.message).to.equal('Phone number is not valid. Number is an unknown local number.'); + }); + }); }); describe('with default overrides', function() { diff --git a/package.json b/package.json index c0d5519..d0be609 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,11 @@ "description": "A configurable mongoose.js plugin that parses phone numbers and stores data about them in the document.", "main": "index.js", "scripts": { - "compile": "gulp 6to5", "test": "gulp test", "coveralls": "gulp coveralls", "travis": "npm run coveralls -s && ((cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js) || exit 0)", "docs": "gulp docs", - "prepublish": "npm run compile && npm run docs", + "prepublish": "npm run docs", "semantic-release": "semantic-release pre && npm publish && semantic-release post" }, "repository": { @@ -29,27 +28,24 @@ }, "homepage": "https://github.com/Dashride/mongoose-intl-phone-number", "devDependencies": { - "babel": "^6.5.2", - "babel-core": "^6.21.0", - "babel-preset-es2015": "^6.14.0", "chai": "^3.2.0", - "coveralls": "^2.11.14", + "coveralls": "^2.13.1", "gulp": "^3.9.0", - "gulp-babel": "^6.1.2", "gulp-concat": "^2.6.0", "gulp-istanbul": "^1.0.0", "gulp-jsdoc-to-markdown": "^1.1.1", "gulp-jshint": "^2.0.0", - "gulp-mocha": "^3.0.0", + "gulp-mocha": "^3.0.1", "gulp-util": "^3.0.6", "isparta": "^4.0.0", "jshint": "^2.9.3", "jshint-stylish": "^2.0.1", - "mocha": "^3.1.0", + "mocha": "^3.4.1", "mongoose": "^4.8.1", - "semantic-release": "^6.3.2" + "semantic-release": "^6.3.6" }, "dependencies": { - "google-libphonenumber": "^2.0.9" + "google-libphonenumber": "^2.0.15", + "lodash": "^4.17.4" } } diff --git a/src-es6/intl-phone-number.js b/src-es6/intl-phone-number.js deleted file mode 100644 index 12c96a2..0000000 --- a/src-es6/intl-phone-number.js +++ /dev/null @@ -1,102 +0,0 @@ -import { PhoneNumberUtil } from 'google-libphonenumber'; - -var phoneUtil = PhoneNumberUtil.getInstance(); - -const PhoneNumberFormat = { - E164: 0, - INTERNATIONAL: 1, - NATIONAL: 2, - RFC3966: 3 -}; - -const PhoneNumberErrorCodes = { - IS_POSSIBLE: 0, - INVALID_COUNTRY_CODE: 1, - TOO_SHORT: 2, - TOO_LONG: 3 -}; - -const PhoneNumberErrorReasons = [ - 'Number is unknown.', - 'Country code is invalid.', - 'Number is too short.', - 'Number is too long.' -]; - -/** - * @class IntlPhoneNumber - */ -class IntlPhoneNumber { - /** - * @param {string} phoneNumber - */ - constructor(phoneNumber) { - this.phoneNumber = phoneNumber; - this.number = phoneUtil.parseAndKeepRawInput(phoneNumber); - } - - /** - * Determines if the number is valid. - * @return {boolean} - */ - get isValid() { - return phoneUtil.isValidNumber(this.number) && phoneUtil.isPossibleNumber(this.number); - } - - /** - * Returns the country code for the parsed number. - * @return {string} - */ - get countryCode() { - return phoneUtil.getRegionCodeForNumber(this.number); - } - - /** - * Returns the e164 format for the parsed number. - * @return {string} - */ - get e164Format() { - return phoneUtil.format(this.number, PhoneNumberFormat.E164); - } - - /** - * Returns the national format for the parsed number. - * @return {string} - */ - get nationalFormat() { - return phoneUtil.format(this.number, PhoneNumberFormat.NATIONAL); - } - - /** - * Returns the international format for the parsed number. - * @return {string} - */ - get internationalFormat() { - return phoneUtil.format(this.number, PhoneNumberFormat.INTERNATIONAL); - } - - /** - * Determines the proper error message based on the error code. - * @return {string} - */ - get errorMsg() { - let message = 'Phone number is not valid.'; - - let errorCode = this.errorCode; - let reason = PhoneNumberErrorReasons[errorCode]; - - message += ' ' + reason; - - return message; - } - - /** - * Determines the error code for a number that was not able to be parsed. - * @return {number} - */ - get errorCode() { - return phoneUtil.isPossibleNumberWithReason(this.number); - } -} - -export { IntlPhoneNumber }; diff --git a/src-es6/mongoose-intl-phone-number.js b/src-es6/mongoose-intl-phone-number.js deleted file mode 100644 index 5aa7c39..0000000 --- a/src-es6/mongoose-intl-phone-number.js +++ /dev/null @@ -1,102 +0,0 @@ -import { IntlPhoneNumber } from './intl-phone-number'; - -/** - * @module mongooseIntlPhoneNumber - * @desc Validates a phone number against google's libphonenumber, otherwise returns a validation error. - * @example - ```js -var mongooseIntlPhoneNumber = require('mongoose-intl-phone-number'); -var schema = Schema({...}); - -schema.plugin(mongooseIntlPhoneNumber, { - hook: 'validate', - phoneNumberField: 'phoneNumber', - nationalFormatField: 'nationalFormat', - internationalFormat: 'internationalFormat', - countryCodeField: 'countryCode', -}); -``` -Use it with a model... -```js -var Customer = mongoose.model('Customer'); - -var customer = new Customer({ - firstName: 'test', - lastName: 'customer', - customerType: 'testing', - phoneNumber: '+18888675309', - email: 'test@testing.com' -}); - -customer.save(); -``` - -Resulting document... -```js -{ - "firstName": "test", - "lastName": "customer", - "customerType": "testing", - "phoneNumber": "+18888675309", - "nationalFormat": "(888) 867-5309", - "internationalFormat": "+1 888-867-5309" - "countryCode": "US" -} - ``` - */ -/** - * Attaches the mongoose document hook and parses the phone number that is provided. - * @param {object} schema - Mongoose schema - * @param {object} [options] - * @param {string} [options.hook=validate] - * @param {string} [options.phoneNumberField=phoneNumber] - * @param {string} [options.nationalFormatField=nationalFormat] - * @param {string} [options.internationalFormatField=internationalFormat] - * @param {string} [options.countryCodeField=countryCode] - */ -function mongooseIntlPhoneNumber(schema, { - hook = 'validate', - phoneNumberField = 'phoneNumber', - nationalFormatField = 'nationalFormat', - internationalFormatField = 'internationalFormat', - countryCodeField = 'countryCode' -} = {}) { - - // If paths don't exist in schema add them - [phoneNumberField, nationalFormatField, internationalFormatField, countryCodeField].forEach(function (path) { - if (!schema.path(path)) { - schema.add({ - [path]: { type: String } - }); - } - }); - - schema.pre(hook, function parsePhoneNumber(next) { - // Only return validation errors if the document is new or phone number has been modified. - if (this.isNew || this.isDirectModified(phoneNumberField)) { - try { - let phoneNumber = this.get(phoneNumberField); - let intlPhoneNumber = new IntlPhoneNumber(phoneNumber); - - if (intlPhoneNumber.isValid) { - this.set(phoneNumberField, intlPhoneNumber.e164Format); - this.set(nationalFormatField, intlPhoneNumber.nationalFormat); - this.set(internationalFormatField, intlPhoneNumber.internationalFormat); - this.set(countryCodeField, intlPhoneNumber.countryCode); - next(); - - } else { - next(new Error(intlPhoneNumber.errorMsg)); - } - - } catch (e) { - next(e); - } - } else { - next(); - } - }); - -} - -export { mongooseIntlPhoneNumber };