Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 33 additions & 10 deletions addon/format.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isEmpty, isNone } from '@ember/utils';
import { assert } from '@ember/debug';
import { getProperties, set } from '@ember/object';
import { getProperties, get, set } from '@ember/object';

import Ember from 'ember';
import validationError from 'ember-validators/utils/validation-error';
Expand Down Expand Up @@ -33,7 +33,7 @@ export const regularExpressions = {
// eslint-disable-next-line no-useless-escape
phone: /^([\+]?1\s*[-\/\.]?\s*)?(\((\d{3})\)|(\d{3}))\s*[-\/\.]?\s*(\d{3})\s*[-\/\.]?\s*(\d{4})\s*(([xX]|[eE][xX][tT]?[\.]?|extension)\s*([#*\d]+))*$/,
// eslint-disable-next-line no-useless-escape
url: /(?:([A-Za-z]+):)?(\/{0,3})[a-zA-Z0-9][a-zA-Z-0-9]*(\.[\w-]+)+([\w.,@?^=%&:\/~+#-{}]*[\w@?^=%&\/~+#-{}])??/
url: /^(?:([A-Za-z]+):)?(\/{0,3})[a-zA-Z0-9][a-zA-Z-0-9]*(\.[\w-]+)+([\w.,@?^=%&:\/~+#-{}]*[\w@?^=%&\/~+#-{}])??$/
};

export default function validateFormat(value, options, model, attribute) {
Expand All @@ -49,11 +49,8 @@ export default function validateFormat(value, options, model, attribute) {
regex = regularExpressions[type];
}

if (type === 'email') {
if (regex === regularExpressions.email) {
regex = formatEmailRegex(options);
}

if (type === 'email' || type === 'url') {
regex = formatEmailRegex(options);
set(options, 'regex', regex);
}

Expand All @@ -64,10 +61,36 @@ export default function validateFormat(value, options, model, attribute) {
return true;
}

function formatUrlRegex(options) {
const allowNonTld = get(options, 'allowNonTld');
const cacheKey = `url:${allowNonTld}`;
const cachedRegex = regularExpressions[cacheKey];

if (cachedRegex) {
return cachedRegex;
}

let { source } = regularExpressions.url;

if (allowNonTld) {
source = source.replace('(\\.[\\w-]+)+', '(\\.[\\w-]+)*');
}

return regularExpressions[cacheKey] = new RegExp(source, 'i');
}

function formatEmailRegex(options) {
let { source } = regularExpressions.email;
let { allowNonTld, minTldLength } = getProperties(options, ['allowNonTld', 'minTldLength']);
const { allowNonTld, minTldLength } = getProperties(options, ['allowNonTld', 'minTldLength']);
const cacheKey = `email:${allowNonTld}:${minTldLength}`;
const cachedRegex = regularExpressions[cacheKey];

if (cachedRegex) {
return cachedRegex;
}

let { source } = regularExpressions.email;


if (!isNone(minTldLength) && typeof minTldLength === 'number') {
source = source.replace('[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$', `[a-z0-9]{${minTldLength},}(?:[a-z0-9-]*[a-z0-9])?$`);
}
Expand All @@ -76,5 +99,5 @@ function formatEmailRegex(options) {
source = source.replace('@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)', '@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.?)');
}

return new RegExp(source, 'i');
return regularExpressions[cacheKey] = new RegExp(source, 'i');
}
47 changes: 33 additions & 14 deletions tests/unit/validators/format-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@ import cloneOptions from '../../helpers/clone-options';

let options, result;

function testEmailAddresses(assert, options, valid = [], invalid = []) {
function testMultipleScenarios(assert, options, valid = [], invalid = []) {
const typeLabelMap = {
email: 'email address',
url: 'url'
}
const label = typeLabelMap[options.type];
options = cloneOptions(options);
valid.forEach((email) => assert.equal(processResult(validate(email, options)), true, `validation of ${email} must succeed`));
invalid.forEach((email) => assert.equal(processResult(validate(email, options)), 'This field must be a valid email address', `validation of ${email} must fail`));
valid.forEach((testItem) => assert.equal(processResult(validate(testItem, options)), true, `validation of ${testItem} must succeed`));
invalid.forEach((testItem) => assert.equal(processResult(validate(testItem, options)), `This field must be a valid ${label}`, `validation of ${testItem} must fail`));
}

module('Unit | Validator | format');
Expand Down Expand Up @@ -87,7 +92,7 @@ test('email', function(assert) {
type: 'email'
};

testEmailAddresses(assert, options, validAddresses, invalidAddresses);
testMultipleScenarios(assert, options, validAddresses, invalidAddresses);
});

test('email + allowNonTld', function(assert) {
Expand All @@ -103,7 +108,7 @@ test('email + allowNonTld', function(assert) {
allowNonTld: true
};

testEmailAddresses(assert, options, validAddresses);
testMultipleScenarios(assert, options, validAddresses);
});

test('email + minTldLength', function(assert) {
Expand All @@ -126,7 +131,27 @@ test('email + minTldLength', function(assert) {
minTldLength: 2
};

testEmailAddresses(assert, options, validAddresses, invalidAddresses);
testMultipleScenarios(assert, options, validAddresses, invalidAddresses);
});

test('url + allowNonTld', function(assert) {
let validUrls = [
'http://google.com',
'http://bburl',
'http://bburl/jello',
'http://bburl.com/really-good-jello'
];

let invalidUrls = ['i am a bad url']

assert.expect(validUrls.length + invalidUrls.length);

options = {
type: 'url',
allowNonTld: true
};

testMultipleScenarios(assert, options, validUrls, invalidUrls);
});

test('phone', function(assert) {
Expand All @@ -146,19 +171,13 @@ test('phone', function(assert) {
});

test('url', function(assert) {
assert.expect(2);
assert.expect(3);

options = {
type: 'url'
};

options = cloneOptions(options);

result = validate('offirgolan', options);
assert.equal(processResult(result), 'This field must be a valid url');

result = validate('http://www.offirgolan.com', options);
assert.equal(processResult(result), true);
testMultipleScenarios(assert, options, ['http://www.offirgolan.com'], ['offirgolan', 'http://bburl']);
});

test('inverse - with type', function(assert) {
Expand Down