Spaces:
Sleeping
Sleeping
| const path = require('bare-path') | |
| const binding = require('./binding') | |
| const errors = require('./lib/errors') | |
| const URLSearchParams = require('./lib/url-search-params') | |
| const kind = Symbol.for('bare.url.kind') | |
| const isWindows = Bare.platform === 'win32' | |
| class URL { | |
| static get [kind]() { | |
| return 0 // Compatibility version | |
| } | |
| constructor(input, base, opts = {}) { | |
| if (arguments.length === 0) throw errors.INVALID_URL() | |
| input = String(input) | |
| if (base !== undefined) base = String(base) | |
| this._components = new Uint32Array(8) | |
| this._parse(input, base, opts.throw !== false) | |
| if (this._href) this._params = new URLSearchParams(this.search, this) | |
| } | |
| get [kind]() { | |
| return URL[kind] | |
| } | |
| // https://url.spec.whatwg.org/#dom-url-href | |
| get href() { | |
| return this._href | |
| } | |
| set href(value) { | |
| this._update(value) | |
| this._params._parse(this.search) | |
| } | |
| // https://url.spec.whatwg.org/#dom-url-protocol | |
| get protocol() { | |
| return this._slice(0, this._components[0]) + ':' | |
| } | |
| set protocol(value) { | |
| this._update(this._replace(value.replace(/:+$/, ''), 0, this._components[0])) | |
| } | |
| // https://url.spec.whatwg.org/#dom-url-username | |
| get username() { | |
| return this._slice(this._components[0] + 3 /* :// */, this._components[1]) | |
| } | |
| set username(value) { | |
| if (cannotHaveCredentialsOrPort(this)) { | |
| return | |
| } | |
| if (this.username === '') value += '@' | |
| this._update(this._replace(value, this._components[0] + 3 /* :// */, this._components[1])) | |
| } | |
| // https://url.spec.whatwg.org/#dom-url-password | |
| get password() { | |
| return this._href.slice(this._components[1] + 1 /* : */, this._components[2] - 1 /* @ */) | |
| } | |
| set password(value) { | |
| if (cannotHaveCredentialsOrPort(this)) { | |
| return | |
| } | |
| let start = this._components[1] + 1 /* : */ | |
| let end = this._components[2] - 1 /* @ */ | |
| if (this.password === '') { | |
| value = ':' + value | |
| start-- | |
| } | |
| if (this.username === '') { | |
| value += '@' | |
| end++ | |
| } | |
| this._update(this._replace(value, start, end)) | |
| } | |
| // https://url.spec.whatwg.org/#dom-url-host | |
| get host() { | |
| return this._slice(this._components[2], this._components[5]) | |
| } | |
| set host(value) { | |
| if (hasOpaquePath(this)) { | |
| return | |
| } | |
| this._update( | |
| this._replace(value, this._components[2], this._components[value.includes(':') ? 5 : 3]) | |
| ) | |
| } | |
| // https://url.spec.whatwg.org/#dom-url-hostname | |
| get hostname() { | |
| return this._slice(this._components[2], this._components[3]) | |
| } | |
| set hostname(value) { | |
| if (hasOpaquePath(this)) { | |
| return | |
| } | |
| this._update(this._replace(value, this._components[2], this._components[3])) | |
| } | |
| // https://url.spec.whatwg.org/#dom-url-port | |
| get port() { | |
| return this._slice(this._components[3] + 1 /* : */, this._components[5]) | |
| } | |
| set port(value) { | |
| if (cannotHaveCredentialsOrPort(this)) { | |
| return | |
| } | |
| let start = this._components[3] + 1 /* : */ | |
| if (this.port === '') { | |
| value = ':' + value | |
| start-- | |
| } | |
| this._update(this._replace(value, start, this._components[5])) | |
| } | |
| // https://url.spec.whatwg.org/#dom-url-pathname | |
| get pathname() { | |
| return this._slice(this._components[5], this._components[6] - 1 /* ? */) | |
| } | |
| set pathname(value) { | |
| if (hasOpaquePath(this)) { | |
| return | |
| } | |
| if (value[0] !== '/' && value[0] !== '\\') { | |
| value = '/' + value | |
| } | |
| this._update(this._replace(value, this._components[5], this._components[6] - 1 /* ? */)) | |
| } | |
| // https://url.spec.whatwg.org/#dom-url-search | |
| get search() { | |
| return this._slice(this._components[6] - 1 /* ? */, this._components[7] - 1 /* # */) | |
| } | |
| set search(value) { | |
| if (value && value[0] !== '?') value = '?' + value | |
| this._update( | |
| this._replace(value, this._components[6] - 1 /* ? */, this._components[7] - 1 /* # */) | |
| ) | |
| this._params._parse(this.search) | |
| } | |
| // https://url.spec.whatwg.org/#dom-url-searchparams | |
| get searchParams() { | |
| return this._params | |
| } | |
| // https://url.spec.whatwg.org/#dom-url-hash | |
| get hash() { | |
| return this._slice(this._components[7] - 1 /* # */) | |
| } | |
| set hash(value) { | |
| if (value && value[0] !== '#') value = '#' + value | |
| this._update(this._replace(value, this._components[7] - 1 /* # */)) | |
| } | |
| toString() { | |
| return this._href | |
| } | |
| toJSON() { | |
| return this._href | |
| } | |
| [Symbol.for('bare.inspect')]() { | |
| return { | |
| __proto__: { constructor: URL }, | |
| href: this.href, | |
| protocol: this.protocol, | |
| username: this.username, | |
| password: this.password, | |
| host: this.host, | |
| hostname: this.hostname, | |
| port: this.port, | |
| pathname: this.pathname, | |
| search: this.search, | |
| searchParams: this.searchParams, | |
| hash: this.hash | |
| } | |
| } | |
| _slice(start, end = this._href.length) { | |
| return this._href.slice(start, end) | |
| } | |
| _replace(replacement, start, end = this._href.length) { | |
| return this._slice(0, start) + replacement + this._slice(end) | |
| } | |
| _parse(input, base, shouldThrow) { | |
| try { | |
| this._href = binding.parse( | |
| String(input), | |
| base ? String(base) : null, | |
| this._components, | |
| shouldThrow | |
| ) | |
| } catch (err) { | |
| if (err instanceof TypeError) throw err | |
| throw errors.INVALID_URL(`Invalid URL '${input}'`, input) | |
| } | |
| } | |
| _update(input) { | |
| try { | |
| this._parse(input, null, true) | |
| } catch (err) { | |
| if (err instanceof TypeError) throw err | |
| } | |
| } | |
| } | |
| module.exports = exports = URL | |
| // https://url.spec.whatwg.org/#url-opaque-path | |
| function hasOpaquePath(url) { | |
| return url.pathname[0] !== '/' | |
| } | |
| // https://url.spec.whatwg.org/#cannot-have-a-username-password-port | |
| function cannotHaveCredentialsOrPort(url) { | |
| return url.hostname === '' || url.protocol === 'file:' | |
| } | |
| exports.URL = URL | |
| exports.URLSearchParams = URLSearchParams | |
| exports.errors = errors | |
| exports.isURL = function isURL(value) { | |
| if (value instanceof URL) return true | |
| return typeof value === 'object' && value !== null && value[kind] === URL[kind] | |
| } | |
| exports.isURLSearchParams = URLSearchParams.isURLSearchParams | |
| // https://url.spec.whatwg.org/#dom-url-parse | |
| exports.parse = function parse(input, base) { | |
| const url = new URL(input, base, { throw: false }) | |
| return url._href ? url : null | |
| } | |
| // https://url.spec.whatwg.org/#dom-url-canparse | |
| exports.canParse = function canParse(input, base) { | |
| return binding.canParse(String(input), base ? String(base) : null) | |
| } | |
| exports.fileURLToPath = function fileURLToPath(url) { | |
| if (typeof url === 'string') { | |
| url = new URL(url) | |
| } | |
| if (url.protocol !== 'file:') { | |
| throw errors.INVALID_URL_SCHEME('The URL must use the file: protocol') | |
| } | |
| if (isWindows) { | |
| if (/%2f|%5c/i.test(url.pathname)) { | |
| throw errors.INVALID_FILE_URL_PATH( | |
| 'The file: URL path must not include encoded \\ or / characters' | |
| ) | |
| } | |
| } else { | |
| if (url.hostname) { | |
| throw errors.INVALID_FILE_URL_HOST("The file: URL host must be 'localhost' or empty") | |
| } | |
| if (/%2f/i.test(url.pathname)) { | |
| throw errors.INVALID_FILE_URL_PATH('The file: URL path must not include encoded / characters') | |
| } | |
| } | |
| const pathname = path.normalize(decodeURIComponent(url.pathname)) | |
| if (isWindows) { | |
| if (url.hostname) return '\\\\' + url.hostname + pathname | |
| const letter = pathname.charCodeAt(1) | 0x20 | |
| if (letter < 0x61 /* a */ || letter > 0x7a /* z */ || pathname.charCodeAt(2) !== 0x3a /* : */) { | |
| throw errors.INVALID_FILE_URL_PATH('The file: URL path must be absolute') | |
| } | |
| return pathname.slice(1) | |
| } | |
| return pathname | |
| } | |
| exports.pathToFileURL = function pathToFileURL(pathname) { | |
| let resolved = path.resolve(pathname) | |
| if (pathname[pathname.length - 1] === '/') { | |
| resolved += '/' | |
| } else if (isWindows && pathname[pathname.length - 1] === '\\') { | |
| resolved += '\\' | |
| } | |
| resolved = resolved | |
| .replaceAll('%', '%25') // Must be first | |
| .replaceAll('#', '%23') | |
| .replaceAll('?', '%3f') | |
| .replaceAll('\n', '%0a') | |
| .replaceAll('\r', '%0d') | |
| .replaceAll('\t', '%09') | |
| if (!isWindows) { | |
| resolved = resolved.replaceAll('\\', '%5c') | |
| } | |
| return new URL('file:' + resolved) | |
| } | |
| exports.format = function format(parts) { | |
| const { protocol, auth, host, hostname, port, pathname, search, query, hash, slashes } = parts | |
| let result = '' | |
| if (typeof protocol === 'string') { | |
| result += protocol | |
| if (protocol[protocol.length - 1] !== ':') { | |
| result += ':' | |
| } | |
| if (slashes === true || /https?|ftp|gopher|file/.test(protocol)) { | |
| result += '//' | |
| } | |
| } | |
| if (typeof auth === 'string') { | |
| if (host || hostname) result += auth + '@' | |
| } | |
| if (typeof host === 'string') result += host | |
| else { | |
| result += hostname | |
| if (port) result += ':' + port | |
| } | |
| if (typeof pathname === 'string' && pathname !== '') { | |
| if (pathname[0] !== '/') result += '/' | |
| result += pathname | |
| } | |
| if (typeof search === 'string') { | |
| if (search[0] !== '?') result += '?' | |
| result += search | |
| } else if (typeof query === 'object' && query !== null) { | |
| result += '?' + new URLSearchParams(query) | |
| } | |
| if (typeof hash === 'string') { | |
| if (hash[0] !== '#') result += '#' | |
| result += hash | |
| } | |
| return result | |
| } | |