summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo K <crowlkats@toaxl.com>2021-07-05 13:17:11 +0200
committerGitHub <noreply@github.com>2021-07-05 13:17:11 +0200
commit220104f577c3c079454b902a413fae98060595ec (patch)
tree50a0945e0c9de598dc67b590243a16b6c8c40203
parenta6c840d15020b72326832c19e6a5ac0d95b9bdca (diff)
fix: spec conformance for performance API (#10887)
-rw-r--r--cli/tests/unit/performance_test.ts6
-rw-r--r--extensions/timers/02_performance.js307
-rw-r--r--extensions/webidl/00_webidl.js1
-rw-r--r--tools/wpt/expectation.json18
4 files changed, 235 insertions, 97 deletions
diff --git a/cli/tests/unit/performance_test.ts b/cli/tests/unit/performance_test.ts
index 229b38bb8..156841165 100644
--- a/cli/tests/unit/performance_test.ts
+++ b/cli/tests/unit/performance_test.ts
@@ -82,12 +82,12 @@ unitTest(function performanceMeasure() {
});
unitTest(function performanceIllegalConstructor() {
- assertThrows(() => new Performance(), TypeError, "Illegal constructor.");
+ assertThrows(() => new Performance(), TypeError, "Illegal constructor");
assertEquals(Performance.length, 0);
});
unitTest(function performanceEntryIllegalConstructor() {
- assertThrows(() => new PerformanceEntry(), TypeError, "Illegal constructor.");
+ assertThrows(() => new PerformanceEntry(), TypeError, "Illegal constructor");
assertEquals(PerformanceEntry.length, 0);
});
@@ -95,6 +95,6 @@ unitTest(function performanceMeasureIllegalConstructor() {
assertThrows(
() => new PerformanceMeasure(),
TypeError,
- "Illegal constructor.",
+ "Illegal constructor",
);
});
diff --git a/extensions/timers/02_performance.js b/extensions/timers/02_performance.js
index baa1676a2..56f82b42e 100644
--- a/extensions/timers/02_performance.js
+++ b/extensions/timers/02_performance.js
@@ -10,6 +10,58 @@
const customInspect = Symbol.for("Deno.customInspect");
let performanceEntries = [];
+ webidl.converters["PerformanceMarkOptions"] = webidl
+ .createDictionaryConverter(
+ "PerformanceMarkOptions",
+ [
+ {
+ key: "detail",
+ converter: webidl.converters.any,
+ },
+ {
+ key: "startTime",
+ converter: webidl.converters.DOMHighResTimeStamp,
+ },
+ ],
+ );
+
+ webidl.converters["DOMString or DOMHighResTimeStamp"] = (V, opts) => {
+ if (webidl.type(V) === "Number" && V !== null) {
+ return webidl.converters.DOMHighResTimeStamp(V, opts);
+ }
+ return webidl.converters.DOMString(V, opts);
+ };
+
+ webidl.converters["PerformanceMeasureOptions"] = webidl
+ .createDictionaryConverter(
+ "PerformanceMeasureOptions",
+ [
+ {
+ key: "detail",
+ converter: webidl.converters.any,
+ },
+ {
+ key: "start",
+ converter: webidl.converters["DOMString or DOMHighResTimeStamp"],
+ },
+ {
+ key: "duration",
+ converter: webidl.converters.DOMHighResTimeStamp,
+ },
+ {
+ key: "end",
+ converter: webidl.converters["DOMString or DOMHighResTimeStamp"],
+ },
+ ],
+ );
+
+ webidl.converters["DOMString or PerformanceMeasureOptions"] = (V, opts) => {
+ if (webidl.type(V) === "Object" && V !== null) {
+ return webidl.converters["PerformanceMeasureOptions"](V, opts);
+ }
+ return webidl.converters.DOMString(V, opts);
+ };
+
function findMostRecent(
name,
type,
@@ -50,26 +102,34 @@
const now = opNow;
+ const _name = Symbol("[[name]]");
+ const _entryType = Symbol("[[entryType]]");
+ const _startTime = Symbol("[[startTime]]");
+ const _duration = Symbol("[[duration]]");
class PerformanceEntry {
- #name = "";
- #entryType = "";
- #startTime = 0;
- #duration = 0;
+ [_name] = "";
+ [_entryType] = "";
+ [_startTime] = 0;
+ [_duration] = 0;
get name() {
- return this.#name;
+ webidl.assertBranded(this, PerformanceEntry);
+ return this[_name];
}
get entryType() {
- return this.#entryType;
+ webidl.assertBranded(this, PerformanceEntry);
+ return this[_entryType];
}
get startTime() {
- return this.#startTime;
+ webidl.assertBranded(this, PerformanceEntry);
+ return this[_startTime];
}
get duration() {
- return this.#duration;
+ webidl.assertBranded(this, PerformanceEntry);
+ return this[_duration];
}
constructor(
@@ -77,41 +137,48 @@
entryType = null,
startTime = null,
duration = null,
- key = null,
+ key = undefined,
) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
+ if (key !== illegalConstructorKey) {
+ webidl.illegalConstructor();
}
- this.#name = name;
- this.#entryType = entryType;
- this.#startTime = startTime;
- this.#duration = duration;
+ this[webidl.brand] = webidl.brand;
+
+ this[_name] = name;
+ this[_entryType] = entryType;
+ this[_startTime] = startTime;
+ this[_duration] = duration;
}
toJSON() {
+ webidl.assertBranded(this, PerformanceEntry);
return {
- name: this.#name,
- entryType: this.#entryType,
- startTime: this.#startTime,
- duration: this.#duration,
+ name: this[_name],
+ entryType: this[_entryType],
+ startTime: this[_startTime],
+ duration: this[_duration],
};
}
- [customInspect]() {
- return `${this.constructor.name} { name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`;
+ [customInspect](inspect) {
+ return `${this.constructor.name} ${inspect(this.toJSON())}`;
}
}
+ webidl.configurePrototype(PerformanceEntry);
+ const _detail = Symbol("[[detail]]");
class PerformanceMark extends PerformanceEntry {
[Symbol.toStringTag] = "PerformanceMark";
- #detail = null;
+ [_detail] = null;
get detail() {
- return this.#detail;
+ webidl.assertBranded(this, PerformanceMark);
+ return this[_detail];
}
get entryType() {
+ webidl.assertBranded(this, PerformanceMark);
return "mark";
}
@@ -122,28 +189,28 @@
const prefix = "Failed to construct 'PerformanceMark'";
webidl.requiredArguments(arguments.length, 1, { prefix });
- // ensure options is object-ish, or null-ish
- switch (typeof options) {
- case "object": // includes null
- case "function":
- case "undefined": {
- break;
- }
- default: {
- throw new TypeError("Invalid options");
- }
- }
+ name = webidl.converters.DOMString(name, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ options = webidl.converters.PerformanceMarkOptions(options, {
+ prefix,
+ context: "Argument 2",
+ });
- const { detail = null, startTime = now() } = options ?? {};
+ const { detail = null, startTime = now() } = options;
super(name, "mark", startTime, 0, illegalConstructorKey);
+ this[webidl.brand] = webidl.brand;
if (startTime < 0) {
throw new TypeError("startTime cannot be negative");
}
- this.#detail = structuredClone(detail);
+ this[_detail] = structuredClone(detail);
}
toJSON() {
+ webidl.assertBranded(this, PerformanceMark);
return {
name: this.name,
entryType: this.entryType,
@@ -153,43 +220,45 @@
};
}
- [customInspect]() {
- return this.detail
- ? `${this.constructor.name} {\n detail: ${
- JSON.stringify(this.detail, null, 2)
- },\n name: "${this.name}",\n entryType: "${this.entryType}",\n startTime: ${this.startTime},\n duration: ${this.duration}\n}`
- : `${this.constructor.name} { detail: ${this.detail}, name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`;
+ [customInspect](inspect) {
+ return `${this.constructor.name} ${inspect(this.toJSON())}`;
}
}
+ webidl.configurePrototype(PerformanceMark);
class PerformanceMeasure extends PerformanceEntry {
[Symbol.toStringTag] = "PerformanceMeasure";
- #detail = null;
+ [_detail] = null;
get detail() {
- return this.#detail;
+ webidl.assertBranded(this, PerformanceMeasure);
+ return this[_detail];
}
get entryType() {
+ webidl.assertBranded(this, PerformanceMeasure);
return "measure";
}
constructor(
- name,
- startTime,
- duration,
+ name = null,
+ startTime = null,
+ duration = null,
detail = null,
- key,
+ key = undefined,
) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
+ if (key !== illegalConstructorKey) {
+ webidl.illegalConstructor();
}
- super(name, "measure", startTime, duration, illegalConstructorKey);
- this.#detail = structuredClone(detail);
+
+ super(name, "measure", startTime, duration, key);
+ this[webidl.brand] = webidl.brand;
+ this[_detail] = structuredClone(detail);
}
toJSON() {
+ webidl.assertBranded(this, PerformanceMeasure);
return {
name: this.name,
entryType: this.entryType,
@@ -199,70 +268,117 @@
};
}
- [customInspect]() {
- return this.detail
- ? `${this.constructor.name} {\n detail: ${
- JSON.stringify(this.detail, null, 2)
- },\n name: "${this.name}",\n entryType: "${this.entryType}",\n startTime: ${this.startTime},\n duration: ${this.duration}\n}`
- : `${this.constructor.name} { detail: ${this.detail}, name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`;
+ [customInspect](inspect) {
+ return `${this.constructor.name} ${inspect(this.toJSON())}`;
}
}
+ webidl.configurePrototype(PerformanceMeasure);
class Performance {
- constructor(key = null) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
+ constructor() {
+ webidl.illegalConstructor();
}
- clearMarks(markName) {
- if (markName == null) {
+ clearMarks(markName = undefined) {
+ webidl.assertBranded(this, Performance);
+ if (markName !== undefined) {
+ markName = webidl.converters.DOMString(markName, {
+ prefix: "Failed to execute 'clearMarks' on 'Performance'",
+ context: "Argument 1",
+ });
+
performanceEntries = performanceEntries.filter(
- (entry) => entry.entryType !== "mark",
+ (entry) => !(entry.name === markName && entry.entryType === "mark"),
);
} else {
performanceEntries = performanceEntries.filter(
- (entry) => !(entry.name === markName && entry.entryType === "mark"),
+ (entry) => entry.entryType !== "mark",
);
}
}
- clearMeasures(measureName) {
- if (measureName == null) {
+ clearMeasures(measureName = undefined) {
+ webidl.assertBranded(this, Performance);
+ if (measureName !== undefined) {
+ measureName = webidl.converters.DOMString(measureName, {
+ prefix: "Failed to execute 'clearMeasures' on 'Performance'",
+ context: "Argument 1",
+ });
+
performanceEntries = performanceEntries.filter(
- (entry) => entry.entryType !== "measure",
+ (entry) =>
+ !(entry.name === measureName && entry.entryType === "measure"),
);
} else {
performanceEntries = performanceEntries.filter(
- (entry) =>
- !(entry.name === measureName && entry.entryType === "measure"),
+ (entry) => entry.entryType !== "measure",
);
}
}
getEntries() {
+ webidl.assertBranded(this, Performance);
return filterByNameType();
}
getEntriesByName(
name,
- type,
+ type = undefined,
) {
+ webidl.assertBranded(this, Performance);
+ const prefix = "Failed to execute 'getEntriesByName' on 'Performance'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ name = webidl.converters.DOMString(name, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ if (type !== undefined) {
+ type = webidl.converters.DOMString(type, {
+ prefix,
+ context: "Argument 2",
+ });
+ }
+
return filterByNameType(name, type);
}
getEntriesByType(type) {
+ webidl.assertBranded(this, Performance);
+ const prefix = "Failed to execute 'getEntriesByName' on 'Performance'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ type = webidl.converters.DOMString(type, {
+ prefix,
+ context: "Argument 1",
+ });
+
return filterByNameType(undefined, type);
}
mark(
markName,
- options = {},
+ markOptions = {},
) {
+ webidl.assertBranded(this, Performance);
+ const prefix = "Failed to execute 'mark' on 'Performance'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ markName = webidl.converters.DOMString(markName, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ markOptions = webidl.converters.PerformanceMarkOptions(markOptions, {
+ prefix,
+ context: "Argument 2",
+ });
+
// 3.1.1.1 If the global object is a Window object and markName uses the
// same name as a read only attribute in the PerformanceTiming interface,
// throw a SyntaxError. - not implemented
- const entry = new PerformanceMark(markName, options);
+ const entry = new PerformanceMark(markName, markOptions);
// 3.1.1.7 Queue entry - not implemented
performanceEntries.push(entry);
return entry;
@@ -271,8 +387,30 @@
measure(
measureName,
startOrMeasureOptions = {},
- endMark,
+ endMark = undefined,
) {
+ webidl.assertBranded(this, Performance);
+ const prefix = "Failed to execute 'measure' on 'Performance'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ measureName = webidl.converters.DOMString(measureName, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ startOrMeasureOptions = webidl.converters
+ ["DOMString or PerformanceMeasureOptions"](startOrMeasureOptions, {
+ prefix,
+ context: "Argument 2",
+ });
+
+ if (endMark !== undefined) {
+ endMark = webidl.converters.DOMString(endMark, {
+ prefix,
+ context: "Argument 3",
+ });
+ }
+
if (
startOrMeasureOptions && typeof startOrMeasureOptions === "object" &&
Object.keys(startOrMeasureOptions).length > 0
@@ -350,17 +488,30 @@
}
now() {
+ webidl.assertBranded(this, Performance);
return now();
}
- }
- const performance = new Performance(illegalConstructorKey);
+ toJSON() {
+ webidl.assertBranded(this, Performance);
+ return {};
+ }
+
+ [customInspect](inspect) {
+ return `${this.constructor.name} ${inspect(this.toJSON())}`;
+ }
+
+ get [Symbol.toStringTag]() {
+ return "Performance";
+ }
+ }
+ webidl.configurePrototype(Performance);
window.__bootstrap.performance = {
PerformanceEntry,
PerformanceMark,
PerformanceMeasure,
Performance,
- performance,
+ performance: webidl.createBranded(Performance),
};
})(this);
diff --git a/extensions/webidl/00_webidl.js b/extensions/webidl/00_webidl.js
index 07c9f8e31..16a6ab4a9 100644
--- a/extensions/webidl/00_webidl.js
+++ b/extensions/webidl/00_webidl.js
@@ -612,6 +612,7 @@
};
converters.DOMTimeStamp = converters["unsigned long long"];
+ converters.DOMHighResTimeStamp = converters["double"];
converters.Function = convertCallbackFunction;
diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json
index 70876c164..5cc1f1b66 100644
--- a/tools/wpt/expectation.json
+++ b/tools/wpt/expectation.json
@@ -283,12 +283,8 @@
"idlharness.any.html": [
"Performance interface: existence and properties of interface object",
"Performance interface: existence and properties of interface prototype object",
- "Performance interface: operation now()",
"Performance interface: attribute timeOrigin",
- "Performance interface: operation toJSON()",
- "Stringification of performance",
"Performance interface: performance must inherit property \"timeOrigin\" with the proper type",
- "Performance interface: performance must inherit property \"toJSON()\" with the proper type",
"Performance interface: default toJSON operation on performance",
"Window interface: attribute performance"
],
@@ -507,17 +503,7 @@
"clear_one_mark.any.html": true,
"clear_one_measure.any.html": true,
"entry_type.any.html": true,
- "idlharness.any.html": [
- "PerformanceMark interface: attribute detail",
- "PerformanceMeasure interface object length",
- "PerformanceMeasure interface: attribute detail",
- "Performance interface: operation mark(DOMString, optional PerformanceMarkOptions)",
- "Performance interface: operation clearMarks(optional DOMString)",
- "Performance interface: operation measure(DOMString, optional (DOMString or PerformanceMeasureOptions), optional DOMString)",
- "Performance interface: operation clearMeasures(optional DOMString)",
- "Performance interface: calling mark(DOMString, optional PerformanceMarkOptions) on performance with too few arguments must throw TypeError",
- "Performance interface: calling measure(DOMString, optional (DOMString or PerformanceMeasureOptions), optional DOMString) on performance with too few arguments must throw TypeError"
- ],
+ "idlharness.any.html": true,
"mark-entry-constructor.any.html": true,
"mark-errors.any.html": true,
"mark-l3.any.html": false,
@@ -1303,4 +1289,4 @@
"eventhandlers.any.html?wss": false,
"referrer.any.html": true
}
-} \ No newline at end of file
+}