guoyu/fronted_uniapp/yuyin/polyfills/url.js
2025-12-03 18:58:36 +08:00

121 lines
3.4 KiB
JavaScript

// Minimal URL polyfill for environments (like uni-app APP service layer) that
// don't provide a native URL implementation. It only supports the pieces that
// our codebase relies on: resolving href/origin/pathname and providing
// createObjectURL/revokeObjectURL stubs.
(function ensureURLPolyfill() {
if (typeof URL !== 'undefined') {
return
}
const globalObj = typeof globalThis !== 'undefined'
? globalThis
: (typeof global !== 'undefined'
? global
: (typeof self !== 'undefined'
? self
: (typeof window !== 'undefined' ? window : {})))
const ABSOLUTE_URL_REGEX = /^([a-zA-Z][a-zA-Z0-9+.-]*:)?\/\/([^\/?#:]+)(?::(\d+))?(\/[^?#]*)?([\?][^#]*)?(#.*)?$/
function normalizePath(path) {
if (!path) return '/'
if (!path.startsWith('/')) return '/' + path
return path
}
function parseAbsoluteUrl(url) {
const match = url.match(ABSOLUTE_URL_REGEX)
if (!match) return null
const protocol = match[1] || ''
const hostname = match[2] || ''
const port = match[3] || ''
const pathname = normalizePath(match[4] || '/')
const search = match[5] || ''
const hash = match[6] || ''
const host = hostname + (port ? ':' + port : '')
const origin = protocol ? `${protocol}//${host}` : ''
return { protocol, hostname, port, pathname, search, hash, host, origin, href: `${origin}${pathname}${search}${hash}` }
}
function isAbsolute(url) {
return /^([a-zA-Z][a-zA-Z0-9+.-]*:)?\/\//.test(url)
}
function resolveUrl(input, base) {
if (isAbsolute(input)) {
return input
}
if (base && isAbsolute(base)) {
const baseParts = parseAbsoluteUrl(base)
if (!baseParts) return input
if (input.startsWith('/')) {
return `${baseParts.origin}${input}`
}
const dir = baseParts.pathname.endsWith('/')
? baseParts.pathname
: baseParts.pathname.replace(/[^/]+$/, '/')
return `${baseParts.origin}${dir}${input}`
}
return input
}
class URLPolyfill {
constructor(input, base) {
const resolved = resolveUrl(String(input || ''), base ? String(base) : undefined)
const parsed = parseAbsoluteUrl(resolved)
if (parsed) {
this.href = parsed.href
this.protocol = parsed.protocol
this.hostname = parsed.hostname
this.port = parsed.port
this.pathname = parsed.pathname
this.search = parsed.search
this.hash = parsed.hash
this.host = parsed.host
this.origin = parsed.origin
} else {
this.href = resolved
this.protocol = ''
this.hostname = ''
this.port = ''
this.pathname = resolved || '/'
this.search = ''
this.hash = ''
this.host = ''
this.origin = ''
}
}
toString() {
return this.href
}
static createObjectURL(blob) {
console.warn('[URL polyfill] createObjectURL fallback used')
if (typeof blob === 'string') {
return blob
}
if (typeof FileReader !== 'undefined' && blob) {
try {
const reader = new FileReader()
reader.readAsDataURL(blob)
return ''
} catch (e) {
console.warn('[URL polyfill] createObjectURL fallback failed:', e)
}
}
return 'data:application/octet-stream;base64,'
}
static revokeObjectURL() {
// No-op in polyfill
}
}
globalObj.URL = URLPolyfill
})()