@limetech/lime-elements 40.13.1 → 40.14.1

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.
@@ -21358,6 +21358,12 @@ function requireUtils$1 () {
21358
21358
  /** @type {(value: string) => boolean} */
21359
21359
  const isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u);
21360
21360
 
21361
+ /** @type {(value: string) => boolean} */
21362
+ const isRegNameCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=]$/u);
21363
+
21364
+ /** @type {(value: string) => boolean} */
21365
+ const isLiteralRegName = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=]*$/u);
21366
+
21361
21367
  /**
21362
21368
  * @param {Array<string>} input
21363
21369
  * @returns {string}
@@ -21681,23 +21687,78 @@ function requireUtils$1 () {
21681
21687
  }
21682
21688
 
21683
21689
  /**
21684
- * Re-escape RFC 3986 gen-delims that must not appear literally in the host.
21685
- * After the URI regex parses, these characters cannot be literal in the host
21686
- * field, so any that appear after decoding came from percent-encoding and
21687
- * must be restored to prevent authority structure changes.
21690
+ * Removes dot segments from the path of a relative reference (a path that does
21691
+ * not start with "/") without changing what it resolves to against any base.
21692
+ * Unlike `removeDotSegments`, leading ".." segments that cannot be collapsed
21693
+ * are kept, the result never becomes root-relative, and a result that would be
21694
+ * empty or start with an empty segment is prefixed with "." (an empty path
21695
+ * means "same document" and a leading "//" would introduce an authority).
21696
+ *
21697
+ * @param {string} path
21698
+ * @returns {string}
21699
+ */
21700
+ function removeDotSegmentsRelative (path) {
21701
+ if (path === '' || path[0] === '/') {
21702
+ return removeDotSegments(path)
21703
+ }
21704
+
21705
+ const segments = path.split('/');
21706
+ const last = segments.length - 1;
21707
+ /** @type {string[]} */
21708
+ const output = [];
21709
+ let trailingDirectory = false;
21710
+
21711
+ for (let i = 0; i <= last; i++) {
21712
+ const segment = segments[i];
21713
+ if (segment === '.' || segment === '..') {
21714
+ if (segment === '..') {
21715
+ if (output.length !== 0 && output[output.length - 1] !== '..') {
21716
+ output.pop();
21717
+ } else {
21718
+ output.push('..');
21719
+ }
21720
+ }
21721
+ trailingDirectory = i === last;
21722
+ } else {
21723
+ output.push(segment);
21724
+ }
21725
+ }
21726
+
21727
+ if (trailingDirectory && output[output.length - 1] !== '..') {
21728
+ output.push('');
21729
+ }
21730
+ if (output.length === 0 || output[0] === '' || output[0].includes(':')) {
21731
+ // An empty path, a leading empty segment ("//"), or a first segment
21732
+ // containing ":" (which would be mistaken for a scheme, RFC 3986 section
21733
+ // 4.2) must stay behind a "." segment so the reference keeps its meaning.
21734
+ output.unshift('.');
21735
+ }
21736
+
21737
+ return output.join('/')
21738
+ }
21739
+
21740
+ /**
21741
+ * Encodes a host according to the RFC 3986 host grammar. Valid IP literals
21742
+ * have already been checked by `normalizeIPv6`, so their address separators
21743
+ * remain literal. Every other host is a reg-name and may contain only
21744
+ * unreserved characters, sub-delimiters, and valid percent escapes.
21688
21745
  *
21689
21746
  * @param {string} host
21690
- * @param {boolean} isIP - true for IPv4/IPv6 hosts (skip colon re-escaping)
21747
+ * @param {boolean} isIP - true for a validated IPv4/IPv6 host
21748
+ * @param {boolean} [allowNonAscii=false] - preserve non-ASCII IRI characters
21691
21749
  * @returns {string}
21692
21750
  */
21693
- const HOST_DELIMS = { '@': '%40', '/': '%2F', '?': '%3F', '#': '%23', ':': '%3A' };
21694
- const HOST_DELIM_RE = /[@/?#:]/g;
21695
- const HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
21751
+ const IP_HOST_DELIMS = { '@': '%40', '/': '%2F', '?': '%3F', '#': '%23' };
21752
+ const IP_HOST_DELIM_RE = /[@/?#]/g;
21696
21753
 
21697
- function reescapeHostDelimiters (host, isIP) {
21698
- const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
21699
- re.lastIndex = 0;
21700
- return host.replace(re, (ch) => HOST_DELIMS[ch])
21754
+ function encodeHost (host, isIP, allowNonAscii = false) {
21755
+ if (!isIP) {
21756
+ if (isLiteralRegName(host)) return host
21757
+ return encodeComponent(host, isRegNameCharacter, allowNonAscii)
21758
+ }
21759
+
21760
+ IP_HOST_DELIM_RE.lastIndex = 0;
21761
+ return host.replace(IP_HOST_DELIM_RE, (ch) => IP_HOST_DELIMS[ch])
21701
21762
  }
21702
21763
 
21703
21764
  /**
@@ -21960,9 +22021,10 @@ function requireUtils$1 () {
21960
22021
  *
21961
22022
  * @param {string} input
21962
22023
  * @param {(value: string) => boolean} isAllowed
22024
+ * @param {boolean} [allowNonAscii=false]
21963
22025
  * @returns {string}
21964
22026
  */
21965
- function encodeComponent (input, isAllowed) {
22027
+ function encodeComponent (input, isAllowed, allowNonAscii = false) {
21966
22028
  let output = '';
21967
22029
 
21968
22030
  for (let i = 0; i < input.length; i++) {
@@ -21983,17 +22045,19 @@ function requireUtils$1 () {
21983
22045
  if (code < 0x80) {
21984
22046
  output += BYTE_HEX[code];
21985
22047
  } else if (code < 0xD800 || code > 0xDFFF) {
21986
- output += percentEncodeNonAscii(code);
22048
+ output += allowNonAscii ? ch : percentEncodeNonAscii(code);
21987
22049
  } else if (code <= 0xDBFF && i + 1 < input.length) {
21988
22050
  const low = input.charCodeAt(i + 1);
21989
22051
  if (low >= 0xDC00 && low <= 0xDFFF) {
21990
- output += percentEncodeNonAscii(0x10000 + ((code - 0xD800) << 10) + (low - 0xDC00));
22052
+ output += allowNonAscii
22053
+ ? ch + input[i + 1]
22054
+ : percentEncodeNonAscii(0x10000 + ((code - 0xD800) << 10) + (low - 0xDC00));
21991
22055
  i++;
21992
22056
  } else {
21993
- output += percentEncodeNonAscii(0xFFFD);
22057
+ output += allowNonAscii ? '\uFFFD' : percentEncodeNonAscii(0xFFFD);
21994
22058
  }
21995
22059
  } else {
21996
- output += percentEncodeNonAscii(0xFFFD);
22060
+ output += allowNonAscii ? '\uFFFD' : percentEncodeNonAscii(0xFFFD);
21997
22061
  }
21998
22062
  }
21999
22063
  }
@@ -22107,9 +22171,10 @@ function requireUtils$1 () {
22107
22171
 
22108
22172
  /**
22109
22173
  * @param {import('../types/index').URIComponent} component
22174
+ * @param {boolean} [allowNonAscii=false] - preserve non-ASCII IRI characters
22110
22175
  * @returns {string|undefined}
22111
22176
  */
22112
- function recomposeAuthority (component) {
22177
+ function recomposeAuthority (component, allowNonAscii = false) {
22113
22178
  const uriTokens = [];
22114
22179
 
22115
22180
  if (component.userinfo !== undefined) {
@@ -22142,7 +22207,7 @@ function requireUtils$1 () {
22142
22207
  if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) {
22143
22208
  host = `[${ipV6res.escapedHost}]`;
22144
22209
  } else {
22145
- host = reescapeHostDelimiters(host, false);
22210
+ host = encodeHost(host, false, allowNonAscii);
22146
22211
  }
22147
22212
  }
22148
22213
  }
@@ -22166,7 +22231,7 @@ function requireUtils$1 () {
22166
22231
  nonSimpleDomain,
22167
22232
  nonSimpleMailtoDomain,
22168
22233
  recomposeAuthority,
22169
- reescapeHostDelimiters,
22234
+ encodeHost,
22170
22235
  normalizePercentEncoding,
22171
22236
  normalizePathEncoding,
22172
22237
  serializePathEncoding,
@@ -22176,6 +22241,7 @@ function requireUtils$1 () {
22176
22241
  encodeFragment,
22177
22242
  escapePreservingEscapes,
22178
22243
  removeDotSegments,
22244
+ removeDotSegmentsRelative,
22179
22245
  isIPv4,
22180
22246
  isUUID,
22181
22247
  normalizeIPv6,
@@ -22421,7 +22487,10 @@ function requireSchemes$1 () {
22421
22487
  scheme: 'urn',
22422
22488
  parse: urnParse,
22423
22489
  serialize: urnSerialize,
22424
- skipNormalize: true
22490
+ skipNormalize: true,
22491
+ // The NSS is opaque to generic URI path processing. In particular, RFC 2141
22492
+ // and RFC 8141 do not treat slash-delimited dot segments as equivalent.
22493
+ absolutePath: true
22425
22494
  });
22426
22495
 
22427
22496
  const urnuuid = /** @type {SchemeHandler} */ ({
@@ -22902,22 +22971,30 @@ function requireFastUri$1 () {
22902
22971
  if (hasRequiredFastUri$1) return fastUri$1.exports;
22903
22972
  hasRequiredFastUri$1 = 1;
22904
22973
 
22905
- const { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = requireUtils$1();
22974
+ const { normalizeIPv6, removeDotSegments, removeDotSegmentsRelative, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, encodeHost, isIPv4, nonSimpleDomain } = requireUtils$1();
22906
22975
  const { SCHEMES, getSchemeHandler } = requireSchemes$1();
22907
22976
 
22908
22977
  const VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
22909
22978
  const MALFORMED_SCHEME_ERROR = 'URI scheme is malformed.';
22979
+ const MALFORMED_HOST_ERROR = 'URI host is malformed.';
22980
+ // ASCII characters outside the RFC 3986 reg-name set (unreserved, sub-delims
22981
+ // and "%" for pct-encoded): C0 controls, space, DEL, and "#/:<>?@[\]^`{|}.
22982
+ const FORBIDDEN_DOMAIN_HOST_CHARACTER = /[\0-\x20"#/:<>?@[\\\]^`{|}\x7F]/u;
22910
22983
 
22911
22984
  /**
22985
+ * RFC 3986 section 3.1 does not allow percent-encoding in a scheme, so the
22986
+ * scheme is validated as-is and never decoded. Decoding would let inert input
22987
+ * such as `%6Aavascript:` become a live `javascript:` scheme.
22988
+ *
22912
22989
  * @param {string} scheme
22913
22990
  * @returns {string}
22914
22991
  */
22915
- function decodeValidScheme (scheme) {
22916
- const decodedScheme = unescape(String(scheme));
22917
- if (!VALID_SCHEME.test(decodedScheme)) {
22992
+ function validateScheme (scheme) {
22993
+ const stringScheme = String(scheme);
22994
+ if (!VALID_SCHEME.test(stringScheme)) {
22918
22995
  throw new TypeError(MALFORMED_SCHEME_ERROR)
22919
22996
  }
22920
- return decodedScheme
22997
+ return stringScheme
22921
22998
  }
22922
22999
 
22923
23000
  /**
@@ -22946,6 +23023,7 @@ function requireFastUri$1 () {
22946
23023
  const {
22947
23024
  parsed: baseParsed,
22948
23025
  malformedAuthorityOrPort: baseMalformed,
23026
+ malformedReferenceEdge: baseMalformedReferenceEdge,
22949
23027
  malformedPercentEncoding: baseMalformedPercentEncoding,
22950
23028
  malformedSchemeSpecific: baseMalformedSchemeSpecific,
22951
23029
  malformedHost: baseMalformedHost,
@@ -22954,6 +23032,7 @@ function requireFastUri$1 () {
22954
23032
  const {
22955
23033
  parsed: relativeParsed,
22956
23034
  malformedAuthorityOrPort: relativeMalformed,
23035
+ malformedReferenceEdge: relativeMalformedReferenceEdge,
22957
23036
  malformedPercentEncoding: relativeMalformedPercentEncoding,
22958
23037
  malformedSchemeSpecific: relativeMalformedSchemeSpecific,
22959
23038
  malformedHost: relativeMalformedHost,
@@ -22962,6 +23041,8 @@ function requireFastUri$1 () {
22962
23041
  if (
22963
23042
  baseMalformed ||
22964
23043
  relativeMalformed ||
23044
+ baseMalformedReferenceEdge ||
23045
+ relativeMalformedReferenceEdge ||
22965
23046
  baseMalformedPercentEncoding ||
22966
23047
  relativeMalformedPercentEncoding ||
22967
23048
  baseMalformedSchemeSpecific ||
@@ -22976,8 +23057,22 @@ function requireFastUri$1 () {
22976
23057
  const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
22977
23058
  const resolvedSchemeHandler = getSchemeHandler((options && options.scheme) || resolved.scheme);
22978
23059
  const resolvedHost = resolved.host;
23060
+ // Inputs are parsed scheme-neutrally during resolution, so enforce the final
23061
+ // HTTP scheme's required host before serializing an invalid HTTP URI.
23062
+ if (
23063
+ (resolved.scheme === 'http' || resolved.scheme === 'https') &&
23064
+ !resolvedHost
23065
+ ) {
23066
+ throw new Error('HTTP URIs must have a host.')
23067
+ }
22979
23068
  const resolvedHostIsIP = resolvedHost !== undefined && resolvedHost !== '' &&
22980
23069
  (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
23070
+ // Inputs are parsed scheme-neutrally, so delimiters and controls in a domain
23071
+ // host are only detected here, once the final scheme is known. They always
23072
+ // fail closed, including in percent-encoded hosts.
23073
+ if (hasForbiddenDomainHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP)) {
23074
+ throw new Error(MALFORMED_HOST_ERROR)
23075
+ }
22981
23076
  canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
22982
23077
  // Percent escapes in an ASCII reg-name are encoded data. The WHATWG hostname
22983
23078
  // parser can reject them even though fast-uri preserves them safely as RFC
@@ -22988,6 +23083,9 @@ function requireFastUri$1 () {
22988
23083
  throw new Error(resolved.error)
22989
23084
  }
22990
23085
  schemelessOptions.skipEscape = true;
23086
+ if (resolvedSchemeHandler && resolvedSchemeHandler.absolutePath) {
23087
+ schemelessOptions.absolutePath = true;
23088
+ }
22991
23089
  return serialize(resolved, schemelessOptions)
22992
23090
  }
22993
23091
 
@@ -23029,7 +23127,10 @@ function requireFastUri$1 () {
23029
23127
  target.userinfo = relative.userinfo;
23030
23128
  copyHost(target, relative);
23031
23129
  target.port = relative.port;
23032
- target.path = removeDotSegments(relative.path || '');
23130
+ const relativeSchemeHandler = getSchemeHandler(relative.scheme);
23131
+ target.path = relativeSchemeHandler && relativeSchemeHandler.absolutePath
23132
+ ? relative.path || ''
23133
+ : removeDotSegments(relative.path || '');
23033
23134
  target.query = relative.query;
23034
23135
  } else {
23035
23136
  if (relative.userinfo !== undefined || relative.host !== undefined || relative.port !== undefined) {
@@ -23051,14 +23152,17 @@ function requireFastUri$1 () {
23051
23152
  if (relative.path[0] === '/') {
23052
23153
  target.path = removeDotSegments(relative.path);
23053
23154
  } else {
23054
- if ((base.userinfo !== undefined || base.host !== undefined || base.port !== undefined) && !base.path) {
23155
+ const baseHasAuthority = base.userinfo !== undefined || base.host !== undefined || base.port !== undefined;
23156
+ if (baseHasAuthority && !base.path) {
23055
23157
  target.path = '/' + relative.path;
23056
23158
  } else if (!base.path) {
23057
23159
  target.path = relative.path;
23058
23160
  } else {
23059
23161
  target.path = base.path.slice(0, base.path.lastIndexOf('/') + 1) + relative.path;
23060
23162
  }
23061
- target.path = removeDotSegments(target.path);
23163
+ target.path = base.scheme === undefined && !baseHasAuthority && target.path[0] !== '/'
23164
+ ? removeDotSegmentsRelative(target.path)
23165
+ : removeDotSegments(target.path);
23062
23166
  }
23063
23167
  target.query = relative.query;
23064
23168
  }
@@ -23119,7 +23223,7 @@ function requireFastUri$1 () {
23119
23223
  const uriTokens = [];
23120
23224
 
23121
23225
  if (component.scheme) {
23122
- component.scheme = decodeValidScheme(component.scheme);
23226
+ component.scheme = validateScheme(component.scheme);
23123
23227
  }
23124
23228
 
23125
23229
  // find scheme handler
@@ -23129,7 +23233,11 @@ function requireFastUri$1 () {
23129
23233
  if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
23130
23234
 
23131
23235
  const hasAuthority = component.userinfo !== undefined || component.host !== undefined || component.port !== undefined;
23132
- const pathNoScheme = !options.skipEscape && component.scheme === undefined && !hasAuthority;
23236
+ // A reference with no emitted scheme is path-noscheme: a bare ':' in its
23237
+ // first path segment would reparse as a scheme (RFC 3986 3.3/4.2). Enforced
23238
+ // under skipEscape too (resolve()), so the reapply below gates on this flag.
23239
+ const schemelessReference = (component.scheme === undefined || options.reference === 'suffix') && !hasAuthority;
23240
+ const pathNoScheme = !options.skipEscape && schemelessReference;
23133
23241
 
23134
23242
  if (component.path !== undefined) {
23135
23243
  if (!options.skipEscape) {
@@ -23141,11 +23249,12 @@ function requireFastUri$1 () {
23141
23249
 
23142
23250
  if (options.reference !== 'suffix' && component.scheme) {
23143
23251
  // Scheme handlers may replace the scheme during serialization.
23144
- component.scheme = decodeValidScheme(component.scheme);
23252
+ component.scheme = validateScheme(component.scheme);
23145
23253
  uriTokens.push(component.scheme, ':');
23146
23254
  }
23147
23255
 
23148
- const authority = recomposeAuthority(component);
23256
+ const allowNonAsciiHost = options.unicodeSupport === true || Boolean(schemeHandler && schemeHandler.unicodeSupport);
23257
+ const authority = recomposeAuthority(component, allowNonAsciiHost);
23149
23258
  if (authority !== undefined) {
23150
23259
  if (options.reference !== 'suffix') {
23151
23260
  uriTokens.push('//');
@@ -23161,13 +23270,18 @@ function requireFastUri$1 () {
23161
23270
  let s = component.path;
23162
23271
 
23163
23272
  if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
23164
- s = removeDotSegments(s);
23273
+ // A relative-path reference keeps its unresolvable leading ".." segments
23274
+ // and must never become root-relative (RFC 3986 section 5.2.4 applies to
23275
+ // merged target paths, not to the reference itself).
23276
+ s = schemelessReference && s[0] !== '/'
23277
+ ? removeDotSegmentsRelative(s)
23278
+ : removeDotSegments(s);
23165
23279
  }
23166
23280
 
23167
23281
  // Dot-segment removal can expose a colon that was not originally in the
23168
23282
  // first segment (for example, "./a:b"). Reapply path-noscheme encoding so
23169
23283
  // the serialized relative reference cannot be reparsed as a URI scheme.
23170
- if (pathNoScheme) {
23284
+ if (schemelessReference) {
23171
23285
  s = serializePathEncoding(s, true);
23172
23286
  }
23173
23287
 
@@ -23287,6 +23401,11 @@ function requireFastUri$1 () {
23287
23401
  parsed.host[0] === '[' &&
23288
23402
  parsed.host[parsed.host.length - 1] === ']';
23289
23403
 
23404
+ if (hasForbiddenDomainHost(parsed, options, schemeHandler, isIP)) {
23405
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
23406
+ return true
23407
+ }
23408
+
23290
23409
  if (
23291
23410
  !options.unicodeSupport &&
23292
23411
  (!schemeHandler || !schemeHandler.unicodeSupport) &&
@@ -23297,21 +23416,67 @@ function requireFastUri$1 () {
23297
23416
  !bracketedIPLiteral &&
23298
23417
  nonSimpleDomain(parsed.host)
23299
23418
  ) {
23419
+ let url;
23300
23420
  try {
23301
- parsed.host = new URL('http://' + parsed.host).hostname;
23421
+ url = new URL('http://' + parsed.host);
23302
23422
  } catch (e) {
23303
23423
  parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
23304
23424
  return true
23305
23425
  }
23426
+ // The WHATWG parser must have read the whole input as a host. Anything
23427
+ // else means it found a delimiter fast-uri did not, so its hostname would
23428
+ // describe a different authority.
23429
+ if (!isHostOnlyURL(url)) {
23430
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
23431
+ return true
23432
+ }
23433
+ parsed.host = url.hostname;
23306
23434
  }
23307
23435
 
23308
23436
  return false
23309
23437
  }
23310
23438
 
23439
+ /**
23440
+ * Whether a domain host contains an ASCII character that RFC 3986 does not
23441
+ * allow in a reg-name (unreserved, sub-delims, or pct-encoded). Such a host is
23442
+ * rejected instead of being handed to the WHATWG URL parser, which would treat
23443
+ * "@" as a userinfo delimiter (silently dropping the data before it) and strip
23444
+ * TAB, LF, and CR. Non-ASCII characters remain allowed for IDNs.
23445
+ *
23446
+ * @param {import('./types/index').URIComponent} parsed
23447
+ * @param {import('./types/index').Options} options
23448
+ * @param {{ domainHost?: boolean }|undefined} schemeHandler
23449
+ * @param {boolean} isIP
23450
+ * @returns {boolean}
23451
+ */
23452
+ function hasForbiddenDomainHost (parsed, options, schemeHandler, isIP) {
23453
+ return Boolean(
23454
+ parsed.host &&
23455
+ isIP === false &&
23456
+ !isIPLiteral(parsed.host) &&
23457
+ (options.domainHost || (schemeHandler && schemeHandler.domainHost)) &&
23458
+ FORBIDDEN_DOMAIN_HOST_CHARACTER.test(parsed.host)
23459
+ )
23460
+ }
23461
+
23462
+ /**
23463
+ * @param {URL} url
23464
+ * @returns {boolean}
23465
+ */
23466
+ function isHostOnlyURL (url) {
23467
+ return url.username === '' &&
23468
+ url.password === '' &&
23469
+ url.port === '' &&
23470
+ url.pathname === '/' &&
23471
+ url.search === '' &&
23472
+ url.hash === '' &&
23473
+ url.hostname !== ''
23474
+ }
23475
+
23311
23476
  /**
23312
23477
  * @param {string} uri
23313
23478
  * @param {import('./types/index').Options} [opts]
23314
- * @returns {{ parsed: import('./types/index').URIComponent, malformedAuthorityOrPort: boolean, malformedPercentEncoding: boolean, malformedSchemeSpecific: boolean, malformedHost: boolean, malformedScheme: boolean }}
23479
+ * @returns {{ parsed: import('./types/index').URIComponent, malformedAuthorityOrPort: boolean, malformedReferenceEdge: boolean, malformedPercentEncoding: boolean, malformedSchemeSpecific: boolean, malformedHost: boolean, malformedScheme: boolean }}
23315
23480
  */
23316
23481
  function parseWithStatus (uri, opts) {
23317
23482
  const options = Object.assign({}, opts);
@@ -23327,6 +23492,12 @@ function requireFastUri$1 () {
23327
23492
  };
23328
23493
 
23329
23494
  let malformedAuthorityOrPort = false;
23495
+ // Check the caller's original reference before suffix mode prepends a scheme
23496
+ // or authority marker and turns its leading edge into interior data.
23497
+ const malformedReferenceEdge = uri.length !== 0 && (
23498
+ uri.charCodeAt(0) <= 0x20 ||
23499
+ uri.charCodeAt(uri.length - 1) <= 0x20
23500
+ );
23330
23501
  let malformedPercentEncoding = false;
23331
23502
  let malformedSchemeSpecific = false;
23332
23503
  let malformedHost = false;
@@ -23377,6 +23548,10 @@ function requireFastUri$1 () {
23377
23548
  }
23378
23549
  }
23379
23550
 
23551
+ if (malformedReferenceEdge) {
23552
+ parsed.error = parsed.error || 'URI must not contain leading or trailing C0 controls or spaces.';
23553
+ }
23554
+
23380
23555
  const matches = uri.match(URI_PARSE);
23381
23556
 
23382
23557
  if (matches) {
@@ -23390,9 +23565,8 @@ function requireFastUri$1 () {
23390
23565
  parsed.fragment = matches[8];
23391
23566
 
23392
23567
  if (parsed.scheme !== undefined) {
23393
- const decodedScheme = unescape(parsed.scheme);
23394
- if (VALID_SCHEME.test(decodedScheme)) {
23395
- parsed.scheme = decodedScheme.toLowerCase();
23568
+ if (VALID_SCHEME.test(parsed.scheme)) {
23569
+ parsed.scheme = parsed.scheme.toLowerCase();
23396
23570
  } else {
23397
23571
  parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
23398
23572
  malformedScheme = true;
@@ -23436,7 +23610,7 @@ function requireFastUri$1 () {
23436
23610
  }
23437
23611
 
23438
23612
  if (malformedIPLiteral) {
23439
- parsed.error = parsed.error || 'URI host is malformed.';
23613
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
23440
23614
  malformedAuthorityOrPort = true;
23441
23615
  }
23442
23616
  } else {
@@ -23466,14 +23640,24 @@ function requireFastUri$1 () {
23466
23640
  malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
23467
23641
  }
23468
23642
 
23469
- if (uri.indexOf('%') !== -1 && parsed.host !== undefined && !malformedIPLiteral) {
23470
- let host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
23471
- if (!isIP) {
23643
+ if (parsed.host !== undefined && !malformedIPLiteral) {
23644
+ let host = parsed.host;
23645
+ if (uri.indexOf('%') !== -1 && !isIP) {
23646
+ host = normalizePercentEncoding(host, true);
23472
23647
  // Fold reg-name case after decoding unreserved octets. The second
23473
23648
  // pass only restores uppercase hex in escapes that remain encoded.
23474
23649
  host = normalizePercentEncoding(host.toLowerCase());
23475
23650
  }
23476
- parsed.host = reescapeHostDelimiters(host, isIP);
23651
+ // Resolution parses both inputs with the internal `null` scheme before
23652
+ // the effective scheme is known. Preserve raw host characters for that
23653
+ // intermediate step so the final scheme can apply domain canonicalization;
23654
+ // the resolved authority is encoded when it is serialized.
23655
+ if (options.scheme !== 'null') {
23656
+ const allowNonAsciiHost = options.unicodeSupport === true || Boolean(schemeHandler && schemeHandler.unicodeSupport);
23657
+ parsed.host = encodeHost(host, isIP, allowNonAsciiHost);
23658
+ } else {
23659
+ parsed.host = host;
23660
+ }
23477
23661
  }
23478
23662
 
23479
23663
  if (!schemeHandler || (schemeHandler && !schemeHandler.skipNormalize)) {
@@ -23498,7 +23682,7 @@ function requireFastUri$1 () {
23498
23682
  } else {
23499
23683
  parsed.error = parsed.error || 'URI can not be parsed.';
23500
23684
  }
23501
- return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme }
23685
+ return { parsed, malformedAuthorityOrPort, malformedReferenceEdge, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme }
23502
23686
  }
23503
23687
 
23504
23688
  /**
@@ -23522,13 +23706,14 @@ function requireFastUri$1 () {
23522
23706
  /**
23523
23707
  * @param {string} uri
23524
23708
  * @param {import('./types/index').Options} [opts]
23525
- * @returns {{ normalized: string, malformedAuthorityOrPort: boolean, malformedPercentEncoding: boolean, malformedSchemeSpecific: boolean, malformedHost: boolean, malformedScheme: boolean }}
23709
+ * @returns {{ normalized: string, malformedAuthorityOrPort: boolean, malformedReferenceEdge: boolean, malformedPercentEncoding: boolean, malformedSchemeSpecific: boolean, malformedHost: boolean, malformedScheme: boolean }}
23526
23710
  */
23527
23711
  function normalizeStringWithStatus (uri, opts) {
23528
- const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
23712
+ const { parsed, malformedAuthorityOrPort, malformedReferenceEdge, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
23529
23713
  return {
23530
- normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
23714
+ normalized: malformedAuthorityOrPort || malformedReferenceEdge || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
23531
23715
  malformedAuthorityOrPort,
23716
+ malformedReferenceEdge,
23532
23717
  malformedPercentEncoding,
23533
23718
  malformedSchemeSpecific,
23534
23719
  malformedHost,
@@ -23552,8 +23737,8 @@ function requireFastUri$1 () {
23552
23737
  } catch {
23553
23738
  return undefined
23554
23739
  }
23555
- const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
23556
- return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? undefined : normalized
23740
+ const { normalized, malformedAuthorityOrPort, malformedReferenceEdge, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
23741
+ return malformedAuthorityOrPort || malformedReferenceEdge || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? undefined : normalized
23557
23742
  }
23558
23743
 
23559
23744
  const fastUri = {
@@ -38759,6 +38944,57 @@ function requireUtils () {
38759
38944
  return output.join('')
38760
38945
  }
38761
38946
 
38947
+ /**
38948
+ * Removes dot segments from the path of a relative reference (a path that does
38949
+ * not start with "/") without changing what it resolves to against any base.
38950
+ * Unlike `removeDotSegments`, leading ".." segments that cannot be collapsed
38951
+ * are kept, the result never becomes root-relative, and a result that would be
38952
+ * empty or start with an empty segment is prefixed with "." (an empty path
38953
+ * means "same document" and a leading "//" would introduce an authority).
38954
+ *
38955
+ * @param {string} path
38956
+ * @returns {string}
38957
+ */
38958
+ function removeDotSegmentsRelative (path) {
38959
+ if (path === '' || path[0] === '/') {
38960
+ return removeDotSegments(path)
38961
+ }
38962
+
38963
+ const segments = path.split('/');
38964
+ const last = segments.length - 1;
38965
+ /** @type {string[]} */
38966
+ const output = [];
38967
+ let trailingDirectory = false;
38968
+
38969
+ for (let i = 0; i <= last; i++) {
38970
+ const segment = segments[i];
38971
+ if (segment === '.' || segment === '..') {
38972
+ if (segment === '..') {
38973
+ if (output.length !== 0 && output[output.length - 1] !== '..') {
38974
+ output.pop();
38975
+ } else {
38976
+ output.push('..');
38977
+ }
38978
+ }
38979
+ trailingDirectory = i === last;
38980
+ } else {
38981
+ output.push(segment);
38982
+ }
38983
+ }
38984
+
38985
+ if (trailingDirectory && output[output.length - 1] !== '..') {
38986
+ output.push('');
38987
+ }
38988
+ if (output.length === 0 || output[0] === '' || output[0].includes(':')) {
38989
+ // An empty path, a leading empty segment ("//"), or a first segment
38990
+ // containing ":" (which would be mistaken for a scheme, RFC 3986 section
38991
+ // 4.2) must stay behind a "." segment so the reference keeps its meaning.
38992
+ output.unshift('.');
38993
+ }
38994
+
38995
+ return output.join('/')
38996
+ }
38997
+
38762
38998
  /**
38763
38999
  * Re-escape RFC 3986 gen-delims that must not appear literally in the host.
38764
39000
  * After the URI regex parses, these characters cannot be literal in the host
@@ -39153,6 +39389,7 @@ function requireUtils () {
39153
39389
  encodeFragment,
39154
39390
  escapePreservingEscapes,
39155
39391
  removeDotSegments,
39392
+ removeDotSegmentsRelative,
39156
39393
  isIPv4,
39157
39394
  isUUID,
39158
39395
  normalizeIPv6,
@@ -39447,22 +39684,30 @@ function requireFastUri () {
39447
39684
  if (hasRequiredFastUri) return fastUri.exports;
39448
39685
  hasRequiredFastUri = 1;
39449
39686
 
39450
- const { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = requireUtils();
39687
+ const { normalizeIPv6, removeDotSegments, removeDotSegmentsRelative, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = requireUtils();
39451
39688
  const { SCHEMES, getSchemeHandler } = requireSchemes();
39452
39689
 
39453
39690
  const VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
39454
39691
  const MALFORMED_SCHEME_ERROR = 'URI scheme is malformed.';
39692
+ const MALFORMED_HOST_ERROR = 'URI host is malformed.';
39693
+ // ASCII characters outside the RFC 3986 reg-name set (unreserved, sub-delims
39694
+ // and "%" for pct-encoded): C0 controls, space, DEL, and "#/:<>?@[\]^`{|}.
39695
+ const FORBIDDEN_DOMAIN_HOST_CHARACTER = /[\0-\x20"#/:<>?@[\\\]^`{|}\x7F]/u;
39455
39696
 
39456
39697
  /**
39698
+ * RFC 3986 section 3.1 does not allow percent-encoding in a scheme, so the
39699
+ * scheme is validated as-is and never decoded. Decoding would let inert input
39700
+ * such as `%6Aavascript:` become a live `javascript:` scheme.
39701
+ *
39457
39702
  * @param {string} scheme
39458
39703
  * @returns {string}
39459
39704
  */
39460
- function decodeValidScheme (scheme) {
39461
- const decodedScheme = unescape(String(scheme));
39462
- if (!VALID_SCHEME.test(decodedScheme)) {
39705
+ function validateScheme (scheme) {
39706
+ const stringScheme = String(scheme);
39707
+ if (!VALID_SCHEME.test(stringScheme)) {
39463
39708
  throw new TypeError(MALFORMED_SCHEME_ERROR)
39464
39709
  }
39465
- return decodedScheme
39710
+ return stringScheme
39466
39711
  }
39467
39712
 
39468
39713
  /**
@@ -39523,6 +39768,12 @@ function requireFastUri () {
39523
39768
  const resolvedHost = resolved.host;
39524
39769
  const resolvedHostIsIP = resolvedHost !== undefined && resolvedHost !== '' &&
39525
39770
  (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
39771
+ // Inputs are parsed scheme-neutrally, so delimiters and controls in a domain
39772
+ // host are only detected here, once the final scheme is known. They always
39773
+ // fail closed, including in percent-encoded hosts.
39774
+ if (hasForbiddenDomainHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP)) {
39775
+ throw new Error(MALFORMED_HOST_ERROR)
39776
+ }
39526
39777
  canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
39527
39778
  // Percent escapes in an ASCII reg-name are encoded data. The WHATWG hostname
39528
39779
  // parser can reject them even though fast-uri preserves them safely as RFC
@@ -39580,14 +39831,17 @@ function requireFastUri () {
39580
39831
  if (relative.path[0] === '/') {
39581
39832
  target.path = removeDotSegments(relative.path);
39582
39833
  } else {
39583
- if ((base.userinfo !== undefined || base.host !== undefined || base.port !== undefined) && !base.path) {
39834
+ const baseHasAuthority = base.userinfo !== undefined || base.host !== undefined || base.port !== undefined;
39835
+ if (baseHasAuthority && !base.path) {
39584
39836
  target.path = '/' + relative.path;
39585
39837
  } else if (!base.path) {
39586
39838
  target.path = relative.path;
39587
39839
  } else {
39588
39840
  target.path = base.path.slice(0, base.path.lastIndexOf('/') + 1) + relative.path;
39589
39841
  }
39590
- target.path = removeDotSegments(target.path);
39842
+ target.path = base.scheme === undefined && !baseHasAuthority && target.path[0] !== '/'
39843
+ ? removeDotSegmentsRelative(target.path)
39844
+ : removeDotSegments(target.path);
39591
39845
  }
39592
39846
  target.query = relative.query;
39593
39847
  }
@@ -39643,7 +39897,7 @@ function requireFastUri () {
39643
39897
  const uriTokens = [];
39644
39898
 
39645
39899
  if (component.scheme) {
39646
- component.scheme = decodeValidScheme(component.scheme);
39900
+ component.scheme = validateScheme(component.scheme);
39647
39901
  }
39648
39902
 
39649
39903
  // find scheme handler
@@ -39653,7 +39907,11 @@ function requireFastUri () {
39653
39907
  if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
39654
39908
 
39655
39909
  const hasAuthority = component.userinfo !== undefined || component.host !== undefined || component.port !== undefined;
39656
- const pathNoScheme = !options.skipEscape && component.scheme === undefined && !hasAuthority;
39910
+ // A reference with no emitted scheme is path-noscheme: a bare ':' in its
39911
+ // first path segment would reparse as a scheme (RFC 3986 3.3/4.2). Enforced
39912
+ // under skipEscape too (resolve()), so the reapply below gates on this flag.
39913
+ const schemelessReference = (component.scheme === undefined || options.reference === 'suffix') && !hasAuthority;
39914
+ const pathNoScheme = !options.skipEscape && schemelessReference;
39657
39915
 
39658
39916
  if (component.path !== undefined) {
39659
39917
  if (!options.skipEscape) {
@@ -39665,7 +39923,7 @@ function requireFastUri () {
39665
39923
 
39666
39924
  if (options.reference !== 'suffix' && component.scheme) {
39667
39925
  // Scheme handlers may replace the scheme during serialization.
39668
- component.scheme = decodeValidScheme(component.scheme);
39926
+ component.scheme = validateScheme(component.scheme);
39669
39927
  uriTokens.push(component.scheme, ':');
39670
39928
  }
39671
39929
 
@@ -39685,13 +39943,18 @@ function requireFastUri () {
39685
39943
  let s = component.path;
39686
39944
 
39687
39945
  if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
39688
- s = removeDotSegments(s);
39946
+ // A relative-path reference keeps its unresolvable leading ".." segments
39947
+ // and must never become root-relative (RFC 3986 section 5.2.4 applies to
39948
+ // merged target paths, not to the reference itself).
39949
+ s = schemelessReference && s[0] !== '/'
39950
+ ? removeDotSegmentsRelative(s)
39951
+ : removeDotSegments(s);
39689
39952
  }
39690
39953
 
39691
39954
  // Dot-segment removal can expose a colon that was not originally in the
39692
39955
  // first segment (for example, "./a:b"). Reapply path-noscheme encoding so
39693
39956
  // the serialized relative reference cannot be reparsed as a URI scheme.
39694
- if (pathNoScheme) {
39957
+ if (schemelessReference) {
39695
39958
  s = serializePathEncoding(s, true);
39696
39959
  }
39697
39960
 
@@ -39806,6 +40069,11 @@ function requireFastUri () {
39806
40069
  * @returns {boolean} whether host conversion failed
39807
40070
  */
39808
40071
  function canonicalizeHost (parsed, options, schemeHandler, isIP) {
40072
+ if (hasForbiddenDomainHost(parsed, options, schemeHandler, isIP)) {
40073
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
40074
+ return true
40075
+ }
40076
+
39809
40077
  if (
39810
40078
  !options.unicodeSupport &&
39811
40079
  (!schemeHandler || !schemeHandler.unicodeSupport) &&
@@ -39815,16 +40083,62 @@ function requireFastUri () {
39815
40083
  isIP === false &&
39816
40084
  nonSimpleDomain(parsed.host)
39817
40085
  ) {
40086
+ let url;
39818
40087
  try {
39819
- parsed.host = new URL('http://' + parsed.host).hostname;
40088
+ url = new URL('http://' + parsed.host);
39820
40089
  } catch (e) {
39821
40090
  parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
39822
40091
  return true
39823
40092
  }
40093
+ // The WHATWG parser must have read the whole input as a host. Anything
40094
+ // else means it found a delimiter fast-uri did not, so its hostname would
40095
+ // describe a different authority.
40096
+ if (!isHostOnlyURL(url)) {
40097
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
40098
+ return true
40099
+ }
40100
+ parsed.host = url.hostname;
39824
40101
  }
39825
40102
  return false
39826
40103
  }
39827
40104
 
40105
+ /**
40106
+ * Whether a domain host contains an ASCII character that RFC 3986 does not
40107
+ * allow in a reg-name (unreserved, sub-delims, or pct-encoded). Such a host is
40108
+ * rejected instead of being handed to the WHATWG URL parser, which would treat
40109
+ * "@" as a userinfo delimiter (silently dropping the data before it) and strip
40110
+ * TAB, LF, and CR. Non-ASCII characters remain allowed for IDNs.
40111
+ *
40112
+ * @param {import('./types/index').URIComponent} parsed
40113
+ * @param {import('./types/index').Options} options
40114
+ * @param {{ domainHost?: boolean }|undefined} schemeHandler
40115
+ * @param {boolean} isIP
40116
+ * @returns {boolean}
40117
+ */
40118
+ function hasForbiddenDomainHost (parsed, options, schemeHandler, isIP) {
40119
+ return Boolean(
40120
+ parsed.host &&
40121
+ isIP === false &&
40122
+ !isIPLiteral(parsed.host) &&
40123
+ (options.domainHost || (schemeHandler && schemeHandler.domainHost)) &&
40124
+ FORBIDDEN_DOMAIN_HOST_CHARACTER.test(parsed.host)
40125
+ )
40126
+ }
40127
+
40128
+ /**
40129
+ * @param {URL} url
40130
+ * @returns {boolean}
40131
+ */
40132
+ function isHostOnlyURL (url) {
40133
+ return url.username === '' &&
40134
+ url.password === '' &&
40135
+ url.port === '' &&
40136
+ url.pathname === '/' &&
40137
+ url.search === '' &&
40138
+ url.hash === '' &&
40139
+ url.hostname !== ''
40140
+ }
40141
+
39828
40142
  /**
39829
40143
  * @param {string} uri
39830
40144
  * @param {import('./types/index').Options} [opts]
@@ -39907,9 +40221,8 @@ function requireFastUri () {
39907
40221
  parsed.fragment = matches[8];
39908
40222
 
39909
40223
  if (parsed.scheme !== undefined) {
39910
- const decodedScheme = unescape(parsed.scheme);
39911
- if (VALID_SCHEME.test(decodedScheme)) {
39912
- parsed.scheme = decodedScheme.toLowerCase();
40224
+ if (VALID_SCHEME.test(parsed.scheme)) {
40225
+ parsed.scheme = parsed.scheme.toLowerCase();
39913
40226
  } else {
39914
40227
  parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
39915
40228
  malformedScheme = true;
@@ -39943,7 +40256,7 @@ function requireFastUri () {
39943
40256
  parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
39944
40257
 
39945
40258
  if (malformedIPLiteral) {
39946
- parsed.error = parsed.error || 'URI host is malformed.';
40259
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
39947
40260
  malformedAuthorityOrPort = true;
39948
40261
  }
39949
40262
  } else {
@@ -39980,7 +40293,11 @@ function requireFastUri () {
39980
40293
  // pass only restores uppercase hex in escapes that remain encoded.
39981
40294
  host = normalizePercentEncoding(host.toLowerCase());
39982
40295
  }
39983
- parsed.host = reescapeHostDelimiters(host, isIP);
40296
+ // Resolution parses both inputs with the internal `null` scheme before
40297
+ // the effective scheme is known. Keep raw host delimiters for that step
40298
+ // so resolve() can reject them for domain-host schemes; the resolved
40299
+ // authority is encoded when it is serialized.
40300
+ parsed.host = isIP || options.scheme !== 'null' ? reescapeHostDelimiters(host, isIP) : host;
39984
40301
  }
39985
40302
 
39986
40303
  if (!schemeHandler || (schemeHandler && !schemeHandler.skipNormalize)) {
@@ -44312,7 +44629,7 @@ class ArrayFieldTemplate extends React.Component {
44312
44629
  render() {
44313
44630
  const orderedItems = this.getOrderedItems();
44314
44631
  const contextValue = this.getContextValue();
44315
- return React.createElement(ArrayFieldContext.Provider, { value: contextValue }, React.createElement('div', {}, renderTitle(this.props.title), renderDescription(this.props.schema.description), React.createElement('div', {
44632
+ return React.createElement(ArrayFieldContext.Provider, { value: contextValue }, React.createElement('div', {}, renderTitle(this.props.title), getHelpComponent(this.props.schema), renderDescription(this.props.schema.description), React.createElement('div', {
44316
44633
  className: 'array-items',
44317
44634
  ref: this.setContainer,
44318
44635
  }, orderedItems), this.renderAddButton()));