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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
// Socket Community Patch: https://socket.dev
// Date: Thu, 30 Jul 2026 15:28:49 GMT
// For more information see https://socket.dev/patch/d4e48cf5-361c-49ba-a4a3-810f58bc94f6
// This file includes modifications made by Socket, Inc. on Thu, 30 Jul 2026; these modifications are called the "Patch". In some cases, Socket may be required to make the Patch available to you under specific terms, or may be prohibited from restricting certain rights you may have. For example, the terms of another applicable license may require Socket to make the Patch available under specific terms. In those cases, the Patch is made available to you under the required terms, and Socket does not seek to restrict your rights relative to the Patch where prohibited. In all other cases, the Patch is available to you exclusively under the PolyForm Shield License 1.0.0 (https://polyformproject.org/licenses/shield/1.0.0/). The Patch was distributed by Socket with additional information concerning licensing, attribution, and limitation of liability which may be relevant to you and your use of the Patch. As far as the law allows, the Patch and the software including the patch come as is, without any warranty or condition, and Socket will not be liable to you for any damages arising out of the applicable license terms or the use or nature of the Patch or the software including the patch, under any kind of legal claim.

'use strict'

const { normalizeIPv6, normalizeIPv4, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes } = require('./lib/utils')
const SCHEMES = require('./lib/schemes')

function normalize (uri, options) {
if (typeof uri === 'string') {
uri = serialize(parse(uri, options), options)
} else if (typeof uri === 'object') {
uri = parse(serialize(uri, options), options)
}
return uri
}

function resolve (baseURI, relativeURI, options) {
const schemelessOptions = Object.assign({ scheme: 'null' }, options)
const resolved = resolveComponents(parse(baseURI, schemelessOptions), parse(relativeURI, schemelessOptions), schemelessOptions, true)
return serialize(resolved, { ...schemelessOptions, skipEscape: true })
}

function resolveComponents (base, relative, options, skipNormalization) {
const target = {}
if (!skipNormalization) {
base = parse(serialize(base, options), options) // normalize base components
relative = parse(serialize(relative, options), options) // normalize relative components
}
options = options || {}

if (!options.tolerant && relative.scheme) {
target.scheme = relative.scheme
// target.authority = relative.authority;
target.userinfo = relative.userinfo
target.host = relative.host
target.port = relative.port
target.path = removeDotSegments(relative.path || '')
target.query = relative.query
} else {
if (relative.userinfo !== undefined || relative.host !== undefined || relative.port !== undefined) {
// target.authority = relative.authority;
target.userinfo = relative.userinfo
target.host = relative.host
target.port = relative.port
target.path = removeDotSegments(relative.path || '')
target.query = relative.query
} else {
if (!relative.path) {
target.path = base.path
if (relative.query !== undefined) {
target.query = relative.query
} else {
target.query = base.query
}
} else {
if (relative.path.charAt(0) === '/') {
target.path = removeDotSegments(relative.path)
} else {
if ((base.userinfo !== undefined || base.host !== undefined || base.port !== undefined) && !base.path) {
target.path = '/' + relative.path
} else if (!base.path) {
target.path = relative.path
} else {
target.path = base.path.slice(0, base.path.lastIndexOf('/') + 1) + relative.path
}
target.path = removeDotSegments(target.path)
}
target.query = relative.query
}
// target.authority = base.authority;
target.userinfo = base.userinfo
target.host = base.host
target.port = base.port
}
target.scheme = base.scheme
}

target.fragment = relative.fragment

return target
}

function equal (uriA, uriB, options) {
if (typeof uriA === 'string') {
uriA = serialize(parse(uriA, options), options)
} else if (typeof uriA === 'object') {
uriA = serialize(uriA, options)
}

if (typeof uriB === 'string') {
uriB = serialize(parse(uriB, options), options)
} else if (typeof uriB === 'object') {
uriB = serialize(uriB, options)
}

return uriA.toLowerCase() === uriB.toLowerCase()
}

function serialize (cmpts, opts) {
const components = {
host: cmpts.host,
scheme: cmpts.scheme,
userinfo: cmpts.userinfo,
port: cmpts.port,
path: cmpts.path,
query: cmpts.query,
nid: cmpts.nid,
nss: cmpts.nss,
uuid: cmpts.uuid,
fragment: cmpts.fragment,
reference: cmpts.reference,
resourceName: cmpts.resourceName,
secure: cmpts.secure,
error: ''
}
const options = Object.assign({}, opts)
const uriTokens = []

// find scheme handler
const schemeHandler = SCHEMES[(options.scheme || components.scheme || '').toLowerCase()]

// perform scheme specific serialization
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(components, options)

if (components.path !== undefined) {
if (!options.skipEscape) {
components.path = escapePreservingEscapes(components.path)

if (components.scheme !== undefined) {
components.path = components.path.split('%3A').join(':')
}
} else {
components.path = normalizePercentEncoding(components.path)
}
}

if (options.reference !== 'suffix' && components.scheme) {
uriTokens.push(components.scheme, ':')
}

const authority = recomposeAuthority(components)
if (authority !== undefined) {
if (options.reference !== 'suffix') {
uriTokens.push('//')
}

uriTokens.push(authority)

if (components.path && components.path.charAt(0) !== '/') {
uriTokens.push('/')
}
}
if (components.path !== undefined) {
let s = components.path

if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
s = removeDotSegments(s)
}

if (authority === undefined) {
s = s.replace(/^\/\//u, '/%2F') // don't allow the path to start with "//"
}

uriTokens.push(s)
}

if (components.query !== undefined) {
uriTokens.push('?', components.query)
}

if (components.fragment !== undefined) {
uriTokens.push('#', components.fragment)
}
return uriTokens.join('')
}

const hexLookUp = Array.from({ length: 127 }, (_v, k) => /[^!"$&'()*+,\-.;=_`a-z{}~]/u.test(String.fromCharCode(k)))

function nonSimpleDomain (value) {
let code = 0
for (let i = 0, len = value.length; i < len; ++i) {
code = value.charCodeAt(i)
if (code > 126 || hexLookUp[code]) {
return true
}
}
return false
}

const URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u

function parse (uri, opts) {
const options = Object.assign({}, opts)
const parsed = {
scheme: undefined,
userinfo: undefined,
host: '',
port: undefined,
path: '',
query: undefined,
fragment: undefined
}
const gotEncoding = uri.indexOf('%') !== -1
let isIP = false
if (options.reference === 'suffix') uri = (options.scheme ? options.scheme + ':' : '') + '//' + uri

const matches = uri.match(URI_PARSE)

if (matches) {
// store each component
parsed.scheme = matches[1]
parsed.userinfo = matches[3]
parsed.host = matches[4]
parsed.port = parseInt(matches[5], 10)
parsed.path = matches[6] || ''
parsed.query = matches[7]
parsed.fragment = matches[8]

// fix port number
if (isNaN(parsed.port)) {
parsed.port = matches[5]
}
if (parsed.host) {
const ipv4result = normalizeIPv4(parsed.host)
if (ipv4result.isIPV4 === false) {
const ipv6result = normalizeIPv6(ipv4result.host)
parsed.host = ipv6result.host.toLowerCase()
isIP = ipv6result.isIPV6
} else {
parsed.host = ipv4result.host
isIP = true
}
}
if (parsed.scheme === undefined && parsed.userinfo === undefined && parsed.host === undefined && parsed.port === undefined && parsed.query === undefined && !parsed.path) {
parsed.reference = 'same-document'
} else if (parsed.scheme === undefined) {
parsed.reference = 'relative'
} else if (parsed.fragment === undefined) {
parsed.reference = 'absolute'
} else {
parsed.reference = 'uri'
}

// check for reference errors
if (options.reference && options.reference !== 'suffix' && options.reference !== parsed.reference) {
parsed.error = parsed.error || 'URI is not a ' + options.reference + ' reference.'
}

// find scheme handler
const schemeHandler = SCHEMES[(options.scheme || parsed.scheme || '').toLowerCase()]

// check if scheme can't handle IRIs
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
// if host component is a domain name
if (parsed.host && (options.domainHost || (schemeHandler && schemeHandler.domainHost)) && isIP === false && nonSimpleDomain(parsed.host)) {
// convert Unicode IDN -> ASCII IDN
try {
parsed.host = URL.domainToASCII(parsed.host.toLowerCase())
} catch (e) {
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e
}
}
// convert IRI -> URI
}

if (!schemeHandler || (schemeHandler && !schemeHandler.skipNormalize)) {
if (gotEncoding && parsed.scheme !== undefined) {
parsed.scheme = unescape(parsed.scheme)
}
if (gotEncoding && parsed.host !== undefined) {
parsed.host = unescape(parsed.host)
}
if (parsed.path) {
parsed.path = normalizePathEncoding(parsed.path)
}
if (parsed.fragment) {
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment))
}
}

// perform scheme specific parsing
if (schemeHandler && schemeHandler.parse) {
schemeHandler.parse(parsed, options)
}
} else {
parsed.error = parsed.error || 'URI can not be parsed.'
}
return parsed
}

const fastUri = {
SCHEMES,
normalize,
resolve,
resolveComponents,
equal,
serialize,
parse
}

module.exports = fastUri
module.exports.default = fastUri
module.exports.fastUri = fastUri
Loading
Loading