URL utils for humans.
Install using npm or your favourite package manager:
npm i ufo
Import:
// CommonJS
const { normalizeURL, joinURL } = require('ufo')
// ESM
import { normalizeURL, joinURL } from 'ufo'
// Deno
import { parseURL } from 'https://unpkg.com/ufo/dist/index.mjs'
Notice: You may need to transpile package and add URL polyfill for legacy environments
- Ensures URL is properly encoded
- Ensures pathname starts with slash
- Preserves protocol/host if provided
normalizeURL('test?query=123 123#hash, test')
// test?query=123%20123#hash,%20test
normalizeURL('https://localhost:3000')
// https://localhost:3000/
joinURL('a', '/b', '/c')
// a/b/c
resolveURL('https://foo.com/foo?test=123#token', 'bar', 'baz')
// https://foo.com/foo/bar/baz?test=123#token
parseURL('https://foo.com/foo?test=123#token')
// { protocol: 'http:', auth: '', host: 'foo.com', pathname: '/foo', search: '?test=123', hash: '#token' }
parseURL('foo.com/foo?test=123#token')
// { pathname: 'foo.com/foo', search: '?test=123', hash: '#token' }
parseURL('foo.com/foo?test=123#token', 'https://')
// { protocol: 'https:', auth: '', host: 'foo.com', pathname: '/foo', search: '?test=123', hash: '#token' }
const obj = parseURL('https://foo.com/foo?test=123#token')
obj.host = 'bar.com'
stringifyParsedURL(obj)
// https://bar.com/foo?test=123#token
withQuery('/foo?page=a', { token: 'secret' })
// /foo?page=a&token=secret
getQuery('https://foo.com/foo?test=123&unicode=%E5%A5%BD')
// { test: '123', unicode: 'ε₯½' }
// Result: filename.ext
parseFilename('https://example.com/path/to/filename.ext')
// Result: undefined
parseFilename('/path/to/.hidden-file', { strict: true })
Implementing URL interface with improvements:
- Supporting schemeless and hostless URLs
- Supporting relative URLs
- Preserving trailing-slash status
- Decoded and mutable class properties (
protocol
,host
,auth
,pathname
,query
,hash
) - Consistent URL parser independent of environment
- Consistent encoding independent of environment
- Punycode support for host encoding
new $URL('https://localhost:3000/hello?world=true')
// { protocol: 'http:', host: 'localhost:3000', auth: '', pathname: '/hello', query: { world: 'true' }, hash: '' }
Ensures url ends with a trailing slash.
withTrailingSlash('/foo')
// /foo/
Set the second option to true
to support query parameters:
withTrailingSlash('/path?query=true', true)
// /path/?query=true
Ensures url does not ends with a trailing slash.
withoutTrailingSlash('/foo/')
// /foo
Set the second option to true
to support query parameters:
withoutTrailingSlash('/path/?query=true', true)
// /path?query=true
Ensures url does not have double slash (except for protocol).
cleanDoubleSlashes('//foo//bar//')
// /foo/bar/
cleanDoubleSlashes('https://example.com/analyze//https://localhost:3000//')
// https://example.com/analyze/https://localhost:3000/
Check two paths are equal or not. Trailing slash and encoding are normalized before comparison.
isSamePath('/foo', '/foo/')
// true
Check if a path starts with ./
or ../
.
isRelative('./foo')
// true
Ensures url protocol is http
withHttp('https://example.com')
// https://example.com
Ensures url protocol is https
withHttps('https://example.com')
// https://example.com
Changes url protocol passed as second argument
withProtocol('https://example.com', 'ftp:https://')
// ftp:https://example.com
Removes url protocol
withoutProtocol('https://example.com')
// example.com
Compare two URLs regardless of their slash condition or encoding:
isEqual('/foo', 'foo')
// true
isEqual('foo/', 'foo')
// true
isEqual('/foo bar', '/foo%20bar')
// true
// Strict compare
isEqual('/foo', 'foo', { leadingSlash: true })
// false
isEqual('foo/', 'foo', { trailingSlash: true })
// false
isEqual('/foo bar', '/foo%20bar', { encoding: true })
// false
Special thanks to Eduardo San Martin Morote (posva) for encoding utilities