Comparing version
@@ -5,3 +5,3 @@ { | ||
"homepage": "https://github.com/Kikobeats/parse-uri", | ||
"version": "1.0.13", | ||
"version": "1.0.14", | ||
"main": "src/index.js", | ||
@@ -30,2 +30,3 @@ "author": { | ||
"ava": "latest", | ||
"benchmark": "latest", | ||
"c8": "latest", | ||
@@ -37,2 +38,3 @@ "ci-publish": "latest", | ||
"nano-staged": "latest", | ||
"parseuri": "latest", | ||
"simple-git-hooks": "latest", | ||
@@ -50,2 +52,3 @@ "standard": "latest", | ||
"scripts": { | ||
"benchmark": "node benchmark/index.js", | ||
"clean": "rm -rf node_modules", | ||
@@ -52,0 +55,0 @@ "contributors": "(npx git-authors-cli && npx finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true", |
@@ -38,2 +38,27 @@ # parse-uri | ||
### Benchmark | ||
Compared vs `parseuri`: | ||
``` | ||
============================================================ | ||
simple | parse-uri is 3302.0% faster | ||
basic | parse-uri is 1370.8% faster | ||
complex | parse-uri is 967.7% faster | ||
mailto | parse-uri is 1493.3% faster | ||
tel | parse-uri is 3296.8% faster | ||
ftp | parse-uri is 1641.9% faster | ||
file | parse-uri is 3305.7% faster | ||
data | parse-uri is 3030.4% faster | ||
javascript | parse-uri is 2992.0% faster | ||
custom | parse-uri is 1196.0% faster | ||
longUrl | parse-uri is 547.1% faster | ||
unicodeUrl | parse-uri is 1005.6% faster | ||
============================================================ | ||
🏆 Overall Winner: parse-uri (2058.1% faster on average) | ||
``` | ||
See more numbers at [benchmark](/benchmark/README.md). | ||
### Related | ||
@@ -40,0 +65,0 @@ |
113
src/index.js
@@ -6,19 +6,10 @@ 'use strict' | ||
const queryParser = /(?:^|&)([^&=]*)=?([^&]*)/g | ||
const patterns = { | ||
// Captures: protocol, authority, path, query, fragment | ||
// Updated to handle schemes without '//' like mailto:, tel:, etc. | ||
strict: | ||
/^(?:([^:/?#]+):)?(?:\/\/([^/?#]*)|([^?#]*?))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/, | ||
// Loose pattern updated to handle mailto and similar schemes | ||
loose: | ||
/^(?:([^:/?#.]+):)?(?:\/\/([^/?#]*)|([^?#]*?))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/ | ||
} | ||
// Single regex pattern - handles both strict and loose modes | ||
const pattern = opts.strictMode | ||
? /^(?:([^:/?#]+):)?(?:\/\/([^/?#]*)|([^?#]*?))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/ | ||
: /^(?:([^:/?#.]+):)?(?:\/\/([^/?#]*)|([^?#]*?))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/ | ||
const pattern = opts.strictMode ? patterns.strict : patterns.loose | ||
const matches = pattern.exec(str) | ||
if (!matches) return undefined | ||
// Destructure regex matches for clarity | ||
// Note: matches[2] is authority (with //), matches[3] is scheme-specific part (without //) | ||
const [ | ||
@@ -29,3 +20,3 @@ , | ||
schemePart = '', | ||
relative = '', | ||
path = '', | ||
query = '', | ||
@@ -35,56 +26,50 @@ anchor = '' | ||
// For schemes like mailto:, the email goes in schemePart, not authority | ||
const actualAuthority = authority || '' | ||
const actualRelative = authority ? relative : schemePart + relative | ||
const actualPath = authority ? path : schemePart + path | ||
const pathname = authority | ||
? actualPath.startsWith('/') | ||
? actualPath | ||
: actualPath | ||
? `/${actualPath}` | ||
: '/' | ||
: actualPath | ||
// Initialize all URI components | ||
const uri = { | ||
source: str, | ||
protocol, | ||
authority: actualAuthority, | ||
relative: actualRelative, | ||
query, | ||
anchor, | ||
userInfo: '', | ||
user: '', | ||
password: '', | ||
host: '', | ||
port: '', | ||
path: actualRelative, | ||
directory: '', | ||
file: '', | ||
queryKey: {} | ||
} | ||
// Parse authority components | ||
const authMatch = authority | ||
? /^(?:(([^:@]*)(?::([^:@]*))?)?@)?([^:/?#]*)(?::(\d*))?/.exec(authority) | ||
: null | ||
const [ | ||
, | ||
userInfo = '', | ||
username = '', | ||
password = '', | ||
hostname = '', | ||
rawPort = '' | ||
] = authMatch || [] | ||
// Parse authority into user info, host, and port | ||
if (actualAuthority) { | ||
const authorityPattern = | ||
/^(?:(([^:@]*)(?::([^:@]*))?)?@)?([^:/?#]*)(?::(\d*))?/ | ||
const authorityMatches = authorityPattern.exec(actualAuthority) | ||
if (authorityMatches) { | ||
const [, userInfo = '', user = '', password = '', host = '', port = ''] = | ||
authorityMatches | ||
Object.assign(uri, { userInfo, user, password, host, port }) | ||
} | ||
} | ||
// Handle default ports and build components | ||
const port = | ||
(rawPort === '80' && protocol === 'http') || | ||
(rawPort === '443' && protocol === 'https') | ||
? '' | ||
: rawPort | ||
const host = port ? `${hostname}:${port}` : hostname | ||
const origin = | ||
protocol === 'http' || protocol === 'https' ? `${protocol}://${host}` : '' | ||
// Parse the relative part into directory and file | ||
if (actualRelative) { | ||
const lastSlashIndex = actualRelative.lastIndexOf('/') | ||
if (lastSlashIndex > -1) { | ||
uri.directory = actualRelative.substring(0, lastSlashIndex + 1) | ||
uri.file = actualRelative.substring(lastSlashIndex + 1) | ||
} else { | ||
uri.file = actualRelative | ||
} | ||
return { | ||
href: str, | ||
protocol: protocol ? `${protocol}:` : '', | ||
authority, | ||
search: query ? `?${query}` : '', | ||
hash: anchor ? `#${anchor}` : '', | ||
userInfo, | ||
username, | ||
password, | ||
host, | ||
hostname, | ||
port, | ||
pathname, | ||
searchParams: new URLSearchParams(query), | ||
origin | ||
} | ||
// Parse query parameters | ||
if (query) { | ||
for (const [, key, value] of query.matchAll(queryParser)) { | ||
if (key) uri.queryKey[key] = value | ||
} | ||
} | ||
return uri | ||
} |
6976
2.8%70
55.56%16
14.29%64
-16.88%