identifier-js 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,267 @@
1
+ Accept: |
2
+ [ ( media-range [ weight ] ) *( OWS "," OWS ( media-range [ weight ] ) ) ]
3
+ Accept-Charset: >
4
+ [ ( ( token / "*" ) [ weight ] ) *( OWS "," OWS ( ( token / "*" ) [ weight ] ) ) ]
5
+ Accept-Encoding: |
6
+ [ ( codings [ weight ] ) *( OWS "," OWS ( codings [ weight ] ) ) ]
7
+ Accept-Language: >
8
+ [ ( language-range [ weight ] ) *( OWS "," OWS ( language-range [ weight ] ) ) ]
9
+ Accept-Ranges: acceptable-ranges
10
+ Allow: |
11
+ [ method *( OWS "," OWS method ) ]
12
+ Authentication-Info: |
13
+ [ auth-param *( OWS "," OWS auth-param ) ]
14
+ Authorization: credentials
15
+ BWS: OWS
16
+ Connection: |
17
+ [ connection-option *( OWS "," OWS connection-option ) ]
18
+ Content-Encoding: |
19
+ [ content-coding *( OWS "," OWS content-coding ) ]
20
+ Content-Language: |
21
+ [ language-tag *( OWS "," OWS language-tag ) ]
22
+ Content-Length: 1*DIGIT
23
+ Content-Location: absolute-URI / partial-URI
24
+ Content-Range: |
25
+ range-unit SP ( range-resp / unsatisfied-range )
26
+ Content-Type: media-type
27
+ Date: HTTP-date
28
+ ETag: entity-tag
29
+ Expect: |
30
+ [ expectation *( OWS "," OWS expectation ) ]
31
+ From: mailbox
32
+ GMT: '%x47.4D.54'
33
+ HTTP-date: IMF-fixdate / obs-date
34
+ Host: uri-host [ ":" port ]
35
+ IMF-fixdate: |
36
+ day-name "," SP date1 SP time-of-day SP GMT
37
+ If-Match: |
38
+ "*" / [ entity-tag *( OWS "," OWS entity-tag ) ]
39
+ If-Modified-Since: HTTP-date
40
+ If-None-Match: |
41
+ "*" / [ entity-tag *( OWS "," OWS entity-tag ) ]
42
+ If-Range: entity-tag / HTTP-date
43
+ If-Unmodified-Since: HTTP-date
44
+ Last-Modified: HTTP-date
45
+ Location: URI-reference
46
+ Max-Forwards: 1*DIGIT
47
+ OWS: |
48
+ *( SP / HTAB )
49
+ Proxy-Authenticate: |
50
+ [ challenge *( OWS "," OWS challenge ) ]
51
+ Proxy-Authentication-Info: |
52
+ [ auth-param *( OWS "," OWS auth-param ) ]
53
+ Proxy-Authorization: credentials
54
+ RWS: |
55
+ 1*( SP / HTAB )
56
+ Range: ranges-specifier
57
+ Referer: absolute-URI / partial-URI
58
+ Retry-After: HTTP-date / delay-seconds
59
+ Server: |
60
+ product *( RWS ( product / comment ) )
61
+ TE: |
62
+ [ t-codings *( OWS "," OWS t-codings ) ]
63
+ Trailer: |
64
+ [ field-name *( OWS "," OWS field-name ) ]
65
+ Upgrade: |
66
+ [ protocol *( OWS "," OWS protocol ) ]
67
+ User-Agent: |
68
+ product *( RWS ( product / comment ) )
69
+ Vary: |
70
+ [ ( "*" / field-name ) *( OWS "," OWS ( "*" / field-name ) ) ]
71
+ Via: |
72
+ [ ( received-protocol RWS received-by [ RWS comment ] )
73
+ *( OWS "," OWS ( received-protocol RWS received-by [ RWS comment ] ) ) ]
74
+ WWW-Authenticate: |
75
+ [ challenge *( OWS "," OWS challenge ) ]
76
+ absolute-path: |
77
+ 1*( "/" segment )
78
+ acceptable-ranges: |
79
+ range-unit *( OWS "," OWS range-unit )
80
+ asctime-date: |
81
+ day-name SP date3 SP time-of-day SP year
82
+ auth-param: |
83
+ token BWS "=" BWS ( token / quoted-string )
84
+ auth-scheme: token
85
+ challenge: |
86
+ auth-scheme [ 1*SP ( token68 / [ auth-param *( OWS "," OWS auth-param ) ] ) ]
87
+ codings: |
88
+ content-coding / "identity" / "*"
89
+ comment: |
90
+ "(" *( ctext / quoted-pair / comment ) ")"
91
+ complete-length: 1*DIGIT
92
+ connection-option: token
93
+ content-coding: token
94
+ credentials: |
95
+ auth-scheme [ 1*SP ( token68 / [ auth-param *( OWS "," OWS auth-param ) ] ) ]
96
+ ctext: |
97
+ HTAB / SP / %x21-27 / %x2A-5B / %x5D-7E / obs-text
98
+ date1: day SP month SP year
99
+ date2: day "-" month "-" 2DIGIT
100
+ date3: |
101
+ month SP ( 2DIGIT / ( SP DIGIT ) )
102
+ day: 2DIGIT
103
+ day-name: >
104
+ %x4D.6F.6E / %x54.75.65 / %x57.65.64 / %x54.68.75 / %x46.72.69 / %x53.61.74 /
105
+ %x53.75.6E
106
+ day-name-l: >
107
+ %x4D.6F.6E.64.61.79 / %x54.75.65.73.64.61.79 / %x57.65.64.6E.65.73.64.61.79 /
108
+ %x54.68.75.72.73.64.61.79 / %x46.72.69.64.61.79 / %x53.61.74.75.72.64.61.79 /
109
+ %x53.75.6E.64.61.79
110
+ delay-seconds: 1*DIGIT
111
+ entity-tag: |
112
+ [ weak ] opaque-tag
113
+ etagc: |
114
+ "!" / %x23-7E / obs-text
115
+ expectation: |
116
+ token [ "=" ( token / quoted-string ) parameters ]
117
+ field-content: |
118
+ field-vchar [ 1*( SP / HTAB / field-vchar ) field-vchar ]
119
+ field-name: token
120
+ field-value: '*field-content'
121
+ field-vchar: VCHAR / obs-text
122
+ first-pos: 1*DIGIT
123
+ hour: 2DIGIT
124
+ http-URI: |
125
+ "http://" authority path-abempty [ "?" query ]
126
+ https-URI: |
127
+ "https://" authority path-abempty [ "?" query ]
128
+ incl-range: |
129
+ first-pos "-" last-pos
130
+ int-range: |
131
+ first-pos "-" [ last-pos ]
132
+ language-range: <language-range, see [RFC4647], Section 2.1>
133
+ language-tag: <Language-Tag, see [RFC5646], Section 2.1>
134
+ last-pos: 1*DIGIT
135
+ mailbox: <mailbox, see [RFC5322], Section 3.4>
136
+ media-range: |
137
+ ( "*/*" / ( type "/*" ) / ( type "/" subtype ) ) parameters
138
+ media-type: |
139
+ type "/" subtype parameters
140
+ method: token
141
+ minute: 2DIGIT
142
+ month: >
143
+ %x4A.61.6E / %x46.65.62 / %x4D.61.72 / %x41.70.72 / %x4D.61.79 / %x4A.75.6E /
144
+ %x4A.75.6C / %x41.75.67 / %x53.65.70 / %x4F.63.74 / %x4E.6F.76 / %x44.65.63
145
+ obs-date: |
146
+ rfc850-date / asctime-date
147
+ obs-text: '%x80-FF'
148
+ opaque-tag: |
149
+ DQUOTE *etagc DQUOTE
150
+ other-range: |
151
+ 1*( %x21-2B / %x2D-7E )
152
+ parameter: |
153
+ parameter-name "=" parameter-value
154
+ parameter-name: token
155
+ parameter-value: |
156
+ ( token / quoted-string )
157
+ parameters: |
158
+ *( OWS ";" OWS [ parameter ] )
159
+ partial-URI: |
160
+ relative-part [ "?" query ]
161
+ product: |
162
+ token [ "/" product-version ]
163
+ product-version: token
164
+ protocol: |
165
+ protocol-name [ "/" protocol-version ]
166
+ protocol-name: token
167
+ protocol-version: token
168
+ pseudonym: token
169
+ qdtext: |
170
+ HTAB / SP / "!" / %x23-5B / %x5D-7E / obs-text
171
+ quoted-pair: |
172
+ "\" ( HTAB / SP / VCHAR / obs-text )
173
+ quoted-string: |
174
+ DQUOTE *( qdtext / quoted-pair ) DQUOTE
175
+ qvalue: |
176
+ ( "0" [ "." *3DIGIT ] ) / ( "1" [ "." *3"0" ] )
177
+ range-resp: |
178
+ incl-range "/" ( complete-length / "*" )
179
+ range-set: |
180
+ range-spec *( OWS "," OWS range-spec )
181
+ range-spec: |
182
+ int-range / suffix-range / other-range
183
+ range-unit: token
184
+ ranges-specifier: |
185
+ range-unit "=" range-set
186
+ received-by: |
187
+ pseudonym [ ":" port ]
188
+ received-protocol: |
189
+ [ protocol-name "/" ] protocol-version
190
+ rfc850-date: |
191
+ day-name-l "," SP date2 SP time-of-day SP GMT
192
+ second: 2DIGIT
193
+ subtype: token
194
+ suffix-length: 1*DIGIT
195
+ suffix-range: |
196
+ "-" suffix-length
197
+ t-codings: |
198
+ "trailers" / ( transfer-coding [ weight ] )
199
+ tchar: >
200
+ "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" / "_" / "`" /
201
+ "|" / "~" / DIGIT / ALPHA
202
+ time-of-day: |
203
+ hour ":" minute ":" second
204
+ token: 1*tchar
205
+ token68: |
206
+ 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) *"="
207
+ transfer-coding: |
208
+ token *( OWS ";" OWS transfer-parameter )
209
+ transfer-parameter: |
210
+ token BWS "=" BWS ( token / quoted-string )
211
+ type: token
212
+ unsatisfied-range: |
213
+ "*/" complete-length
214
+ uri-host: |
215
+ host
216
+ weak: '%x57.2F'
217
+ weight: |
218
+ OWS ";" OWS "q=" qvalue
219
+ year: 4DIGIT
220
+ # RFC 9112
221
+ HTTP-message: |
222
+ start-line CRLF *( field-line CRLF ) CRLF [ message-body ]
223
+ HTTP-name: '%x48.54.54.50'
224
+ HTTP-version: |
225
+ HTTP-name "/" DIGIT "." DIGIT
226
+ Transfer-Encoding: |
227
+ [ transfer-coding *( OWS "," OWS transfer-coding ) ]
228
+ absolute-form: absolute-URI
229
+ asterisk-form: '*'
230
+ authority-form: |
231
+ uri-host ":" port
232
+ chunk: |
233
+ chunk-size [ chunk-ext ] CRLF chunk-data CRLF
234
+ chunk-data: |
235
+ 1*OCTET
236
+ chunk-ext: |
237
+ *( BWS ";" BWS chunk-ext-name [ BWS "=" BWS chunk-ext-val ] )
238
+ chunk-ext-name: token
239
+ chunk-ext-val: |
240
+ token / quoted-string
241
+ chunk-size: |
242
+ 1*HEXDIG
243
+ chunked-body: |
244
+ *chunk last-chunk trailer-section CRLF
245
+ field-line: |
246
+ field-name ":" OWS field-value OWS
247
+ last-chunk: |
248
+ 1*"0" [ chunk-ext ] CRLF
249
+ message-body: |
250
+ *OCTET
251
+ obs-fold: |
252
+ OWS CRLF RWS
253
+ origin-form: |
254
+ absolute-path [ "?" query ]
255
+ reason-phrase: |
256
+ 1*( HTAB / SP / VCHAR / obs-text )
257
+ request-line: |
258
+ method SP request-target SP HTTP-version
259
+ request-target: |
260
+ origin-form / absolute-form / authority-form / asterisk-form
261
+ start-line: |
262
+ request-line / status-line
263
+ status-code: 3DIGIT
264
+ status-line: |
265
+ HTTP-version SP status-code SP [ reason-phrase ]
266
+ trailer-section: |
267
+ *( field-line CRLF )
package/index.js CHANGED
@@ -4,7 +4,8 @@ const { recursiveCompile } = require('url-templates');
4
4
  const patterns = new Map();
5
5
  // RFC3986/RFC3987 common rules + https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2:~:text=DNS%29%2E-,A,of%20%5BRFC1123%5D%2E
6
6
  const commonRules = {
7
- scheme: '[a-zA-Z][a-zA-Z0-9+.-]*',
7
+ implemented_schemes: '(?:[hH][tT][tT][pP][sS]?|[wW][sS][sS]?|[fF][iI][lL][eE]):',
8
+ scheme: '(?!{implemented_schemes})[a-zA-Z][a-zA-Z0-9+.-]*',
8
9
  port: '(?:0|[1-9]\\d{0,3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])?',
9
10
  IP_literal: '\\[(?:{IPv6address}|{IPvFuture})\\]',
10
11
  IPv6address: '(?:(?:{h16}:){6}{ls32}|::(?:{h16}:){5}{ls32}|(?:(?:{h16})?)::(?:{h16}:){4}{ls32}|(?:(?:{h16}:)?{h16})?::(?:{h16}:){3}{ls32}|(?:(?:{h16}:){0,2}{h16})?::(?:{h16}:){2}{ls32}|(?:(?:{h16}:){0,3}{h16})?::(?:{h16}:){1}{ls32}|(?:(?:{h16}:){0,4}{h16})?::{ls32}|(?:(?:{h16}:){0,5}{h16})?::{h16}|(?:(?:{h16}:){0,6}{h16})?::)',
@@ -34,8 +35,7 @@ const uriRules = {
34
35
  authority: '(?:{userinfo}@)?{host}(?::{port})?',
35
36
  userinfo: '(?:{unreserved}|{pct_encoded}|{sub_delims}|:)*',
36
37
  host: '(?:{IP_literal}|{IPv4address}|{reg_name})',
37
- a_label: '(?:{alpha_digit})(?:(?:{alpha_digit}|-){0,61}(?:{alpha_digit}))?',
38
- reg_name: "(?:(?=.{1,255}(?:[:/?#]|$))(?:{a_label})(?:\\.{a_label})*)",
38
+ reg_name: '(?:{unreserved}|{pct_encoded}|{sub_delims})*',
39
39
  path: '(?:{path_abempty}|{path_absolute}|{path_noscheme}|{path_rootless}|{path_empty})',
40
40
  path_abempty: '(?:\/{segment})*',
41
41
  path_absolute: '\/(?:{segment_nz}(?:\/{segment})*)?',
@@ -60,9 +60,7 @@ const iriRules = {
60
60
  iauthority: '(?:{iuserinfo}@)?{ihost}(?::{port})?',
61
61
  iuserinfo: '(?:{iunreserved}|{pct_encoded}|{sub_delims}|:)*',
62
62
  ihost: '(?:{IP_literal}|{IPv4address}|{ireg_name})',
63
- separator: '[\\x2E\\uFF0E\\u3002\\uFF61]',
64
- u_label: '(?:{uchar})(?:(?:{uchar}|-){0,61}(?:{uchar}))?',
65
- ireg_name: '(?:(?=.{1,255}(?:[:/?#]|$))(?:{u_label})(?:{separator}(?:{u_label}))*)',
63
+ ireg_name: '(?:{iunreserved}|{pct_encoded}|{sub_delims})*',
66
64
  ipath: '(?:{ipath_abempty}|{ipath_absolute}|{ipath_noscheme}|{ipath_rootless}|{ipath_empty})',
67
65
  ipath_empty: '',
68
66
  ipath_rootless: '{isegment_nz}(?:\/{isegment})*',
@@ -77,9 +75,18 @@ const iriRules = {
77
75
  ipchar: '(?:{iunreserved}|{pct_encoded}|{sub_delims}|:|@)',
78
76
  iunreserved: '(?:{unreserved}|{ucschar})',
79
77
  iprivate: '[\\uE000-\\uF8FF\\u{F0000}-\\u{FFFFD}\\u{100000}-\\u{10FFFD}]',
80
- uchar: '[\\u200C\\u200D\\u00B7\\u0375\\u30FB\\u05F3\\u05F4\\p{L}\\p{N}\\p{Mn}\\p{Mc}]',
81
78
  ucschar: '[\\xA0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF\\u{10000}-\\u{1FFFD}\\u{20000}-\\u{2FFFD}\\u{30000}-\\u{3FFFD}\\u{40000}-\\u{4FFFD}\\u{50000}-\\u{5FFFD}\\u{60000}-\\u{6FFFD}\\u{70000}-\\u{7FFFD}\\u{80000}-\\u{8FFFD}\\u{90000}-\\u{9FFFD}\\u{A0000}-\\u{AFFFD}\\u{B0000}-\\u{BFFFD}\\u{C0000}-\\u{CFFFD}\\u{D0000}-\\u{DFFFD}\\u{E1000}-\\u{EFFFD}]',
82
79
  };
80
+ // scheme specific URI reg_name and IRI ireg_name
81
+ const schemeSpecificRules = {
82
+ scheme: '(?:https?|wss?|file)',
83
+ reg_name: '(?:(?=.{1,255}(?:[:/?#]|$))(?:{a_label})(?:\\.{a_label})*)',
84
+ a_label: '(?:{alpha_digit})(?:(?:{alpha_digit}|-){0,61}(?:{alpha_digit}))?',
85
+ ireg_name: '(?:(?=.{1,255}(?:[:/?#]|$))(?:{u_label})(?:{u_separator}(?:{u_label}))*)',
86
+ u_label: '(?:{u_char})(?:(?:{u_char}|-){0,61}(?:{u_char}))?',
87
+ u_separator: '[\\x2E\\uFF0E\\u3002\\uFF61]',
88
+ u_char: '[\\p{L}\\p{N}\\p{Mn}\\p{Mc}\\u200C\\u200D\\u00B7\\u0375\\u30FB\\u05F3\\u05F4]',
89
+ };
83
90
  // pattern RFC group names
84
91
  const groupNames = {
85
92
  scheme: 'scheme',
@@ -106,21 +113,26 @@ const groupNames = {
106
113
  ipath_empty: 'path',
107
114
  };
108
115
  // all rules into one map
109
- const rules = Object.assign({}, commonRules, uriRules, iriRules);
110
- const addNames = (key) => (groupNames[key] ? `(?<${groupNames[key]}>${rules[key]})` : rules[key]);
116
+ const isSpecificScheme = (string) => new RegExp('^' + schemeSpecificRules.scheme + ':').test(string);
117
+ const rules = (specific) => specific ? Object.assign({}, commonRules, uriRules, iriRules, schemeSpecificRules) : Object.assign({}, commonRules, uriRules, iriRules);
111
118
  // parse (slower, it uses regex.exec and includes named capture groups)
112
119
  const parse = (string, rule) => {
113
120
  if (typeof string !== 'string') throw new TypeError(`Invalid ${rule.replace('_', '-')} type: must be a string.`);
114
- if (!patterns.has('_' + rule)) patterns.set('_' + rule, new RegExp(`^${recursiveCompile(rules, rule, addNames)}$`, 'u'));
115
- const match = patterns.get('_' + rule).exec(string);
121
+ const specific = isSpecificScheme(string) ? 's' : '';
122
+ const addNames = (key) => (groupNames[key] ? `(?<${groupNames[key]}>${rules(specific)[key]})` : rules(specific)[key]);
123
+ const ruleId = '_' + specific + rule;
124
+ if (!patterns.has(ruleId)) patterns.set(ruleId, new RegExp(`^${recursiveCompile(rules(specific), rule, addNames)}$`, 'u'));
125
+ const match = patterns.get(ruleId).exec(string);
116
126
  if (match) return match.groups;
117
127
  throw new SyntaxError(`Invalid ${rule.replace('_', '-')}: ${string}`);
118
128
  };
119
129
  // validate (faster, it uses regex.test and does not include named capture groups)
120
130
  const validate = (string, rule) => {
121
131
  if (typeof string !== 'string') throw new TypeError(`Invalid ${rule.replace('_', '-')} type: must be a string.`);
122
- if (!patterns.has(rule)) patterns.set(rule, new RegExp(`^${recursiveCompile(rules, rule)}$`, 'u'));
123
- if (patterns.get(rule).test(string)) return true;
132
+ const specific = isSpecificScheme(string) ? 's' : '';
133
+ const ruleId = specific + rule;
134
+ if (!patterns.has(ruleId)) patterns.set(ruleId, new RegExp(`^${recursiveCompile(rules(specific), rule)}$`, 'u'));
135
+ if (patterns.get(ruleId).test(string)) return true;
124
136
  throw new SyntaxError(`Invalid ${rule.replace('_', '-')}: ${string}`);
125
137
  };
126
138
  // compose as per RFC 3986 Section 5.3 (component recomposition)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "identifier-js",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "A RFC3986 / RFC3987 compliant fast parser/validator/resolver/composer for NodeJS and browser.",
5
5
  "keywords": [
6
6
  "IRI",
@@ -0,0 +1,21 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import id from '../index.js';
3
+ // not yet done
4
+ const resolveTests = [
5
+ ['', 'hTTp://example.com/b/c/d/e', 'http://example.com/b/c/d/e'], // scheme to lowercase
6
+ ['', 'http://eXaMpLe.com/b/c/d/e', 'http://example.com/b/c/d/e'], // authority to lowercase
7
+ ['', 'http://example.com/b%2Ec/d/e', 'http://example.com/b.c/d/e'], // Unnecessary encoding segment
8
+ ['', 'http://example.com/b%2Fc/d/e', 'http://example.com/b%2Fc/d/e'], // Necessary encoding segment
9
+ ['', 'http://example.com/b%2fc/d/e', 'http://example.com/b%2Fc/d/e'], // Case normalization of encoding segment
10
+ ['', 'http://example.com/b?c%2Fd%3Fe', 'http://example.com/b?c/d?e'], // Unnecessary encoding query
11
+ ['#c%2Fd%3Fe', 'http://example.com/b', 'http://example.com/b#c/d?e'], // Unnecessary encoding fragment
12
+ ];
13
+
14
+ describe('resolveReference', () => {
15
+ resolveTests.forEach(([reference, base, expected]) => {
16
+ test(`resolveReference('${reference}', '${base}') === '${expected}'`, () => {
17
+ const subject = id.normalizeReference(reference, base);
18
+ expect(subject).to.equal(expected);
19
+ });
20
+ });
21
+ });
@@ -44,6 +44,7 @@ const refs = {
44
44
  "g?y/../x" : "http://a/b/c/g?y/../x",
45
45
  "g#s/./x" : "http://a/b/c/g#s/./x",
46
46
  "g#s/../x" : "http://a/b/c/g#s/../x",
47
+ "http:g" : "http:g",
47
48
  }
48
49
 
49
50
  describe('resolveReference', () => {
@@ -4,13 +4,6 @@ import id from '../index.js';
4
4
  const resolveTests = [
5
5
  ['urn:some:ip:prop', 'urn:some:ip:prop', 'urn:some:ip:prop'],
6
6
  ['urn:some:ip:prop', 'urn:some:other:prop', 'urn:some:ip:prop'],
7
- ['', 'hTTp://example.com/b/c/d/e', 'http://example.com/b/c/d/e'], // scheme to lowercase
8
- ['', 'http://eXaMpLe.com/b/c/d/e', 'http://example.com/b/c/d/e'], // authority to lowercase
9
- ['', 'http://example.com/b%2Ec/d/e', 'http://example.com/b.c/d/e'], // Unnecessary encoding segment
10
- ['', 'http://example.com/b%2Fc/d/e', 'http://example.com/b%2Fc/d/e'], // Necessary encoding segment
11
- ['', 'http://example.com/b%2fc/d/e', 'http://example.com/b%2Fc/d/e'], // Case normalization of encoding segment
12
- ['', 'http://example.com/b?c%2Fd%3Fe', 'http://example.com/b?c/d?e'], // Unnecessary encoding query
13
- ['#c%2Fd%3Fe', 'http://example.com/b', 'http://example.com/b#c/d?e'], // Unnecessary encoding fragment
14
7
  ];
15
8
 
16
9
  describe('resolveReference', () => {
@@ -0,0 +1,554 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import id from '../index.js';
3
+
4
+ describe('isUri with hostnames', () => {
5
+ test('Valid character ! (sub-delims) in uri reg_name', () => {
6
+ expect(id.isUri('uri://exa!mple')).to.equal(true);
7
+ });
8
+
9
+ test('Valid character & (sub-delims) in uri reg_name', () => {
10
+ expect(id.isUri('uri://exa&mple')).to.equal(true);
11
+ });
12
+
13
+ test('Valid character $ (sub-delims) in uri reg_name', () => {
14
+ expect(id.isUri('uri://exa$mple')).to.equal(true);
15
+ });
16
+
17
+ test("Valid character ' (sub-delims) in uri reg_name", () => {
18
+ expect(id.isUri("uri://exa'mple")).to.equal(true);
19
+ });
20
+
21
+ test('Valid character ( (sub-delims) in uri reg_name', () => {
22
+ expect(id.isUri('uri://exa(mple')).to.equal(true);
23
+ });
24
+
25
+ test('Valid character ) (sub-delims) in uri reg_name', () => {
26
+ expect(id.isUri('uri://exa)mple')).to.equal(true);
27
+ });
28
+
29
+ test('Valid character * (sub-delims) in uri reg_name', () => {
30
+ expect(id.isUri('uri://exa*mple')).to.equal(true);
31
+ });
32
+
33
+ test('Valid character + (sub-delims) in uri reg_name', () => {
34
+ expect(id.isUri('uri://exa+mple')).to.equal(true);
35
+ });
36
+
37
+ test('Valid character , (sub-delims) in uri reg_name', () => {
38
+ expect(id.isUri('uri://exa,mple')).to.equal(true);
39
+ });
40
+
41
+ test('Valid character ; (sub-delims) in uri reg_name', () => {
42
+ expect(id.isUri('uri://exa;mple')).to.equal(true);
43
+ });
44
+
45
+ test('Valid character = (sub-delims) in uri reg_name', () => {
46
+ expect(id.isUri('uri://exa=mple')).to.equal(true);
47
+ });
48
+
49
+ test('Valid character . multiple times (unreserved) in uri reg_name', () => {
50
+ expect(id.isUri('uri://exa..mple')).to.equal(true);
51
+ });
52
+
53
+ test('Valid character ~ (unreserved) in uri reg_name', () => {
54
+ expect(id.isUri('uri://exa~mple')).to.equal(true);
55
+ });
56
+
57
+ test('Valid character _ (unreserved) in uri reg_name', () => {
58
+ expect(id.isUri('uri://exa_mple')).to.equal(true);
59
+ });
60
+
61
+ test('Valid character %20 (pct-encoded) in uri reg_name', () => {
62
+ expect(id.isUri('uri://exa%20mple')).to.equal(true);
63
+ });
64
+
65
+ test('Invalid %GG (pct-encoded) in uri reg_name', () => {
66
+ expect(() => id.isUri('uri://exa%GGmple')).to.throw(Error, 'Invalid URI: uri://exa%GGmple');
67
+ });
68
+
69
+ test('Valid label - alphanumeric', () => {
70
+ expect(id.isUri('https://example')).to.equal(true);
71
+ });
72
+
73
+ test('Valid label - hyphen in middle', () => {
74
+ expect(id.isUri('https://exa-mple')).to.equal(true);
75
+ });
76
+
77
+ test('Invalid label - hyphen at start', () => {
78
+ expect(() => id.isUri('https://-example')).to.throw(Error, 'Invalid URI: https://-example');
79
+ });
80
+
81
+ test('Invalid label - hyphen at end', () => {
82
+ expect(() => id.isUri('https://example-')).to.throw(Error, 'Invalid URI: https://example-');
83
+ });
84
+
85
+ test('Valid multiple labels', () => {
86
+ expect(id.isUri('https://example-domain.com')).to.equal(true);
87
+ });
88
+
89
+ test('Invalid - leading dot', () => {
90
+ expect(() => id.isUri('https://.example.com')).to.throw(Error, 'Invalid URI: https://.example.com');
91
+ });
92
+
93
+ test('Invalid - trailing dot', () => {
94
+ expect(() => id.isUri('https://example.com.')).to.throw(Error, 'Invalid URI: https://example.com.');
95
+ });
96
+
97
+ test('Invalid - consecutive dots', () => {
98
+ expect(() => id.isUri('https://example..com')).to.throw(Error, 'Invalid URI: https://example..com');
99
+ });
100
+
101
+ test('Invalid - unicode character', () => {
102
+ expect(() => id.isUri('https://exämple')).to.throw(Error, 'Invalid URI: https://exämple');
103
+ });
104
+
105
+ test('Invalid - % character (pct_encoded) in http(s) reg_name', () => {
106
+ expect(() => id.isUri('https://exa%20mple')).to.throw(Error, 'Invalid URI: https://exa%20mple');
107
+ });
108
+
109
+ test('Invalid - % character (pct_encoded) in ws(s) reg_name', () => {
110
+ expect(() => id.isUri('wss://exa%20mple')).to.throw(Error, 'Invalid URI: wss://exa%20mple');
111
+ });
112
+
113
+ test('Invalid - % character (pct_encoded) in file reg_name', () => {
114
+ expect(() => id.isUri('file://exa%20mple')).to.throw(Error, 'Invalid URI: file://exa%20mple');
115
+ });
116
+
117
+ test('Invalid - ~ character (unreserved) in http(s) reg_name', () => {
118
+ expect(() => id.isUri('https://exa~mple')).to.throw(Error, 'Invalid URI: https://exa~mple');
119
+ });
120
+
121
+ test('Invalid - ~ character (unreserved) in ws(s) reg_name', () => {
122
+ expect(() => id.isUri('wss://exa~mple')).to.throw(Error, 'Invalid URI: wss://exa~mple');
123
+ });
124
+
125
+ test('Invalid - ~ character (unreserved) in file reg_name', () => {
126
+ expect(() => id.isUri('file://exa~mple')).to.throw(Error, 'Invalid URI: file://exa~mple');
127
+ });
128
+
129
+ test('Invalid - _ character (unreserved) in http(s) reg_name', () => {
130
+ expect(() => id.isUri('https://exa_mple')).to.throw(Error, 'Invalid URI: https://exa_mple');
131
+ });
132
+
133
+ test('Invalid - _ character (unreserved) in ws(s) reg_name', () => {
134
+ expect(() => id.isUri('wss://exa_mple')).to.throw(Error, 'Invalid URI: wss://exa_mple');
135
+ });
136
+
137
+ test('Invalid - _ character (unreserved) in file reg_name', () => {
138
+ expect(() => id.isUri('file://exa_mple')).to.throw(Error, 'Invalid URI: file://exa_mple');
139
+ });
140
+
141
+ test('Invalid - ! character (sub-delims) in http(s) reg_name', () => {
142
+ expect(() => id.isUri('https://exa!mple')).to.throw(Error, 'Invalid URI: https://exa!mple');
143
+ });
144
+
145
+ test('Invalid - ! character (sub-delims) in ws(s) reg_name', () => {
146
+ expect(() => id.isUri('wss://exa!mple')).to.throw(Error, 'Invalid URI: wss://exa!mple');
147
+ });
148
+
149
+ test('Invalid - ! character (sub-delims) in file reg_name', () => {
150
+ expect(() => id.isUri('file://exa!mple')).to.throw(Error, 'Invalid URI: file://exa!mple');
151
+ });
152
+
153
+ test('Invalid - & character (sub-delims) in http(s) reg_name', () => {
154
+ expect(() => id.isUri('https://exa&mple')).to.throw(Error, 'Invalid URI: https://exa&mple');
155
+ });
156
+
157
+ test('Invalid - & character (sub-delims) in ws(s) reg_name', () => {
158
+ expect(() => id.isUri('wss://exa&mple')).to.throw(Error, 'Invalid URI: wss://exa&mple');
159
+ });
160
+
161
+ test('Invalid - & character (sub-delims) in file reg_name', () => {
162
+ expect(() => id.isUri('file://exa&mple')).to.throw(Error, 'Invalid URI: file://exa&mple');
163
+ });
164
+
165
+ test('Invalid - $ character (sub-delims) in http(s) reg_name', () => {
166
+ expect(() => id.isUri('https://exa$mple')).to.throw(Error, 'Invalid URI: https://exa$mple');
167
+ });
168
+
169
+ test('Invalid - $ character (sub-delims) in ws(s) reg_name', () => {
170
+ expect(() => id.isUri('wss://exa$mple')).to.throw(Error, 'Invalid URI: wss://exa$mple');
171
+ });
172
+
173
+ test('Invalid - $ character (sub-delims) in file reg_name', () => {
174
+ expect(() => id.isUri('file://exa$mple')).to.throw(Error, 'Invalid URI: file://exa$mple');
175
+ });
176
+
177
+ test("Invalid - ' character (sub-delims) in http(s) reg_name", () => {
178
+ expect(() => id.isUri("https://exa'mple")).to.throw(Error, "Invalid URI: https://exa'mple");
179
+ });
180
+
181
+ test("Invalid - ' character (sub-delims) in ws(s) reg_name", () => {
182
+ expect(() => id.isUri("wss://exa'mple")).to.throw(Error, "Invalid URI: wss://exa'mple");
183
+ });
184
+
185
+ test("Invalid - ' character (sub-delims) in file reg_name", () => {
186
+ expect(() => id.isUri("file://exa'mple")).to.throw(Error, "Invalid URI: file://exa'mple");
187
+ });
188
+
189
+ test('Invalid - ( character (sub-delims) in http(s) reg_name', () => {
190
+ expect(() => id.isUri('https://exa(mple')).to.throw(Error, 'Invalid URI: https://exa(mple');
191
+ });
192
+
193
+ test('Invalid - ( character (sub-delims) in ws(s) reg_name', () => {
194
+ expect(() => id.isUri('wss://exa(mple')).to.throw(Error, 'Invalid URI: wss://exa(mple');
195
+ });
196
+
197
+ test('Invalid - ( character (sub-delims) in file reg_name', () => {
198
+ expect(() => id.isUri('file://exa(mple')).to.throw(Error, 'Invalid URI: file://exa(mple');
199
+ });
200
+
201
+ test('Invalid - ) character (sub-delims) in http(s) reg_name', () => {
202
+ expect(() => id.isUri('https://exa)mple')).to.throw(Error, 'Invalid URI: https://exa)mple');
203
+ });
204
+
205
+ test('Invalid - ) character (sub-delims) in ws(s) reg_name', () => {
206
+ expect(() => id.isUri('wss://exa)mple')).to.throw(Error, 'Invalid URI: wss://exa)mple');
207
+ });
208
+
209
+ test('Invalid - ) character (sub-delims) in file reg_name', () => {
210
+ expect(() => id.isUri('file://exa)mple')).to.throw(Error, 'Invalid URI: file://exa)mple');
211
+ });
212
+
213
+ test('Invalid - * character (sub-delims) in http(s) reg_name', () => {
214
+ expect(() => id.isUri('https://exa*mple')).to.throw(Error, 'Invalid URI: https://exa*mple');
215
+ });
216
+
217
+ test('Invalid - * character (sub-delims) in ws(s) reg_name', () => {
218
+ expect(() => id.isUri('wss://exa*mple')).to.throw(Error, 'Invalid URI: wss://exa*mple');
219
+ });
220
+
221
+ test('Invalid - * character (sub-delims) in file reg_name', () => {
222
+ expect(() => id.isUri('file://exa*mple')).to.throw(Error, 'Invalid URI: file://exa*mple');
223
+ });
224
+
225
+ test('Invalid - + character (sub-delims) in http(s) reg_name', () => {
226
+ expect(() => id.isUri('https://exa+mple')).to.throw(Error, 'Invalid URI: https://exa+mple');
227
+ });
228
+
229
+ test('Invalid - + character (sub-delims) in ws(s) reg_name', () => {
230
+ expect(() => id.isUri('wss://exa+mple')).to.throw(Error, 'Invalid URI: wss://exa+mple');
231
+ });
232
+
233
+ test('Invalid - + character (sub-delims) in file reg_name', () => {
234
+ expect(() => id.isUri('file://exa+mple')).to.throw(Error, 'Invalid URI: file://exa+mple');
235
+ });
236
+
237
+ test('Invalid - , character (sub-delims) in http(s) reg_name', () => {
238
+ expect(() => id.isUri('https://exa,mple')).to.throw(Error, 'Invalid URI: https://exa,mple');
239
+ });
240
+
241
+ test('Invalid - , character (sub-delims) in ws(s) reg_name', () => {
242
+ expect(() => id.isUri('wss://exa,mple')).to.throw(Error, 'Invalid URI: wss://exa,mple');
243
+ });
244
+
245
+ test('Invalid - , character (sub-delims) in file reg_name', () => {
246
+ expect(() => id.isUri('file://exa,mple')).to.throw(Error, 'Invalid URI: file://exa,mple');
247
+ });
248
+
249
+ test('Invalid - ; character (sub-delims) in http(s) reg_name', () => {
250
+ expect(() => id.isUri('https://exa;mple')).to.throw(Error, 'Invalid URI: https://exa;mple');
251
+ });
252
+
253
+ test('Invalid - ; character (sub-delims) in ws(s) reg_name', () => {
254
+ expect(() => id.isUri('wss://exa;mple')).to.throw(Error, 'Invalid URI: wss://exa;mple');
255
+ });
256
+
257
+ test('Invalid - ; character (sub-delims) in file reg_name', () => {
258
+ expect(() => id.isUri('file://exa;mple')).to.throw(Error, 'Invalid URI: file://exa;mple');
259
+ });
260
+
261
+ test('Invalid - = character (sub-delims) in http(s) reg_name', () => {
262
+ expect(() => id.isUri('https://exa=mple')).to.throw(Error, 'Invalid URI: https://exa=mple');
263
+ });
264
+
265
+ test('Invalid - = character (sub-delims) in ws(s) reg_name', () => {
266
+ expect(() => id.isUri('wss://exa=mple')).to.throw(Error, 'Invalid URI: wss://exa=mple');
267
+ });
268
+
269
+ test('Invalid - = character (sub-delims) in file reg_name', () => {
270
+ expect(() => id.isUri('file://exa=mple')).to.throw(Error, 'Invalid URI: file://exa=mple');
271
+ });
272
+ });
273
+
274
+ describe('isIri with hostnames', () => {
275
+ test('Valid character ! (sub-delims) in iri reg_name', () => {
276
+ expect(id.isIri('iri://exa!mple')).to.equal(true);
277
+ });
278
+
279
+ test('Valid character & (sub-delims) in iri reg_name', () => {
280
+ expect(id.isIri('iri://exa&mple')).to.equal(true);
281
+ });
282
+
283
+ test('Valid character $ (sub-delims) in iri reg_name', () => {
284
+ expect(id.isIri('iri://exa$mple')).to.equal(true);
285
+ });
286
+
287
+ test("Valid character ' (sub-delims) in iri reg_name", () => {
288
+ expect(id.isIri("iri://exa'mple")).to.equal(true);
289
+ });
290
+
291
+ test('Valid character ( (sub-delims) in iri reg_name', () => {
292
+ expect(id.isIri('iri://exa(mple')).to.equal(true);
293
+ });
294
+
295
+ test('Valid character ) (sub-delims) in iri reg_name', () => {
296
+ expect(id.isIri('iri://exa)mple')).to.equal(true);
297
+ });
298
+
299
+ test('Valid character * (sub-delims) in iri reg_name', () => {
300
+ expect(id.isIri('iri://exa*mple')).to.equal(true);
301
+ });
302
+
303
+ test('Valid character + (sub-delims) in iri reg_name', () => {
304
+ expect(id.isIri('iri://exa+mple')).to.equal(true);
305
+ });
306
+
307
+ test('Valid character , (sub-delims) in iri reg_name', () => {
308
+ expect(id.isIri('iri://exa,mple')).to.equal(true);
309
+ });
310
+
311
+ test('Valid character ; (sub-delims) in iri reg_name', () => {
312
+ expect(id.isIri('iri://exa;mple')).to.equal(true);
313
+ });
314
+
315
+ test('Valid character = (sub-delims) in iri reg_name', () => {
316
+ expect(id.isIri('iri://exa=mple')).to.equal(true);
317
+ });
318
+
319
+ test('Valid character . multiple times (unreserved) in iri reg_name', () => {
320
+ expect(id.isIri('iri://exa..mple')).to.equal(true);
321
+ });
322
+
323
+ test('Valid character _ (unreserved) in iri reg_name', () => {
324
+ expect(id.isIri('iri://exa_mple')).to.equal(true);
325
+ });
326
+
327
+ test('Valid character %20 (pct-encoded) in iri reg_name', () => {
328
+ expect(id.isIri('iri://exa%20mple')).to.equal(true);
329
+ });
330
+
331
+ test('Invalid %GG (invalid pct-encoded) in iri reg_name', () => {
332
+ expect(() => id.isIri('iri://exa%GGmple')).to.throw(Error, 'Invalid IRI: iri://exa%GGmple');
333
+ });
334
+
335
+ test('Valid label - alphanumeric', () => {
336
+ expect(id.isIri('https://example')).to.equal(true);
337
+ });
338
+
339
+ test('Valid label - hyphen in middle', () => {
340
+ expect(id.isIri('https://exa-mple')).to.equal(true);
341
+ });
342
+
343
+ test('Invalid label - hyphen at start', () => {
344
+ expect(() => id.isIri('https://-example')).to.throw(Error, 'Invalid IRI: https://-example');
345
+ });
346
+
347
+ test('Invalid label - hyphen at end', () => {
348
+ expect(() => id.isIri('https://example-')).to.throw(Error, 'Invalid IRI: https://example-');
349
+ });
350
+
351
+ test('Valid unicode label - Latin extended', () => {
352
+ expect(id.isIri('https://exämple')).to.equal(true);
353
+ });
354
+
355
+ test('Valid unicode label - Chinese', () => {
356
+ expect(id.isIri('https://例子')).to.equal(true);
357
+ });
358
+
359
+ test('Valid unicode label - Hindi', () => {
360
+ expect(id.isIri('https://उदाहरण')).to.equal(true);
361
+ });
362
+
363
+ test('Valid unicode label - Japanese', () => {
364
+ expect(id.isIri('https://例え.テスト')).to.equal(true);
365
+ });
366
+
367
+ test('Valid label with middle dot', () => {
368
+ expect(id.isIri('https://exa·mple')).to.equal(true);
369
+ });
370
+
371
+ test('Invalid - leading dot', () => {
372
+ expect(() => id.isIri('https://.example')).to.throw(Error, 'Invalid IRI: https://.example');
373
+ });
374
+
375
+ test('Invalid - trailing dot', () => {
376
+ expect(() => id.isIri('https://example.')).to.throw(Error, 'Invalid IRI: https://example.');
377
+ });
378
+
379
+ test('Invalid - consecutive dots', () => {
380
+ expect(() => id.isIri('https://example..test')).to.throw(Error, 'Invalid IRI: https://example..test');
381
+ });
382
+
383
+ test('Invalid - emoji in label', () => {
384
+ expect(() => id.isIri('https://example😀')).to.throw(Error, 'Invalid IRI: https://example😀');
385
+ });
386
+
387
+ test('Invalid - % character (pct_encoded) in http(s) reg_name', () => {
388
+ expect(() => id.isIri('https://exa%20mple')).to.throw(Error, 'Invalid IRI: https://exa%20mple');
389
+ });
390
+
391
+ test('Invalid - % character (pct_encoded) in ws(s) reg_name', () => {
392
+ expect(() => id.isIri('wss://exa%20mple')).to.throw(Error, 'Invalid IRI: wss://exa%20mple');
393
+ });
394
+
395
+ test('Invalid - % character (pct_encoded) in file reg_name', () => {
396
+ expect(() => id.isIri('file://exa%20mple')).to.throw(Error, 'Invalid IRI: file://exa%20mple');
397
+ });
398
+
399
+ test('Invalid - ~ character (unreserved) in http(s) reg_name', () => {
400
+ expect(() => id.isIri('https://exa~mple')).to.throw(Error, 'Invalid IRI: https://exa~mple');
401
+ });
402
+
403
+ test('Invalid - ~ character (unreserved) in ws(s) reg_name', () => {
404
+ expect(() => id.isIri('wss://exa~mple')).to.throw(Error, 'Invalid IRI: wss://exa~mple');
405
+ });
406
+
407
+ test('Invalid - ~ character (unreserved) in file reg_name', () => {
408
+ expect(() => id.isIri('file://exa~mple')).to.throw(Error, 'Invalid IRI: file://exa~mple');
409
+ });
410
+
411
+ test('Invalid - _ character (unreserved) in http(s) reg_name', () => {
412
+ expect(() => id.isIri('https://exa_mple')).to.throw(Error, 'Invalid IRI: https://exa_mple');
413
+ });
414
+
415
+ test('Invalid - _ character (unreserved) in ws(s) reg_name', () => {
416
+ expect(() => id.isIri('wss://exa_mple')).to.throw(Error, 'Invalid IRI: wss://exa_mple');
417
+ });
418
+
419
+ test('Invalid - _ character (unreserved) in file reg_name', () => {
420
+ expect(() => id.isIri('file://exa_mple')).to.throw(Error, 'Invalid IRI: file://exa_mple');
421
+ });
422
+
423
+ test('Invalid - ! character (sub-delims) in http(s) reg_name', () => {
424
+ expect(() => id.isIri('https://exa!mple')).to.throw(Error, 'Invalid IRI: https://exa!mple');
425
+ });
426
+
427
+ test('Invalid - ! character (sub-delims) in ws(s) reg_name', () => {
428
+ expect(() => id.isIri('wss://exa!mple')).to.throw(Error, 'Invalid IRI: wss://exa!mple');
429
+ });
430
+
431
+ test('Invalid - ! character (sub-delims) in file reg_name', () => {
432
+ expect(() => id.isIri('file://exa!mple')).to.throw(Error, 'Invalid IRI: file://exa!mple');
433
+ });
434
+
435
+ test('Invalid - & character (sub-delims) in http(s) reg_name', () => {
436
+ expect(() => id.isIri('https://exa&mple')).to.throw(Error, 'Invalid IRI: https://exa&mple');
437
+ });
438
+
439
+ test('Invalid - & character (sub-delims) in ws(s) reg_name', () => {
440
+ expect(() => id.isIri('wss://exa&mple')).to.throw(Error, 'Invalid IRI: wss://exa&mple');
441
+ });
442
+
443
+ test('Invalid - & character (sub-delims) in file reg_name', () => {
444
+ expect(() => id.isIri('file://exa&mple')).to.throw(Error, 'Invalid IRI: file://exa&mple');
445
+ });
446
+
447
+ test('Invalid - $ character (sub-delims) in http(s) reg_name', () => {
448
+ expect(() => id.isIri('https://exa$mple')).to.throw(Error, 'Invalid IRI: https://exa$mple');
449
+ });
450
+
451
+ test('Invalid - $ character (sub-delims) in ws(s) reg_name', () => {
452
+ expect(() => id.isIri('wss://exa$mple')).to.throw(Error, 'Invalid IRI: wss://exa$mple');
453
+ });
454
+
455
+ test('Invalid - $ character (sub-delims) in file reg_name', () => {
456
+ expect(() => id.isIri('file://exa$mple')).to.throw(Error, 'Invalid IRI: file://exa$mple');
457
+ });
458
+
459
+ test("Invalid - ' character (sub-delims) in http(s) reg_name", () => {
460
+ expect(() => id.isIri("https://exa'mple")).to.throw(Error, "Invalid IRI: https://exa'mple");
461
+ });
462
+
463
+ test("Invalid - ' character (sub-delims) in ws(s) reg_name", () => {
464
+ expect(() => id.isIri("wss://exa'mple")).to.throw(Error, "Invalid IRI: wss://exa'mple");
465
+ });
466
+
467
+ test("Invalid - ' character (sub-delims) in file reg_name", () => {
468
+ expect(() => id.isIri("file://exa'mple")).to.throw(Error, "Invalid IRI: file://exa'mple");
469
+ });
470
+
471
+ test('Invalid - ( character (sub-delims) in http(s) reg_name', () => {
472
+ expect(() => id.isIri('https://exa(mple')).to.throw(Error, 'Invalid IRI: https://exa(mple');
473
+ });
474
+
475
+ test('Invalid - ( character (sub-delims) in ws(s) reg_name', () => {
476
+ expect(() => id.isIri('wss://exa(mple')).to.throw(Error, 'Invalid IRI: wss://exa(mple');
477
+ });
478
+
479
+ test('Invalid - ( character (sub-delims) in file reg_name', () => {
480
+ expect(() => id.isIri('file://exa(mple')).to.throw(Error, 'Invalid IRI: file://exa(mple');
481
+ });
482
+
483
+ test('Invalid - ) character (sub-delims) in http(s) reg_name', () => {
484
+ expect(() => id.isIri('https://exa)mple')).to.throw(Error, 'Invalid IRI: https://exa)mple');
485
+ });
486
+
487
+ test('Invalid - ) character (sub-delims) in ws(s) reg_name', () => {
488
+ expect(() => id.isIri('wss://exa)mple')).to.throw(Error, 'Invalid IRI: wss://exa)mple');
489
+ });
490
+
491
+ test('Invalid - ) character (sub-delims) in file reg_name', () => {
492
+ expect(() => id.isIri('file://exa)mple')).to.throw(Error, 'Invalid IRI: file://exa)mple');
493
+ });
494
+
495
+ test('Invalid - * character (sub-delims) in http(s) reg_name', () => {
496
+ expect(() => id.isIri('https://exa*mple')).to.throw(Error, 'Invalid IRI: https://exa*mple');
497
+ });
498
+
499
+ test('Invalid - * character (sub-delims) in ws(s) reg_name', () => {
500
+ expect(() => id.isIri('wss://exa*mple')).to.throw(Error, 'Invalid IRI: wss://exa*mple');
501
+ });
502
+
503
+ test('Invalid - * character (sub-delims) in file reg_name', () => {
504
+ expect(() => id.isIri('file://exa*mple')).to.throw(Error, 'Invalid IRI: file://exa*mple');
505
+ });
506
+
507
+ test('Invalid - + character (sub-delims) in http(s) reg_name', () => {
508
+ expect(() => id.isIri('https://exa+mple')).to.throw(Error, 'Invalid IRI: https://exa+mple');
509
+ });
510
+
511
+ test('Invalid - + character (sub-delims) in ws(s) reg_name', () => {
512
+ expect(() => id.isIri('wss://exa+mple')).to.throw(Error, 'Invalid IRI: wss://exa+mple');
513
+ });
514
+
515
+ test('Invalid - + character (sub-delims) in file reg_name', () => {
516
+ expect(() => id.isIri('file://exa+mple')).to.throw(Error, 'Invalid IRI: file://exa+mple');
517
+ });
518
+
519
+ test('Invalid - , character (sub-delims) in http(s) reg_name', () => {
520
+ expect(() => id.isIri('https://exa,mple')).to.throw(Error, 'Invalid IRI: https://exa,mple');
521
+ });
522
+
523
+ test('Invalid - , character (sub-delims) in ws(s) reg_name', () => {
524
+ expect(() => id.isIri('wss://exa,mple')).to.throw(Error, 'Invalid IRI: wss://exa,mple');
525
+ });
526
+
527
+ test('Invalid - , character (sub-delims) in file reg_name', () => {
528
+ expect(() => id.isIri('file://exa,mple')).to.throw(Error, 'Invalid IRI: file://exa,mple');
529
+ });
530
+
531
+ test('Invalid - ; character (sub-delims) in http(s) reg_name', () => {
532
+ expect(() => id.isIri('https://exa;mple')).to.throw(Error, 'Invalid IRI: https://exa;mple');
533
+ });
534
+
535
+ test('Invalid - ; character (sub-delims) in ws(s) reg_name', () => {
536
+ expect(() => id.isIri('wss://exa;mple')).to.throw(Error, 'Invalid IRI: wss://exa;mple');
537
+ });
538
+
539
+ test('Invalid - ; character (sub-delims) in file reg_name', () => {
540
+ expect(() => id.isIri('file://exa;mple')).to.throw(Error, 'Invalid IRI: file://exa;mple');
541
+ });
542
+
543
+ test('Invalid - = character (sub-delims) in http(s) reg_name', () => {
544
+ expect(() => id.isIri('https://exa=mple')).to.throw(Error, 'Invalid IRI: https://exa=mple');
545
+ });
546
+
547
+ test('Invalid - = character (sub-delims) in ws(s) reg_name', () => {
548
+ expect(() => id.isIri('wss://exa=mple')).to.throw(Error, 'Invalid IRI: wss://exa=mple');
549
+ });
550
+
551
+ test('Invalid - = character (sub-delims) in file reg_name', () => {
552
+ expect(() => id.isIri('file://exa=mple')).to.throw(Error, 'Invalid IRI: file://exa=mple');
553
+ });
554
+ });
@@ -7,12 +7,13 @@ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
7
7
  // Install vitest if not already installed
8
8
  if (!packageJson.devDependencies?.vitest) {
9
9
  console.log('Installing vitest...');
10
- execSync('npm install --save-dev vitest', { stdio: 'inherit' });
10
+ execSync('npm i -D vitest', { stdio: 'inherit' });
11
11
  }
12
12
 
13
13
  // Ensure the test script is set to vitest
14
14
  if (packageJson.scripts?.test !== 'vitest') {
15
15
  console.log('Updating test script to vitest...');
16
16
  packageJson.scripts.test = 'vitest --watch=false';
17
+ packageJson.devDependencies = { vitest: '*' };
17
18
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
18
19
  }
@@ -1,94 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
- import id from '../index.js';
3
-
4
- describe('isUri with hostnames', () => {
5
- test('Valid label - alphanumeric', () => {
6
- expect(id.isUri('https://example')).to.equal(true);
7
- });
8
-
9
- test('Valid label - hyphen in middle', () => {
10
- expect(id.isUri('https://exa-mple')).to.equal(true);
11
- });
12
-
13
- test('Invalid label - hyphen at start', () => {
14
- expect(() => id.isUri('https://-example')).to.throw(Error, 'Invalid URI: https://-example');
15
- });
16
-
17
- test('Invalid label - hyphen at end', () => {
18
- expect(() => id.isUri('https://example-')).to.throw(Error, 'Invalid URI: https://example-');
19
- });
20
-
21
- test('Valid multiple labels', () => {
22
- expect(id.isUri('https://example-domain.com')).to.equal(true);
23
- });
24
-
25
- test('Invalid - leading dot', () => {
26
- expect(() => id.isUri('https://.example.com')).to.throw(Error, 'Invalid URI: https://.example.com');
27
- });
28
-
29
- test('Invalid - trailing dot', () => {
30
- expect(() => id.isUri('https://example.com.')).to.throw(Error, 'Invalid URI: https://example.com.');
31
- });
32
-
33
- test('Invalid - consecutive dots', () => {
34
- expect(() => id.isUri('https://example..com')).to.throw(Error, 'Invalid URI: https://example..com');
35
- });
36
-
37
- test('Invalid - unicode character', () => {
38
- expect(() => id.isUri('https://exämple')).to.throw(Error, 'Invalid URI: https://exämple');
39
- });
40
- });
41
-
42
- describe('isIri with hostnames', () => {
43
- test('Valid label - alphanumeric', () => {
44
- expect(id.isIri('https://example')).to.equal(true);
45
- });
46
-
47
- test('Valid label - hyphen in middle', () => {
48
- expect(id.isIri('https://exa-mple')).to.equal(true);
49
- });
50
-
51
- test('Invalid label - hyphen at start', () => {
52
- expect(() => id.isIri('https://-example')).to.throw(Error, 'Invalid IRI: https://-example');
53
- });
54
-
55
- test('Invalid label - hyphen at end', () => {
56
- expect(() => id.isIri('https://example-')).to.throw(Error, 'Invalid IRI: https://example-');
57
- });
58
-
59
- test('Valid unicode label - Latin extended', () => {
60
- expect(id.isIri('https://exämple')).to.equal(true);
61
- });
62
-
63
- test('Valid unicode label - Chinese', () => {
64
- expect(id.isIri('https://例子')).to.equal(true);
65
- });
66
-
67
- test('Valid unicode label - Hindi', () => {
68
- expect(id.isIri('https://उदाहरण')).to.equal(true);
69
- });
70
-
71
- test('Valid unicode label - Japanese', () => {
72
- expect(id.isIri('https://例え.テスト')).to.equal(true);
73
- });
74
-
75
- test('Valid label with middle dot', () => {
76
- expect(id.isIri('https://exa·mple')).to.equal(true);
77
- });
78
-
79
- test('Invalid - leading dot', () => {
80
- expect(() => id.isIri('https://.example')).to.throw(Error, 'Invalid IRI: https://.example');
81
- });
82
-
83
- test('Invalid - trailing dot', () => {
84
- expect(() => id.isIri('https://example.')).to.throw(Error, 'Invalid IRI: https://example.');
85
- });
86
-
87
- test('Invalid - consecutive dots', () => {
88
- expect(() => id.isIri('https://example..test')).to.throw(Error, 'Invalid IRI: https://example..test');
89
- });
90
-
91
- test('Invalid - emoji in label', () => {
92
- expect(() => id.isIri('https://example😀')).to.throw(Error, 'Invalid IRI: https://example😀');
93
- });
94
- });