UNPKG

@expo/metro-runtime

Version:

Tools for making advanced Metro bundler features work

211 lines (201 loc) 5.75 kB
// Copyright © 2023 650 Industries. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. class DOMException extends Error { constructor(message: string, name: string) { super(message); this.name = name; } } // The differences between the definitions of `Location` and `WorkerLocation` // are because of the `LegacyUnforgeable` attribute only specified upon // `Location`'s properties. See: // - https://html.spec.whatwg.org/multipage/history.html#the-location-interface // - https://heycam.github.io/webidl/#LegacyUnforgeable class Location { constructor(href: string | null = null) { const url = new URL( // @ts-expect-error href ); try { url.username = ''; } catch { throw new Error( 'Attempting to use the window.location polyfill before the URL built-in has been polyfilled.' ); } url.password = ''; Object.defineProperties(this, { hash: { get() { return url.hash; }, set() { throw new DOMException(`Cannot set "location.hash".`, 'NotSupportedError'); }, enumerable: true, }, host: { get() { return url.host; }, set() { throw new DOMException(`Cannot set "location.host".`, 'NotSupportedError'); }, enumerable: true, }, hostname: { get() { return url.hostname; }, set() { throw new DOMException(`Cannot set "location.hostname".`, 'NotSupportedError'); }, enumerable: true, }, href: { get() { return url.href; }, set() { throw new DOMException(`Cannot set "location.href".`, 'NotSupportedError'); }, enumerable: true, }, origin: { get() { return url.origin; }, enumerable: true, }, pathname: { get() { return url.pathname; }, set() { throw new DOMException(`Cannot set "location.pathname".`, 'NotSupportedError'); }, enumerable: true, }, port: { get() { return url.port; }, set() { throw new DOMException(`Cannot set "location.port".`, 'NotSupportedError'); }, enumerable: true, }, protocol: { get() { return url.protocol; }, set() { throw new DOMException(`Cannot set "location.protocol".`, 'NotSupportedError'); }, enumerable: true, }, search: { get() { return url.search; }, set() { throw new DOMException(`Cannot set "location.search".`, 'NotSupportedError'); }, enumerable: true, }, ancestorOrigins: { get() { return { length: 0, item: () => null, contains: () => false, }; }, enumerable: true, }, assign: { value: function assign() { throw new DOMException(`Cannot call "location.assign()".`, 'NotSupportedError'); }, enumerable: true, }, reload: { value: function reload() { if (process.env.NODE_ENV !== 'production') { // NOTE: This does change how native fast refresh works. The upstream metro-runtime will check // if `location.reload` exists before falling back on an implementation that is nearly identical to // this. The main difference is that on iOS there is a "reason" message sent, but at the time of writing // this, that message is unused (ref: `RCTTriggerReloadCommandNotification`). const DevSettings = (require('react-native') as typeof import('react-native')) .DevSettings; return DevSettings.reload(); } else if ( typeof globalThis.expo !== 'undefined' && 'reloadAppAsync' in globalThis.expo ) { // Expo SDK 51 and above. globalThis.expo.reloadAppAsync(''); } else { throw new DOMException(`Cannot call "location.reload()".`, 'NotSupportedError'); } }, enumerable: true, }, replace: { value: function replace() { throw new DOMException(`Cannot call "location.replace()".`, 'NotSupportedError'); }, enumerable: true, }, toString: { value: function toString() { return url.href; }, enumerable: true, }, [Symbol.for('Expo.privateCustomInspect')]: { value(inspect: any) { const object = { hash: this.hash, host: this.host, hostname: this.hostname, href: this.href, origin: this.origin, pathname: this.pathname, port: this.port, protocol: this.protocol, search: this.search, }; return `${this.constructor.name} ${inspect(object)}`; }, }, }); } } Object.defineProperties(Location.prototype, { [Symbol.toString()]: { value: 'Location', configurable: true, }, }); let location: Location | undefined = undefined; export function setLocationHref(href: string) { location = new Location(href); } export function install() { Object.defineProperty(global, 'Location', { value: Location, configurable: true, writable: true, }); Object.defineProperty(window, 'location', { get() { return location; }, set() { throw new DOMException(`Cannot set "location".`, 'NotSupportedError'); }, enumerable: true, }); }