Skip to content

Commit 9af6f1f

Browse files
authored
feat: Support encoding uri (#3027)
* feat: Add encodeUri in UriOptions interface * feat: Add encodeUri in options list for uri method * feat: Encode uri with true flags in uri validation * feat: Add test for uri encoding * fix: Integrate lint suggestions for style consistency * fix: Pre-encode value before other cases * feat: Add custom error message for uriEncoding * feat: Add case for uriEncoding convert false * docs: Add description for encodeUri
1 parent 554a437 commit 9af6f1f

File tree

4 files changed

+40
-1
lines changed

4 files changed

+40
-1
lines changed

API.md

+1
Original file line numberDiff line numberDiff line change
@@ -3085,6 +3085,7 @@ Requires the string value to be a valid [RFC 3986](http://tools.ietf.org/html/rf
30853085
- `relativeOnly` - Restrict only relative URIs. Defaults to `false`.
30863086
- `allowQuerySquareBrackets` - Allows unencoded square brackets inside the query string. This is **NOT** RFC 3986 compliant but query strings like `abc[]=123&abc[]=456` are very common these days. Defaults to `false`.
30873087
- `domain` - Validate the domain component using the options specified in [`string.domain()`](#stringdomainoptions).
3088+
- `encodeUri` - Encodes the uri with non-alphabetical characters. Defaults to `false`.
30883089

30893090
```js
30903091
// Accept git or git http/https

lib/index.d.ts

+6
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,12 @@ declare namespace Joi {
426426
* Validate the domain component using the options specified in `string.domain()`.
427427
*/
428428
domain?: DomainOptions;
429+
/**
430+
* Encode URI before validation.
431+
*
432+
* @default false
433+
*/
434+
encodeUri?: boolean;
429435
}
430436

431437
interface DataUriOptions {

lib/types/string.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ module.exports = Any.extend({
649649
uri: {
650650
method(options = {}) {
651651

652-
Common.assertOptions(options, ['allowRelative', 'allowQuerySquareBrackets', 'domain', 'relativeOnly', 'scheme']);
652+
Common.assertOptions(options, ['allowRelative', 'allowQuerySquareBrackets', 'domain', 'relativeOnly', 'scheme', 'encodeUri']);
653653

654654
if (options.domain) {
655655
Common.assertOptions(options.domain, ['allowFullyQualified', 'allowUnicode', 'maxDomainSegments', 'minDomainSegments', 'tlds']);
@@ -665,6 +665,10 @@ module.exports = Any.extend({
665665
return helpers.error('string.uri');
666666
}
667667

668+
if (helpers.prefs.convert && options.encodeUri) {
669+
value = encodeURI(value);
670+
}
671+
668672
const match = regex.exec(value);
669673
if (match) {
670674
const matched = match[1] || match[2];
@@ -686,6 +690,10 @@ module.exports = Any.extend({
686690
return helpers.error('string.uriCustomScheme', { scheme, value });
687691
}
688692

693+
if (options.encodeUri) {
694+
return helpers.error('string.uriEncoding');
695+
}
696+
689697
return helpers.error('string.uri');
690698
}
691699
}
@@ -736,6 +744,7 @@ module.exports = Any.extend({
736744
'string.uri': '{{#label}} must be a valid uri',
737745
'string.uriCustomScheme': '{{#label}} must be a valid uri with a scheme matching the {{#scheme}} pattern',
738746
'string.uriRelativeOnly': '{{#label}} must be a valid relative uri',
747+
'string.uriEncoding': '{{#label}} must contain only valid characters or "convert" must be allowed',
739748
'string.uppercase': '{{#label}} must only contain uppercase characters'
740749
}
741750
});

test/types/string.js

+23
Original file line numberDiff line numberDiff line change
@@ -9012,6 +9012,29 @@ describe('string', () => {
90129012
]);
90139013
});
90149014

9015+
it('validates uri with accented characters with encoding', () => {
9016+
9017+
const schema = Joi.string().uri({ encodeUri: true });
9018+
9019+
Helper.validate(schema, { convert: true }, [
9020+
['https://linkedin.com/in/aïssa/', true, 'https://linkedin.com/in/a%C3%AFssa/']
9021+
]);
9022+
});
9023+
9024+
it('validates uri with accented characters without encoding', () => {
9025+
9026+
const schema = Joi.string().uri({ encodeUri: true });
9027+
9028+
Helper.validate(schema, { convert: false }, [
9029+
['https://linkedin.com/in/aïssa/', false, {
9030+
message: '"value" must contain only valid characters or "convert" must be allowed',
9031+
path: [],
9032+
type: 'string.uriEncoding',
9033+
context: { value: 'https://linkedin.com/in/aïssa/', label: 'value' }
9034+
}]
9035+
]);
9036+
});
9037+
90159038
it('errors on unknown options', () => {
90169039

90179040
expect(() => Joi.string().uri({ foo: 'bar', baz: 'qux' })).to.throw('Options contain unknown keys: foo,baz');

0 commit comments

Comments
 (0)