Skip to content

Instantly share code, notes, and snippets.

@harm-smits
Last active October 12, 2020 12:24
Show Gist options
  • Save harm-smits/208ccf3ea8d4a956fd71cfed73eb402d to your computer and use it in GitHub Desktop.
Save harm-smits/208ccf3ea8d4a956fd71cfed73eb402d to your computer and use it in GitHub Desktop.
Simple url function to add / remove components of a url dynamically
const URL_REGEX = /^(?:([^:\/?#]+):\/\/)?((?:([^\/?#@]*)@)?([^\/?#:]*)(?:\:(\d*))?)?([^?#]*)(?:\?([^#]*))?(?:#((?:.|\n)*))?/i
/**
* Map search parameters to an according associative array
* @param search
* @returns {{}}
*/
function mapSearchParams(search) {
let map = {}
if (typeof search === 'string') {
search.split('&').forEach(values => {
values = values.split('=')
if (map.hasOwnProperty(values[0])) {
map[values[0]] = Array.isArray(map[values[0]]) ? map[values[0]] : [map[values[0]]]
map[values[0]].push(decodeURIComponent(values[1]))
} else {
map[values[0]] = decodeURIComponent(values[1])
}
})
return map
}
}
/**
* A URL managing function
* @param rawUrl
*/
export function url(rawUrl = null) {
let _parsed = {},
_url = null;
if (rawUrl)
parse(rawUrl)
/**
* Parse the URL
* @param uri
* @returns {{
* path: string,
* protocol: string,
* hostname: string,
* password: string,
* search: string,
* port: string,
* auth: string,
* query: {},
* host: *,
* uri: string,
* user: string,
* hash: string
* }}
*/
function parse(uri) {
let parts = (uri || '').match(URL_REGEX),
auth = (parts[3] || '').split(':'),
host = auth.length
? (parts[2] || '').replace(/(.*@)/, '')
: parts[2]
_parsed = {
uri: parts[0],
protocol: parts[1],
host: host,
hostname: parts[4],
path: decodeURIComponent(parts[6]),
query: mapSearchParams(parts[7]),
hash: decodeURIComponent(parts[8])
}
return _parsed;
}
/**
* Build the URL
* @returns {string}
*/
function build() {
let buf = []
if (_parsed.protocol)
buf.push(`${_parsed.protocol}://`)
if (_parsed.host) {
buf.push(_parsed.host)
} else {
if (_parsed.hostname)
buf.push(_parsed.hostname)
}
if (_parsed.path)
buf.push(encodeURIComponent(_parsed.path))
if (_parsed.query && typeof _parsed.query === 'object') {
if (!_parsed.path)
buf.push('/')
buf.push('?' + (Object.keys(_parsed.query).map(name => {
if (Array.isArray(_parsed.query[name])) {
return _parsed.query[name].map(value => {
return `${encodeURIComponent(name)}[]=${encodeURIComponent(value)}`
}).join('&')
} else {
return `${encodeURIComponent(name)}=${encodeURIComponent(_parsed.query[name])}`
}
}).join('&')))
}
if (_parsed.hash) {
if (!_parsed.path)
buf.push('/')
buf.push(`#${encodeURIComponent(_parsed.hash)}`)
}
return _url = buf.filter(part => typeof part === 'string').join('')
}
/**
* A setter and getter for all of our properties
* @param type
* @returns {function(*=): (*)}
*/
function accessor(type) {
return value => {
if (value) {
_parsed[type] = encodeURIComponent(escape(value))
}
return _parsed[type]
}
}
return {
parse: (url) => parse(url),
build: () => build(),
uri : accessor('uri'),
protocol: accessor('protocol'),
host : accessor('host'),
hostname: accessor('hostname'),
path : accessor('path'),
hash : accessor('hash'),
query : (value, mode = 'append') => {
if (value) {
if (mode === 'override') {
_parsed.query = value
} else if ($mode === 'append') {
_parsed.query = {
..._parsed.query,
...value
}
} else {
throw new Error('url.js unknown mode')
}
}
return _parsed.query
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment