const { URL, domainToUnicode } = require('url') const CHAR_LOWERCASE_A = 97 const CHAR_LOWERCASE_Z = 122 const isWindows = process.platform === 'win32' class ERR_INVALID_FILE_URL_HOST extends TypeError { constructor (platform) { super(`File URL host must be "localhost" or empty on ${platform}`) this.code = 'ERR_INVALID_FILE_URL_HOST' } toString () { return `${this.name} [${this.code}]: ${this.message}` } } class ERR_INVALID_FILE_URL_PATH extends TypeError { constructor (msg) { super(`File URL path ${msg}`) this.code = 'ERR_INVALID_FILE_URL_PATH' } toString () { return `${this.name} [${this.code}]: ${this.message}` } } class ERR_INVALID_ARG_TYPE extends TypeError { constructor (name, actual) { super(`The "${name}" argument must be one of type string or an instance of URL. Received type ${typeof actual} ${actual}`) this.code = 'ERR_INVALID_ARG_TYPE' } toString () { return `${this.name} [${this.code}]: ${this.message}` } } class ERR_INVALID_URL_SCHEME extends TypeError { constructor (expected) { super(`The URL must be of scheme ${expected}`) this.code = 'ERR_INVALID_URL_SCHEME' } toString () { return `${this.name} [${this.code}]: ${this.message}` } } const isURLInstance = (input) => { return input != null && input.href && input.origin } const getPathFromURLWin32 = (url) => { const hostname = url.hostname let pathname = url.pathname for (let n = 0; n < pathname.length; n++) { if (pathname[n] === '%') { const third = pathname.codePointAt(n + 2) | 0x20 if ((pathname[n + 1] === '2' && third === 102) || (pathname[n + 1] === '5' && third === 99)) { throw new ERR_INVALID_FILE_URL_PATH('must not include encoded \\ or / characters') } } } pathname = pathname.replace(/\//g, '\\') pathname = decodeURIComponent(pathname) if (hostname !== '') { return `\\\\${domainToUnicode(hostname)}${pathname}` } const letter = pathname.codePointAt(1) | 0x20 const sep = pathname[2] if (letter < CHAR_LOWERCASE_A || letter > CHAR_LOWERCASE_Z || (sep !== ':')) { throw new ERR_INVALID_FILE_URL_PATH('must be absolute') } return pathname.slice(1) } const getPathFromURLPosix = (url) => { if (url.hostname !== '') { throw new ERR_INVALID_FILE_URL_HOST(process.platform) } const pathname = url.pathname for (let n = 0; n < pathname.length; n++) { if (pathname[n] === '%') { const third = pathname.codePointAt(n + 2) | 0x20 if (pathname[n + 1] === '2' && third === 102) { throw new ERR_INVALID_FILE_URL_PATH('must not include encoded / characters') } } } return decodeURIComponent(pathname) } const fileURLToPath = (path) => { if (typeof path === 'string') { path = new URL(path) } else if (!isURLInstance(path)) { throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path) } if (path.protocol !== 'file:') { throw new ERR_INVALID_URL_SCHEME('file') } return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path) } module.exports = fileURLToPath