diff --git a/packages/n4s/.npmignore b/packages/n4s/.npmignore index 0381aeb04..6aa0dfccc 100644 --- a/packages/n4s/.npmignore +++ b/packages/n4s/.npmignore @@ -5,6 +5,7 @@ src !dist/ tsconfig.json !schema/ +!isURL/ !email/ !date/ !compounds/ diff --git a/packages/n4s/package.json b/packages/n4s/package.json index ce1d0abff..e9a9f9999 100644 --- a/packages/n4s/package.json +++ b/packages/n4s/package.json @@ -59,6 +59,36 @@ "module": "./dist/es/schema.production.js", "default": "./dist/cjs/schema.production.js" }, + "./isURL": { + "production": { + "types": "./types/isURL.d.ts", + "browser": "./dist/es/isURL.production.js", + "umd": "./dist/umd/isURL.production.js", + "import": "./dist/es/isURL.production.js", + "require": "./dist/cjs/isURL.production.js", + "node": "./dist/cjs/isURL.production.js", + "module": "./dist/es/isURL.production.js", + "default": "./dist/cjs/isURL.production.js" + }, + "development": { + "types": "./types/isURL.d.ts", + "browser": "./dist/es/isURL.development.js", + "umd": "./dist/umd/isURL.development.js", + "import": "./dist/es/isURL.development.js", + "require": "./dist/cjs/isURL.development.js", + "node": "./dist/cjs/isURL.development.js", + "module": "./dist/es/isURL.development.js", + "default": "./dist/cjs/isURL.development.js" + }, + "types": "./types/isURL.d.ts", + "browser": "./dist/es/isURL.production.js", + "umd": "./dist/umd/isURL.production.js", + "import": "./dist/es/isURL.production.js", + "require": "./dist/cjs/isURL.production.js", + "node": "./dist/cjs/isURL.production.js", + "module": "./dist/es/isURL.production.js", + "default": "./dist/cjs/isURL.production.js" + }, "./email": { "production": { "types": "./types/email.d.ts", diff --git a/packages/n4s/src/exports/__tests__/isUrl.test.ts b/packages/n4s/src/exports/__tests__/isUrl.test.ts new file mode 100644 index 000000000..639f0af44 --- /dev/null +++ b/packages/n4s/src/exports/__tests__/isUrl.test.ts @@ -0,0 +1,51 @@ +import { enforce } from 'n4s'; +import 'isURL'; + +describe('isURL', () => { + it('Should pass for valid URLs', () => { + expect(() => enforce('http://www.google.com').isURL()).not.toThrow(); + expect(() => enforce('https://google.com').isURL()).not.toThrow(); + expect(() => enforce('google.com').isURL()).not.toThrow(); + expect(() => enforce('https://www.wikipedia.org/wiki/Main_Page').isURL()).not.toThrow(); + expect(() => enforce('ftp://myserver.net').isURL()).not.toThrow(); + expect(() => enforce('https://www.example.com/query?search=AI').isURL()).not.toThrow(); + expect(() => enforce('https://username:password@hostname.com:8080').isURL()).not.toThrow(); + expect(() => enforce('http://233.233.233.233').isURL()).not.toThrow(); + expect(() => enforce('https://www.example.com/foo/?bar=baz&inga=42&quux').isURL()).not.toThrow(); + expect(() => enforce('http://www.example.com/index.html#section1').isURL()).not.toThrow(); + }); + + it('Should fail for invalid URLs', () => { + expect(() => enforce('').isURL()).toThrow(); + expect(() => enforce('google').isURL()).toThrow(); + expect(() => enforce('http://').isURL()).toThrow(); + expect(() => enforce('https://').isURL()).toThrow(); + expect(() => enforce('www.google.').isURL()).toThrow(); + expect(() => enforce('http://google').isURL()).toThrow(); + expect(() => enforce('https://google').isURL()).toThrow(); + expect(() => enforce('http:///www.google.com').isURL()).toThrow(); + expect(() => enforce('https:///www.google.com').isURL()).toThrow(); + expect(() => enforce('http://www.goo gle.com').isURL()).toThrow(); + expect(() => enforce('://www.google.com').isURL()).toThrow(); + expect(() => enforce('http://localhost').isURL()).toThrow(); + expect(() => enforce('www.com').isURL({ require_host: false })).not.toThrow(); + }) + + describe('With options', () => { + it('should pass for valid URLs', () => { + expect(() => enforce('myprotocol://customdomain.com').isURL({ protocols: ['myprotocol'] })).not.toThrow(); + expect(() => enforce('http://localhost:8080').isURL({ require_tld: false })).not.toThrow(); + expect(() => enforce('invalid://www.google.com').isURL({ require_valid_protocol: false })).not.toThrow(); + expect(() => enforce('http://my_server.com').isURL({ allow_underscores: true })).not.toThrow(); + }); + + it('should fail for invalid URLs', () => { + expect(() => enforce('myprotocol://customdomain.com').isURL({ protocols: ['http'] })).toThrow(); + expect(() => enforce('http://localhost:8080').isURL({ require_tld: true })).toThrow(); + expect(() => enforce('invalid://www.google.com').isURL({ require_valid_protocol: true })).toThrow(); + expect(() => enforce('http://my_server.com').isURL({ allow_underscores: false })).toThrow(); + expect(() => enforce('http://www.example.com/index.html#section1').isURL({ allow_fragments: false })).toThrow(); + }); + }); + +}); \ No newline at end of file diff --git a/packages/n4s/src/exports/isUrl.ts b/packages/n4s/src/exports/isUrl.ts new file mode 100644 index 000000000..3d76b4bd7 --- /dev/null +++ b/packages/n4s/src/exports/isUrl.ts @@ -0,0 +1,15 @@ +import { enforce } from 'n4s'; +import isURL from 'validator/es/lib/isURL'; + +import { EnforceCustomMatcher } from 'enforceUtilityTypes'; + +enforce.extend({ isURL }); + +/* eslint-disable @typescript-eslint/no-namespace */ +declare global { + namespace n4s { + interface EnforceCustomMatchers { + isURL: EnforceCustomMatcher; + } + } +} diff --git a/packages/n4s/tsconfig.json b/packages/n4s/tsconfig.json index f73985d76..06f650e9d 100644 --- a/packages/n4s/tsconfig.json +++ b/packages/n4s/tsconfig.json @@ -53,6 +53,7 @@ "ruleReturn": ["./src/lib/ruleReturn.ts"], "enforceUtilityTypes": ["./src/lib/enforceUtilityTypes.ts"], "schema": ["./src/exports/schema.ts"], + "isURL": ["./src/exports/isURL.ts"], "email": ["./src/exports/email.ts"], "date": ["./src/exports/date.ts"], "compounds": ["./src/exports/compounds.ts"], diff --git a/website/docs/enforce/builtin-enforce-plugins/isUrl.md b/website/docs/enforce/builtin-enforce-plugins/isUrl.md new file mode 100644 index 000000000..d74bb1472 --- /dev/null +++ b/website/docs/enforce/builtin-enforce-plugins/isUrl.md @@ -0,0 +1,60 @@ +--- +sidebar_position: 4 +title: isURL enforce Rule +description: isURL enforce rule for validating url addresses. +keywords: [Vest, enforce, plugin, isURL, n4s, url] +--- + +# isURL Enforce Rule + +## Description + +The isURL enforce rule provides functionality to validate URL values. This documentation covers the `isUrl` rule, along with its options and configurations. + +These rule exposes the [`validator.js`](https://www.npmjs.com/package/validator) isURL rule, and accepts the same options. + +## isURL Rule + +The `isURL` rule checks whether a given value is a valid URL. It accepts various options to customize the validation behavior. + +```javascript +enforce(value).isURL(options); +``` + +### Options + +The isURL rule accepts an optional options object to customize the validation behavior. The available options are as follows: + +The `isUrl` rule accepts an optional `options` object to customize the validation behavior. The available options are as follows: + +| Option | Default Value | Description | +| ----------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------- | +| `require_protocol` | `false` | Requires the URL to include a protocol (e.g., `http://` or `https://`). | +| `require_host` | `true` | Requires the URL to include a host (e.g., `www.example.com`). | +| `require_valid_protocol` | `true` | Requires the URL's protocol to be in the list of valid protocols (`http`, `https`, `ftp`). | +| `allow_underscores` | `false` | Allows underscores in the host name. | +| `allow_trailing_dot` | `false` | Allows a trailing dot in the host name. | +| `allow_protocol_relative_urls`| `false` | Allows protocol-relative URLs (e.g., `//www.example.com`). | +| `allow_fragments` | `true` | Allows URL fragments (e.g., `#section`). | +| `allow_query_components` | `true` | Allows query components in the URL (e.g., `?query=value`). | +| `validate_length` | `true` | Validates that the URL length does not exceed the maximum allowed length (2083 characters). | + +### Usage Example + +```javascript +// Usage with options +enforce(url).isURL({ + protocols: ['http', 'https', 'ftp'], + require_tld: true, + require_protocol: false, + require_host: true, + require_port: false, + require_valid_protocol: true, + allow_underscores: false, + allow_trailing_dot: false, + allow_protocol_relative_urls: false, + allow_fragments: true, + allow_query_components: true, + validate_length: true +}); +```