2024-01-01 14:58:21 -05:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2021-01-07 13:06:08 -05:00
|
|
|
|
2021-07-06 08:38:12 -04:00
|
|
|
/// <reference path="../../core/internal.d.ts" />
|
|
|
|
|
2023-12-07 08:21:01 -05:00
|
|
|
import { primordials } from "ext:core/mod.js";
|
2023-02-07 14:22:46 -05:00
|
|
|
const {
|
|
|
|
Error,
|
|
|
|
ObjectDefineProperties,
|
2023-04-14 16:23:28 -04:00
|
|
|
SafeWeakMap,
|
2023-02-07 14:22:46 -05:00
|
|
|
Symbol,
|
|
|
|
SymbolFor,
|
|
|
|
SymbolToStringTag,
|
|
|
|
TypeError,
|
|
|
|
WeakMapPrototypeGet,
|
|
|
|
WeakMapPrototypeSet,
|
|
|
|
} = primordials;
|
2021-07-03 15:32:28 -04:00
|
|
|
|
2024-01-10 17:37:25 -05:00
|
|
|
import { URL } from "ext:deno_url/00_url.js";
|
2024-03-22 12:21:05 -04:00
|
|
|
import { DOMException } from "./01_dom_exception.js";
|
2024-01-10 17:37:25 -05:00
|
|
|
|
2023-06-26 09:10:27 -04:00
|
|
|
const locationConstructorKey = Symbol("locationConstructorKey");
|
2021-01-07 13:06:08 -05:00
|
|
|
|
2023-02-07 14:22:46 -05:00
|
|
|
// 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 = null, key = null) {
|
|
|
|
if (key != locationConstructorKey) {
|
|
|
|
throw new TypeError("Illegal constructor.");
|
|
|
|
}
|
|
|
|
const url = new URL(href);
|
|
|
|
url.username = "";
|
|
|
|
url.password = "";
|
|
|
|
ObjectDefineProperties(this, {
|
|
|
|
hash: {
|
|
|
|
get() {
|
|
|
|
return url.hash;
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
set() {
|
|
|
|
throw new DOMException(
|
|
|
|
`Cannot set "location.hash".`,
|
|
|
|
"NotSupportedError",
|
|
|
|
);
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
host: {
|
|
|
|
get() {
|
|
|
|
return url.host;
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
set() {
|
|
|
|
throw new DOMException(
|
|
|
|
`Cannot set "location.host".`,
|
|
|
|
"NotSupportedError",
|
|
|
|
);
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
hostname: {
|
|
|
|
get() {
|
|
|
|
return url.hostname;
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
set() {
|
|
|
|
throw new DOMException(
|
|
|
|
`Cannot set "location.hostname".`,
|
|
|
|
"NotSupportedError",
|
|
|
|
);
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
href: {
|
|
|
|
get() {
|
|
|
|
return url.href;
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
set() {
|
|
|
|
throw new DOMException(
|
|
|
|
`Cannot set "location.href".`,
|
|
|
|
"NotSupportedError",
|
|
|
|
);
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
origin: {
|
|
|
|
get() {
|
|
|
|
return url.origin;
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
pathname: {
|
|
|
|
get() {
|
|
|
|
return url.pathname;
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
set() {
|
|
|
|
throw new DOMException(
|
|
|
|
`Cannot set "location.pathname".`,
|
|
|
|
"NotSupportedError",
|
|
|
|
);
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
port: {
|
|
|
|
get() {
|
|
|
|
return url.port;
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
set() {
|
|
|
|
throw new DOMException(
|
|
|
|
`Cannot set "location.port".`,
|
|
|
|
"NotSupportedError",
|
|
|
|
);
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
protocol: {
|
|
|
|
get() {
|
|
|
|
return url.protocol;
|
2021-01-07 13:06:08 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
set() {
|
|
|
|
throw new DOMException(
|
|
|
|
`Cannot set "location.protocol".`,
|
|
|
|
"NotSupportedError",
|
|
|
|
);
|
2021-01-29 08:08:22 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
search: {
|
|
|
|
get() {
|
|
|
|
return url.search;
|
|
|
|
},
|
|
|
|
set() {
|
|
|
|
throw new DOMException(
|
|
|
|
`Cannot set "location.search".`,
|
|
|
|
"NotSupportedError",
|
|
|
|
);
|
|
|
|
},
|
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
ancestorOrigins: {
|
|
|
|
get() {
|
|
|
|
// TODO(nayeemrmn): Replace with a `DOMStringList` instance.
|
|
|
|
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() {
|
|
|
|
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,
|
|
|
|
},
|
|
|
|
[SymbolFor("Deno.privateCustomInspect")]: {
|
2023-11-19 03:13:38 -05:00
|
|
|
value: function (inspect, inspectOptions) {
|
|
|
|
return `${this.constructor.name} ${
|
|
|
|
inspect({
|
|
|
|
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,
|
|
|
|
}, inspectOptions)
|
|
|
|
}`;
|
2023-02-07 14:22:46 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
2021-01-07 13:06:08 -05:00
|
|
|
}
|
2023-02-07 14:22:46 -05:00
|
|
|
}
|
2021-01-07 13:06:08 -05:00
|
|
|
|
2023-02-07 14:22:46 -05:00
|
|
|
ObjectDefineProperties(Location.prototype, {
|
|
|
|
[SymbolToStringTag]: {
|
|
|
|
value: "Location",
|
|
|
|
configurable: true,
|
|
|
|
},
|
|
|
|
});
|
2021-01-07 13:06:08 -05:00
|
|
|
|
2023-04-14 16:23:28 -04:00
|
|
|
const workerLocationUrls = new SafeWeakMap();
|
2021-01-17 10:28:54 -05:00
|
|
|
|
2023-02-07 14:22:46 -05:00
|
|
|
class WorkerLocation {
|
|
|
|
constructor(href = null, key = null) {
|
|
|
|
if (key != locationConstructorKey) {
|
|
|
|
throw new TypeError("Illegal constructor.");
|
2021-01-17 10:28:54 -05:00
|
|
|
}
|
2023-02-07 14:22:46 -05:00
|
|
|
const url = new URL(href);
|
|
|
|
url.username = "";
|
|
|
|
url.password = "";
|
|
|
|
WeakMapPrototypeSet(workerLocationUrls, this, url);
|
2021-01-17 10:28:54 -05:00
|
|
|
}
|
2023-02-07 14:22:46 -05:00
|
|
|
}
|
2021-01-17 10:28:54 -05:00
|
|
|
|
2023-02-07 14:22:46 -05:00
|
|
|
ObjectDefineProperties(WorkerLocation.prototype, {
|
|
|
|
hash: {
|
|
|
|
get() {
|
|
|
|
const url = WeakMapPrototypeGet(workerLocationUrls, this);
|
|
|
|
if (url == null) {
|
|
|
|
throw new TypeError("Illegal invocation.");
|
|
|
|
}
|
|
|
|
return url.hash;
|
2021-01-17 10:28:54 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
host: {
|
|
|
|
get() {
|
|
|
|
const url = WeakMapPrototypeGet(workerLocationUrls, this);
|
|
|
|
if (url == null) {
|
|
|
|
throw new TypeError("Illegal invocation.");
|
|
|
|
}
|
|
|
|
return url.host;
|
2021-01-17 10:28:54 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
hostname: {
|
|
|
|
get() {
|
|
|
|
const url = WeakMapPrototypeGet(workerLocationUrls, this);
|
|
|
|
if (url == null) {
|
|
|
|
throw new TypeError("Illegal invocation.");
|
|
|
|
}
|
|
|
|
return url.hostname;
|
2021-01-17 10:28:54 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
href: {
|
|
|
|
get() {
|
|
|
|
const url = WeakMapPrototypeGet(workerLocationUrls, this);
|
|
|
|
if (url == null) {
|
|
|
|
throw new TypeError("Illegal invocation.");
|
|
|
|
}
|
|
|
|
return url.href;
|
2021-01-17 10:28:54 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
origin: {
|
|
|
|
get() {
|
|
|
|
const url = WeakMapPrototypeGet(workerLocationUrls, this);
|
|
|
|
if (url == null) {
|
|
|
|
throw new TypeError("Illegal invocation.");
|
|
|
|
}
|
|
|
|
return url.origin;
|
2021-01-17 10:28:54 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
pathname: {
|
|
|
|
get() {
|
|
|
|
const url = WeakMapPrototypeGet(workerLocationUrls, this);
|
|
|
|
if (url == null) {
|
|
|
|
throw new TypeError("Illegal invocation.");
|
|
|
|
}
|
|
|
|
return url.pathname;
|
2021-01-17 10:28:54 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
port: {
|
|
|
|
get() {
|
|
|
|
const url = WeakMapPrototypeGet(workerLocationUrls, this);
|
|
|
|
if (url == null) {
|
|
|
|
throw new TypeError("Illegal invocation.");
|
|
|
|
}
|
|
|
|
return url.port;
|
2021-01-17 10:28:54 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
protocol: {
|
|
|
|
get() {
|
|
|
|
const url = WeakMapPrototypeGet(workerLocationUrls, this);
|
|
|
|
if (url == null) {
|
|
|
|
throw new TypeError("Illegal invocation.");
|
|
|
|
}
|
|
|
|
return url.protocol;
|
2021-01-17 10:28:54 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
search: {
|
|
|
|
get() {
|
|
|
|
const url = WeakMapPrototypeGet(workerLocationUrls, this);
|
|
|
|
if (url == null) {
|
|
|
|
throw new TypeError("Illegal invocation.");
|
|
|
|
}
|
|
|
|
return url.search;
|
2021-01-17 10:28:54 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
},
|
|
|
|
toString: {
|
|
|
|
value: function toString() {
|
|
|
|
const url = WeakMapPrototypeGet(workerLocationUrls, this);
|
|
|
|
if (url == null) {
|
|
|
|
throw new TypeError("Illegal invocation.");
|
|
|
|
}
|
|
|
|
return url.href;
|
2021-01-17 10:28:54 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
writable: true,
|
|
|
|
},
|
|
|
|
[SymbolToStringTag]: {
|
|
|
|
value: "WorkerLocation",
|
|
|
|
configurable: true,
|
|
|
|
},
|
|
|
|
[SymbolFor("Deno.privateCustomInspect")]: {
|
2023-11-19 03:13:38 -05:00
|
|
|
value: function (inspect, inspectOptions) {
|
|
|
|
return `${this.constructor.name} ${
|
|
|
|
inspect({
|
|
|
|
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,
|
|
|
|
}, inspectOptions)
|
|
|
|
}`;
|
2021-01-29 08:08:22 -05:00
|
|
|
},
|
2023-02-07 14:22:46 -05:00
|
|
|
},
|
|
|
|
});
|
2021-01-17 10:28:54 -05:00
|
|
|
|
2023-02-07 14:22:46 -05:00
|
|
|
let location = undefined;
|
|
|
|
let workerLocation = undefined;
|
2021-01-07 13:06:08 -05:00
|
|
|
|
2023-02-07 14:22:46 -05:00
|
|
|
function setLocationHref(href) {
|
|
|
|
location = new Location(href, locationConstructorKey);
|
|
|
|
workerLocation = new WorkerLocation(href, locationConstructorKey);
|
|
|
|
}
|
2021-01-07 13:06:08 -05:00
|
|
|
|
2023-02-07 14:22:46 -05:00
|
|
|
function getLocationHref() {
|
|
|
|
return location?.href;
|
|
|
|
}
|
|
|
|
|
|
|
|
const locationConstructorDescriptor = {
|
|
|
|
value: Location,
|
|
|
|
configurable: true,
|
|
|
|
writable: true,
|
|
|
|
};
|
|
|
|
|
|
|
|
const workerLocationConstructorDescriptor = {
|
|
|
|
value: WorkerLocation,
|
|
|
|
configurable: true,
|
|
|
|
writable: true,
|
|
|
|
};
|
|
|
|
|
|
|
|
const locationDescriptor = {
|
|
|
|
get() {
|
|
|
|
return location;
|
|
|
|
},
|
|
|
|
set() {
|
|
|
|
throw new DOMException(`Cannot set "location".`, "NotSupportedError");
|
|
|
|
},
|
|
|
|
enumerable: true,
|
|
|
|
};
|
|
|
|
const workerLocationDescriptor = {
|
|
|
|
get() {
|
|
|
|
if (workerLocation == null) {
|
|
|
|
throw new Error(
|
|
|
|
`Assertion: "globalThis.location" must be defined in a worker.`,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return workerLocation;
|
|
|
|
},
|
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
};
|
|
|
|
|
|
|
|
export {
|
|
|
|
getLocationHref,
|
|
|
|
locationConstructorDescriptor,
|
|
|
|
locationDescriptor,
|
|
|
|
setLocationHref,
|
|
|
|
workerLocationConstructorDescriptor,
|
|
|
|
workerLocationDescriptor,
|
|
|
|
};
|