Skip to content

Commit

Permalink
spec compliance
Browse files Browse the repository at this point in the history
  • Loading branch information
lucacasonato committed Jun 21, 2021
1 parent 614b330 commit f6258e8
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 47 deletions.
41 changes: 41 additions & 0 deletions extensions/web/02_event.js
Original file line number Diff line number Diff line change
Expand Up @@ -1197,6 +1197,46 @@
}
}

const _eventHandlers = Symbol("eventHandlers");

function makeWrappedHandler(handler) {
function wrappedHandler(...args) {
if (typeof wrappedHandler.handler !== "function") {
return;
}
return wrappedHandler.handler.call(this, ...args);
}
wrappedHandler.handler = handler;
return wrappedHandler;
}

// TODO(benjamingr) reuse this here and websocket where possible
function defineEventHandler(emitter, name, init) {
// HTML specification section 8.1.5.1
Object.defineProperty(emitter, `on${name}`, {
get() {
return this[_eventHandlers]?.get(name)?.handler;
},
set(value) {
if (!this[_eventHandlers]) {
this[_eventHandlers] = new Map();
}
let handlerWrapper = this[_eventHandlers]?.get(name);
if (handlerWrapper) {
console.log("foo");
handlerWrapper.handler = value;
} else {
handlerWrapper = makeWrappedHandler(value);
this.addEventListener(name, handlerWrapper);
init?.(this);
}
this[_eventHandlers].set(name, handlerWrapper);
},
configurable: true,
enumerable: true,
});
}

window.Event = Event;
window.EventTarget = EventTarget;
window.ErrorEvent = ErrorEvent;
Expand All @@ -1214,5 +1254,6 @@
window.__bootstrap.event = {
setIsTrusted,
setTarget,
defineEventHandler,
};
})(this);
39 changes: 1 addition & 38 deletions extensions/web/03_abort_signal.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

((window) => {
const webidl = window.__bootstrap.webidl;
const { setIsTrusted } = window.__bootstrap.event;
const { setIsTrusted, defineEventHandler } = window.__bootstrap.event;

const add = Symbol("add");
const signalAbort = Symbol("signalAbort");
Expand Down Expand Up @@ -81,43 +81,6 @@

webidl.configurePrototype(AbortController);

const handlerSymbol = Symbol("eventHandlers");

function makeWrappedHandler(handler) {
function wrappedHandler(...args) {
if (typeof wrappedHandler.handler !== "function") {
return;
}
return wrappedHandler.handler.call(this, ...args);
}
wrappedHandler.handler = handler;
return wrappedHandler;
}
// TODO(benjamingr) reuse this here and websocket where possible
function defineEventHandler(emitter, name) {
// HTML specification section 8.1.5.1
Object.defineProperty(emitter, `on${name}`, {
get() {
return this[handlerSymbol]?.get(name)?.handler;
},
set(value) {
if (!this[handlerSymbol]) {
this[handlerSymbol] = new Map();
}
let handlerWrapper = this[handlerSymbol]?.get(name);
if (handlerWrapper) {
handlerWrapper.handler = value;
} else {
handlerWrapper = makeWrappedHandler(value);
this.addEventListener(name, handlerWrapper);
}
this[handlerSymbol].set(name, handlerWrapper);
},
configurable: true,
enumerable: true,
});
}

webidl.converters["AbortSignal"] = webidl.createInterfaceConverter(
"AbortSignal",
AbortSignal,
Expand Down
78 changes: 70 additions & 8 deletions extensions/web/13_message_port.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
const core = window.Deno.core;
const webidl = window.__bootstrap.webidl;
const { setEventTargetData } = window.__bootstrap.eventTarget;
const { defineEventHandler } = window.__bootstrap.event;

class MessageChannel {
/** @type {MessagePort} */
Expand Down Expand Up @@ -49,7 +50,10 @@
}
}

webidl.configurePrototype(MessageChannel);

const _id = Symbol("id");
const _enabled = Symbol("enabled");

/**
* @param {number} id
Expand All @@ -64,7 +68,9 @@

class MessagePort extends EventTarget {
/** @type {number | null} */
[_id];
[_id] = null;
/** @type {boolean} */
[_enabled] = false;

constructor() {
super();
Expand All @@ -76,42 +82,84 @@
* @param {object[] | PostMessageOptions} transferOrOptions
*/
postMessage(message, transferOrOptions = {}) {
let transfer = [];
if (Array.isArray(transferOrOptions)) {
transfer = transferOrOptions;
} else if (Array.isArray(transferOrOptions.transfer)) {
transfer = transferOrOptions.transfer;
webidl.assertBranded(this, MessagePort);
const prefix = "Failed to execute 'postMessage' on 'MessagePort'";
webidl.requiredArguments(arguments.length, 1, { prefix });
message = webidl.converters.any(message);
let options;
if (
webidl.type(transferOrOptions) === "Object" &&
transferOrOptions !== undefined &&
transferOrOptions[Symbol.iterator] !== undefined
) {
const transfer = webidl.converters["sequence<object>"](
transferOrOptions,
{ prefix, context: "Argument 2" },
);
options = { transfer };
} else {
options = webidl.converters.PostMessageOptions(transferOrOptions, {
prefix,
context: "Argument 2",
});
}
const { transfer } = options;
if (transfer.includes(this)) {
throw new DOMException("Can not tranfer self", "DataCloneError");
}

const data = serializeJsMessageData(message, transfer);
if (this[_id] === null) return;
core.opSync("op_message_port_post_message", this[_id], data);
}

start() {
webidl.assertBranded(this, MessagePort);
if (this[_enabled]) return;
(async () => {
this[_enabled] = true;
while (true) {
if (this[_id] === null) break;
const data = await core.opAsync(
"op_message_port_recv_message",
this[_id],
);
if (data === null) break;
const [message, transfer] = deserializeJsMessageData(data);
let message, transfer;
try {
const v = deserializeJsMessageData(data);
message = v[0];
transfer = v[1];
} catch (err) {
const event = new MessageEvent("messageerror", { data: err });
this.dispatchEvent(event);
return;
}
const event = new MessageEvent("message", {
data: message,
ports: transfer,
});
this.dispatchEvent(event);
}
this[_enabled] = false;
})();
}

close() {
webidl.assertBranded(this, MessagePort);
if (this[_id] !== null) {
core.close(this[_id]);
this[_id] = null;
}
}
}

defineEventHandler(MessagePort.prototype, "message", function (self) {
self.start();
});
defineEventHandler(MessagePort.prototype, "messageerror");

webidl.configurePrototype(MessagePort);

/**
* @returns {[number, number]}
*/
Expand Down Expand Up @@ -162,6 +210,7 @@
if (id === null) {
throw new TypeError("Can not transfer disentangled message port");
}
transferable[_id] = null;
serializedTransferables.push({ kind: "messagePort", data: id });
} else {
throw new TypeError("Value not transferable");
Expand All @@ -174,6 +223,19 @@
};
}

webidl.converters.PostMessageOptions = webidl.createDictionaryConverter(
"PostMessageOptions",
[
{
key: "transfer",
converter: webidl.converters["sequence<object>"],
get defaultValue() {
return [];
},
},
],
);

window.__bootstrap.messagePort = {
MessageChannel,
MessagePort,
Expand Down
6 changes: 5 additions & 1 deletion extensions/webidl/00_webidl.js
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,10 @@
converters.USVString,
);
converters["sequence<double>"] = createSequenceConverter(
converters["double"],
converters.double,
);
converters["sequence<object>"] = createSequenceConverter(
converters.object,
);
converters["Promise<undefined>"] = createPromiseConverter(() => undefined);

Expand Down Expand Up @@ -626,6 +629,7 @@
get() {
return member.defaultValue;
},
enumerable: true,
});
}
}
Expand Down
15 changes: 15 additions & 0 deletions extensions/webidl/internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,21 @@ declare namespace globalThis {
* Configure prototype properties enumerability / writability / configurability.
*/
declare function configurePrototype(prototype: any);

/**
* Get the WebIDL / ES type of a value.
*/
declare function type(
v: any,
):
| "Null"
| "Undefined"
| "Boolean"
| "Number"
| "String"
| "Symbol"
| "BigInt"
| "Object";
}
}
}

0 comments on commit f6258e8

Please sign in to comment.