commit ae5ef441741ad114eefb0beb0a235d1925ca5cba Author: Martin Donnelly Date: Fri Mar 11 09:49:35 2016 +0000 Initial upload diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e86f5fa --- /dev/null +++ b/.editorconfig @@ -0,0 +1,32 @@ +; http://editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[*.txt] +insert_final_newline = false +trim_trailing_whitespace = false + +[*.py] +indent_size = 4 + +[*.m] +indent_size = 4 + +[Makefile] +indent_style = tab +indent_size = 8 + +[*.{js,json}] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..90e76ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,177 @@ +# Created by .ignore support plugin (hsz.mobi) +### Archives template +# It's better to unpack these files and commit the raw source because +# git has its own built in compression methods. +*.7z +*.jar +*.rar +*.zip +*.gz +*.bzip +*.bz2 +*.xz +*.lzma +*.cab + +#packing-only formats +*.iso +*.tar + +#package management formats +*.dmg +*.xpi +*.gem +*.egg +*.deb +*.rpm +*.msi +*.msm +*.msp +### Windows template +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk +### OSX template +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +### Node template +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git +node_modules +### VisualStudioCode template +.settings + +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata + +## Other +*.xccheckout +*.moved-aside +*.xcuserstate + diff --git a/md-validator.js b/md-validator.js new file mode 100644 index 0000000..12f749b --- /dev/null +++ b/md-validator.js @@ -0,0 +1,268 @@ +"use strict"; +/** + * + * User: Martin Donnelly + * Date: 2016-03-09 + * Time: 14:26 + * + */ +var VALIDATE = new function() { + + this.dateBuilder = function(d, m, y) { + return new Date(Date.UTC(y, m, d, 0, 0, 0)); + }; + + /** + * Check to see if a date is actually a valid date (e.g. FF browser converts 31 Feb to an invalid date) + * @param {number} d + * @param {number} m + * @param {number} y + * @returns {boolean} + */ + this.isDateValid = function(d, m, y) { + var enteredDate = new Date(y, m, d); + /* + if (enteredDate.getFullYear() == y && enteredDate.getMonth() == m && enteredDate.getDate() == d) { + return true; + } + */ + + return !!(enteredDate.getFullYear() === y && enteredDate.getMonth() === m && enteredDate.getDate() === d); + + }; + + /** + * Validates emails + * @return {boolean} + */ + this.Email = function(email) { + var flag, b; + /* + if (/^\w+([\+\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)) { + + flag = true; + } + else + flag = false; + + */ + flag = !!/^\w+([\+\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email); + + b = email.split("@"); + if (b.length > 2) flag = false; + if (b[0].length == 0) flag = false; + if (email.charAt(0) == '.' || email.charAt(email.length - 1) == '.') flag = false; + return flag; + }; + + /** + * + * @param inval + * @returns {boolean} + */ + + this.time = function(inval) { + + var rtrn = false, exp = /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/; + + if (exp.test(inval)) { + rtrn = true; + } + + return rtrn; + }; + + /** + * + * @param inval + * @returns {boolean} + */ + this.money = function(inval) { + "use strict"; + var rtrn = '', exp = /^\xA3?\d{1,3}?([,]\d{3}|\d)*?([.]\d{1,2})?$/; + + if (exp.test(inval)) { + rtrn = exp.exec(inval); + } + + return rtrn[0]; + + }; + + /** + * Validates UK postcodes + */ + + this.checkPostCode = function(toCheck) { + + // Permitted letters depend upon their position in the postcode. + var valid, postCode; + var alpha1 = '[abcdefghijklmnoprstuwyz]'; // Character 1 + var alpha2 = '[abcdefghklmnopqrstuvwxy]'; // Character 2 + var alpha3 = '[abcdefghjkpmnrstuvwxy]'; // Character 3 + var alpha4 = '[abehmnprvwxy]'; // Character 4 + var alpha5 = '[abdefghjlnpqrstuwxyz]'; // Character 5 + var BFPOa5 = '[abdefghjlnpqrst]'; // BFPO alpha5 + var BFPOa6 = '[abdefghjlnpqrstuwzyz]'; // BFPO alpha6 + + var invalidW1 = /^(W1)([eilmnopqrvwxyz]{1})(\s*)([0-9]{1}[abdefghjlnpqrstuwxyz]{2})$/i; + + // Array holds the regular expressions for the valid postcodes + var pcexp = []; + + // BFPO postcodes + pcexp.push(new RegExp('^(bf1)(\\s*)([0-6]{1}' + BFPOa5 + '{1}' + BFPOa6 + '{1})$', 'i')); + + // Expression for postcodes: AN NAA, ANN NAA, AAN NAA, and AANN NAA + pcexp.push(new RegExp('^(' + alpha1 + '{1}' + alpha2 + '?[0-9]{1,2})(\\s*)([0-9]{1}' + alpha5 + '{2})$', 'i')); + + // Expression for postcodes: ANA NAA + pcexp.push(new RegExp('^(' + alpha1 + '{1}[0-9]{1}' + alpha3 + '{1})(\\s*)([0-9]{1}' + alpha5 + '{2})$', 'i')); + + // Expression for postcodes: AANA NAA + pcexp.push(new RegExp('^(' + alpha1 + '{1}' + alpha2 + '{1}' + '?[0-9]{1}' + alpha4 + '{1})(\\s*)([0-9]{1}' + alpha5 + '{2})$', 'i')); + + // Exception for the special postcode GIR 0AA + pcexp.push(/^(GIR)(\s*)(0AA)$/i); + + // Standard BFPO numbers + pcexp.push(/^(bfpo)(\s*)([0-9]{1,4})$/i); + + // c/o BFPO numbers + pcexp.push(/^(bfpo)(\s*)(c\/o\s*[0-9]{1,3})$/i); + + // Overseas Territories + pcexp.push(/^([A-Z]{4})(\s*)(1ZZ)$/i); + + // Anguilla + pcexp.push(/^(ai-2640)$/i); + + // Load up the string to check + postCode = toCheck; + + // Assume we're not going to find a valid postcode + valid = false; + + // Check the string against the types of post codes + for (var i = 0; i < pcexp.length; i++) { + + if (pcexp[i].test(postCode)) { + + // The post code is valid - split the post code into component parts + pcexp[i].exec(postCode); + + // Copy it back into the original string, converting it to uppercase + // and inserting a space between the inward and outward codes + postCode = RegExp.$1.toUpperCase() + ' ' + RegExp.$3.toUpperCase(); + + // If it is a BFPO c/o type postcode, tidy up the "c/o" part + postCode = postCode.replace(/C\/O\s*/, 'c/o '); + + // If it is the Anguilla overseas territory postcode, we need to + // treat it specially + if (toCheck.toUpperCase() == 'AI-2640') {postCode = 'AI-2640'} + // Load new postcode back into the form element + valid = true; + + // Remember that we have found that the code is valid and break + // from loop + break; + } + } + + if (invalidW1.test(postCode)) { + valid = false; + } + + // Return with either the reformatted valid postcode or the original + // invalid postcode + //if (valid) {return postCode;} else return false; + if (valid) {return postCode;} + else return ''; + }; + + /** + * Validates UK Telephone numbers + * @param {string} telephoneNumber + * @returns {*} + */ + this.checkUKTelephone = function(telephoneNumber) { + + // Convert into a string and check that we were provided with something + var telNumberErrorNo, telnum = telephoneNumber + ' '; + if (telnum.length == 1) { + // telNumberErrorNo = 1; + return false; + } + telnum = (telnum).trim(); + + // Don't allow country codes to be included (assumes a leading "+") + var exp = /^(\+)[\s]*(.*)$/; + if (exp.test(telnum) == true) { + //telNumberErrorNo = 2; + return false; + } + + // Remove spaces from the telephone number to help validation + while (telnum.indexOf(' ') != -1) { + telnum = telnum.slice(0, + telnum.indexOf(' ')) + telnum.slice(telnum.indexOf(' ') + 1); + } + + // Remove hyphens from the telephone number to help validation + while (telnum.indexOf('-') != -1) { + telnum = telnum.slice(0, + telnum.indexOf('-')) + telnum.slice(telnum.indexOf('-') + 1); + } + + // Now check that all the characters are digits + + exp = /^[0-9]{10,11}$/; + if (exp.test(telnum) != true) { + // telNumberErrorNo = 3; + return false; + } + + // Now check that the first digit is 0 + exp = /^0[0-9]{9,10}$/; + if (exp.test(telnum) != true) { + // telNumberErrorNo = 4; + return false; + } + + // Disallow numbers allocated for dramas. + + // Array holds the regular expressions for the drama telephone numbers + var tnexp = []; + tnexp.push( + /^(0113|0114|0115|0116|0117|0118|0121|0131|0141|0151|0161)(4960)[0-9]{3}$/); + tnexp.push(/^02079460[0-9]{3}$/); + tnexp.push(/^01914980[0-9]{3}$/); + tnexp.push(/^02890180[0-9]{3}$/); + tnexp.push(/^02920180[0-9]{3}$/); + tnexp.push(/^01632960[0-9]{3}$/); + tnexp.push(/^07700900[0-9]{3}$/); + tnexp.push(/^08081570[0-9]{3}$/); + tnexp.push(/^09098790[0-9]{3}$/); + tnexp.push(/^03069990[0-9]{3}$/); + + for (var i = 0; i < tnexp.length; i++) { + if (tnexp[i].test(telnum)) { + telNumberErrorNo = 5; + return false; + } + } + + // Finally check that the telephone number is appropriate. + exp = (/^(01|02|03|05|070|071|072|073|074|075|07624|077|078|079)[0-9]+$/); + if (exp.test(telnum) != true) { + // telNumberErrorNo = 5; + return false; + } + + // Telephone number seems to be valid - return the stripped telehone number + return telnum; + }; +}; + +module.exports = VALIDATE; diff --git a/package.json b/package.json new file mode 100644 index 0000000..901df3f --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "node-validator", + "version": "0.0.1", + "description": "A collection of validators.", + "main": "md-validator.js", + "scripts": { + "test": "mocha --recursive --reporter spec --bail --check-leaks --timeout 3000" + }, + "repository": { + "type": "git", + "url": "git+http://gitlab.silvrtree.co.uk/martind2000/node-validator.git" + }, + "keywords": [ + "validator" + ], + "engines": { + "node": "*" + }, + "author": "Martin Donnelly ", + "license": "ISC", + "private": true, + "devDependencies": { + "mocha": "^2.4.5" + } +} diff --git a/test/md-validator.js b/test/md-validator.js new file mode 100644 index 0000000..17a0d96 --- /dev/null +++ b/test/md-validator.js @@ -0,0 +1,334 @@ +/** + * + * User: Martin Donnelly + * Date: 2016-03-09 + * Time: 14:37 + * + */ +"use strict"; +var mdValidate = require('../md-validator'); + +var assert = require('assert'); + +var phone = [ + 'A', + 'AA', + 'AAA', + 'AAAA', + 'AAAAA', + 'AAAAAA', + '0', + '01', + '012', + '0123', + '01234', + '012345', + '0123456', + '01234567', + '012345678', + '01134960000', + '01134960500', + '01134960999', + '01144960000', + '01144960500', + '01144960999', + '01154960000', + '01154960500', + '01154960999', + '01164960000', + '01164960500', + '01164960999', + '01174960000', + '01174960500', + '01174960999', + '01184960000', + '01184960500', + '01184960999', + '01214960000', + '01214960500', + '01214960999', + '01314960000', + '01314960500', + '01314960999', + '01414960000', + '01414960500', + '01414960999', + '01514960000', + '01514960500', + '01514960999', + '01614960000', + '01614960500', + '01614960999', + '02079460000', + '02079460500', + '02079460999', + '01914980000', + '01914980500', + '01914980999', + '02890180000', + '02890180500', + '02890180999', + '02920180000', + '02920180500', + '02920180999', + '01632960000', + '01632960500', + '01632960999', + '07700900000', + '07700900500', + '07700900999', + '08081570000', + '08081570555', + '08081570999', + '09098790000', + '09098790500', + '09098790999', + '03069990000', + '03069990500', + '03069990999', + '08002323636', + '09002323636', + '06002323636', + "00254745856", + "+254745856" +]; + +var validPhone = ['01389703002', '07944577934', '01412807000', '02071539996']; + +var postcodes = [ + 'A', + 'AA', + 'AAA', + 'AAAA', + 'AAAAA', + 'AAAAAA', + 'Q1 1AA', + 'V1 1AA', + 'X1 1AA', + 'M1 CAA', + 'M1 IAA', + 'M1 KAA', + 'M1 MAA', + 'M1 OAA', + 'M1 VAA', + + 'Q60 1NW', + 'V60 1NW', + 'X60 1NW', + 'M60 1CW', + 'M60 1IW', + 'M60 1KW', + 'M60 1MW', + 'M60 1OW', + 'M60 1VW', + 'M60 1NC', + 'M60 1NI', + 'M60 1NK', + 'M60 1NM', + 'M60 1NO', + 'M60 1NV', + + 'QR2 6XH', + 'VR2 6XH', + 'XR2 6XH', + 'CI2 6XH', + 'CJ2 6XH', + 'CZ2 6XH', + 'CR2 6CH', + 'CR2 6IH', + 'CR2 6KH', + 'CR2 6MH', + 'CR2 6OH', + 'CR2 6VH', + 'CR2 6XC', + 'CR2 6XI', + 'CR2 6XK', + 'CR2 6XM', + 'CR2 6XO', + 'CR2 6XV', + + 'QN55 1PT', + 'VN55 1PT', + 'XN55 1PT', + 'DI55 1PT', + 'DJ55 1PT', + 'DZ55 1PT', + 'DN55 1CT', + 'DN55 1IT', + 'DN55 1KT', + 'DN55 1MT', + 'DN55 1OT', + 'DN55 1VT', + 'DN55 1PC', + 'DN55 1PI', + 'DN55 1PK', + 'DN55 1PM', + 'DN55 1PO', + 'DN55 1PV', + + 'Q1A 1HQ', + 'V1A 1HQ', + 'X1A 1HQ', + 'W1I 1HQ', + 'W1L 1HQ', + 'W1M 1HQ', + 'W1N 1HQ', + 'W1O 1HQ', + 'W1P 1HQ', + 'W1Q 1HQ', + 'W1R 1HQ', + 'W1V 1HQ', + 'W1X 1HQ', + 'W1Y 1HQ', + 'W1Z 1HQ', + 'W1A 1CQ', + 'W1A 1IQ', + 'W1A 1KQ', + 'W1A 1MQ', + 'W1A 1OQ', + 'W1A 1VQ', + 'W1A 1HC', + 'W1A 1HI', + 'W1A 1HK', + 'W1A 1HM', + 'W1A 1HO', + 'W1A 1HV', + + 'QC1A 1BB', + 'VC1A 1BB', + 'XC1A 1BB', + 'EI1A 1BB', + 'EJ1A 1BB', + 'EZ1A 1BB', + 'EC1C 1BB', + 'EC1D 1BB', + 'EC1F 1BB', + 'EC1G 1BB', + 'EC1I 1BB', + 'EC1J 1BB', + 'EC1K 1BB', + 'EC1L 1BB', + 'EC1O 1BB', + 'EC1Q 1BB', + 'EC1S 1BB', + 'EC1T 1BB', + 'EC1U 1BB', + 'EC1Z 1BB', + 'EC1A 1IB', + 'EC1A 1MB', + 'EC1A 1OB', + 'EC1A 1VB', + 'EC1A 1BC', + 'EC1A 1BI', + 'EC1A 1BK', + 'EC1A 1BM', + 'EC1A 1BO', + 'EC1A 1BV' + +]; + +var validPostcodes = [ + 'M1 1AA', + 'M60 1NW', + 'CR2 6XH', + 'DN55 1PT', + 'W1A 1HQ', + 'EC1A 1BB', + 'BT9 7JL', + 'GIR 0AA' + +]; + +// taken from http://blogs.msdn.com/b/testing123/archive/2009/02/05/email-address-test-cases.aspx +// having difficulty invalidating /*'あいうえお@domain.com',*/ +// Several test cases for the email address have been removed as they should really be fixed by the mail system +// and they would be costly to fix in code at the moment + +var invalidEmail = [ + 'plainaddress', + '#@%^%#$@#$@#.com', + '@domain.com', + 'Joe Smith ', + 'email.domain.com', + 'email@domain@domain.com', + '.email@domain.com', + 'email.@domain.com', + 'email..email@domain.com', + 'email@domain.com (Joe Smith)', + 'email@domain', + 'email@-domain.com', + /*'email@domain.web',*/ + 'email@111.222.333.44444', + 'email@domain..com' +]; + +var validEmail = [ + 'email@domain.com', + 'firstname.lastname@domain.com', + 'email@subdomain.domain.com', + 'firstname+lastname@domain.com', + 'email@123.123.123.123', + /*'email@[123.123.123.123]',*/ + /*'"email"@domain.com',*/ + '1234567890@domain.com', + 'email@domain-one.com', + '_______@domain.com', + /*'email@domain.name',*/ + 'email@domain.co.uk', + 'firstname-lastname@domain.com' +]; + +var emailOne = ['m@g.com', 'm@g.co.uk', 'bob@g.com']; +var emailTwo = ['m@g.co.uk', 'bob@g.com', 'm@g.com']; + +describe('MD-Validator', function() { + it('should not validate an incorrect email address', function(done) { + + for (var i in invalidEmail) { + assert.ifError(mdValidate.Email(invalidEmail[i])); + } + done(); + }); + + it('should validate a correct email address', function(done) { + + for (var i in validEmail) { + assert(mdValidate.Email(validEmail[i])); + } + done(); + }); + + it('should not validate an incorrect phone number', function(done) { + + for (var i in phone) { + assert.ifError(mdValidate.checkUKTelephone(phone[i])); + + } + done(); + }); + + it('should validate a correct phone number', function(done) { + + for (var i in validPhone) { + assert(mdValidate.checkUKTelephone(validPhone[i])); + } + done(); + }); + + it('should not validate an incorrect postcode', function(done) { + + for (var i in postcodes) { + assert.ifError(mdValidate.checkPostCode(postcodes[i])); + } + done(); + }); + + it('should validate a correct postcode', function(done) { + + for (var i in validPostcodes) { + assert(mdValidate.checkPostCode(validPostcodes[i])); + } + done(); + }); + +});