wpt-runner
Version:
Runs web platform tests in Node.js using jsdom
1,681 lines (1,533 loc) • 119 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["WebIDL2"] = factory();
else
root["WebIDL2"] = factory();
})(globalThis, () => {
return /******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ([
/* 0 */,
/* 1 */
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "parse": () => (/* binding */ parse)
/* harmony export */ });
/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var _productions_enum_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(15);
/* harmony import */ var _productions_includes_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(16);
/* harmony import */ var _productions_extended_attributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8);
/* harmony import */ var _productions_typedef_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(17);
/* harmony import */ var _productions_callback_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(18);
/* harmony import */ var _productions_interface_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(19);
/* harmony import */ var _productions_mixin_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(25);
/* harmony import */ var _productions_dictionary_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(26);
/* harmony import */ var _productions_namespace_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(28);
/* harmony import */ var _productions_callback_interface_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(29);
/* harmony import */ var _productions_helpers_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(4);
/* harmony import */ var _productions_token_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(10);
/**
* @param {Tokeniser} tokeniser
* @param {object} options
* @param {boolean} [options.concrete]
* @param {Function[]} [options.productions]
*/
function parseByTokens(tokeniser, options) {
const source = tokeniser.source;
function error(str) {
tokeniser.error(str);
}
function consume(...candidates) {
return tokeniser.consume(...candidates);
}
function callback() {
const callback = consume("callback");
if (!callback) return;
if (tokeniser.probe("interface")) {
return _productions_callback_interface_js__WEBPACK_IMPORTED_MODULE_10__.CallbackInterface.parse(tokeniser, callback);
}
return _productions_callback_js__WEBPACK_IMPORTED_MODULE_5__.CallbackFunction.parse(tokeniser, callback);
}
function interface_(opts) {
const base = consume("interface");
if (!base) return;
const ret =
_productions_mixin_js__WEBPACK_IMPORTED_MODULE_7__.Mixin.parse(tokeniser, base, opts) ||
_productions_interface_js__WEBPACK_IMPORTED_MODULE_6__.Interface.parse(tokeniser, base, opts) ||
error("Interface has no proper body");
return ret;
}
function partial() {
const partial = consume("partial");
if (!partial) return;
return (
_productions_dictionary_js__WEBPACK_IMPORTED_MODULE_8__.Dictionary.parse(tokeniser, { partial }) ||
interface_({ partial }) ||
_productions_namespace_js__WEBPACK_IMPORTED_MODULE_9__.Namespace.parse(tokeniser, { partial }) ||
error("Partial doesn't apply to anything")
);
}
function definition() {
if (options.productions) {
for (const production of options.productions) {
const result = production(tokeniser);
if (result) {
return result;
}
}
}
return (
callback() ||
interface_() ||
partial() ||
_productions_dictionary_js__WEBPACK_IMPORTED_MODULE_8__.Dictionary.parse(tokeniser) ||
_productions_enum_js__WEBPACK_IMPORTED_MODULE_1__.Enum.parse(tokeniser) ||
_productions_typedef_js__WEBPACK_IMPORTED_MODULE_4__.Typedef.parse(tokeniser) ||
_productions_includes_js__WEBPACK_IMPORTED_MODULE_2__.Includes.parse(tokeniser) ||
_productions_namespace_js__WEBPACK_IMPORTED_MODULE_9__.Namespace.parse(tokeniser)
);
}
function definitions() {
if (!source.length) return [];
const defs = [];
while (true) {
const ea = _productions_extended_attributes_js__WEBPACK_IMPORTED_MODULE_3__.ExtendedAttributes.parse(tokeniser);
const def = definition();
if (!def) {
if (ea.length) error("Stray extended attributes");
break;
}
(0,_productions_helpers_js__WEBPACK_IMPORTED_MODULE_11__.autoParenter)(def).extAttrs = ea;
defs.push(def);
}
const eof = _productions_token_js__WEBPACK_IMPORTED_MODULE_12__.Eof.parse(tokeniser);
if (options.concrete) {
defs.push(eof);
}
return defs;
}
const res = definitions();
if (tokeniser.position < source.length) error("Unrecognised tokens");
return res;
}
/**
* @param {string} str
* @param {object} [options]
* @param {*} [options.sourceName]
* @param {boolean} [options.concrete]
* @param {Function[]} [options.productions]
* @return {import("./productions/base.js").Base[]}
*/
function parse(str, options = {}) {
const tokeniser = new _tokeniser_js__WEBPACK_IMPORTED_MODULE_0__.Tokeniser(str);
if (typeof options.sourceName !== "undefined") {
// @ts-ignore (See Tokeniser.source in supplement.d.ts)
tokeniser.source.name = options.sourceName;
}
return parseByTokens(tokeniser, options);
}
/***/ }),
/* 2 */
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "Tokeniser": () => (/* binding */ Tokeniser),
/* harmony export */ "WebIDLParseError": () => (/* binding */ WebIDLParseError),
/* harmony export */ "argumentNameKeywords": () => (/* binding */ argumentNameKeywords),
/* harmony export */ "stringTypes": () => (/* binding */ stringTypes),
/* harmony export */ "typeNameKeywords": () => (/* binding */ typeNameKeywords)
/* harmony export */ });
/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
/* harmony import */ var _productions_helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
// These regular expressions use the sticky flag so they will only match at
// the current location (ie. the offset of lastIndex).
const tokenRe = {
// This expression uses a lookahead assertion to catch false matches
// against integers early.
decimal:
/-?(?=[0-9]*\.|[0-9]+[eE])(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/y,
integer: /-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/y,
identifier: /[_-]?[A-Za-z][0-9A-Z_a-z-]*/y,
string: /"[^"]*"/y,
whitespace: /[\t\n\r ]+/y,
comment: /\/\/.*|\/\*[\s\S]*?\*\//y,
other: /[^\t\n\r 0-9A-Za-z]/y,
};
const typeNameKeywords = [
"ArrayBuffer",
"DataView",
"Int8Array",
"Int16Array",
"Int32Array",
"Uint8Array",
"Uint16Array",
"Uint32Array",
"Uint8ClampedArray",
"BigInt64Array",
"BigUint64Array",
"Float32Array",
"Float64Array",
"any",
"object",
"symbol",
];
const stringTypes = ["ByteString", "DOMString", "USVString"];
const argumentNameKeywords = [
"async",
"attribute",
"callback",
"const",
"constructor",
"deleter",
"dictionary",
"enum",
"getter",
"includes",
"inherit",
"interface",
"iterable",
"maplike",
"namespace",
"partial",
"required",
"setlike",
"setter",
"static",
"stringifier",
"typedef",
"unrestricted",
];
const nonRegexTerminals = [
"-Infinity",
"FrozenArray",
"Infinity",
"NaN",
"ObservableArray",
"Promise",
"bigint",
"boolean",
"byte",
"double",
"false",
"float",
"long",
"mixin",
"null",
"octet",
"optional",
"or",
"readonly",
"record",
"sequence",
"short",
"true",
"undefined",
"unsigned",
"void",
].concat(argumentNameKeywords, stringTypes, typeNameKeywords);
const punctuations = [
"(",
")",
",",
"...",
":",
";",
"<",
"=",
">",
"?",
"*",
"[",
"]",
"{",
"}",
];
const reserved = [
// "constructor" is now a keyword
"_constructor",
"toString",
"_toString",
];
/**
* @typedef {ArrayItemType<ReturnType<typeof tokenise>>} Token
* @param {string} str
*/
function tokenise(str) {
const tokens = [];
let lastCharIndex = 0;
let trivia = "";
let line = 1;
let index = 0;
while (lastCharIndex < str.length) {
const nextChar = str.charAt(lastCharIndex);
let result = -1;
if (/[\t\n\r ]/.test(nextChar)) {
result = attemptTokenMatch("whitespace", { noFlushTrivia: true });
} else if (nextChar === "/") {
result = attemptTokenMatch("comment", { noFlushTrivia: true });
}
if (result !== -1) {
const currentTrivia = tokens.pop().value;
line += (currentTrivia.match(/\n/g) || []).length;
trivia += currentTrivia;
index -= 1;
} else if (/[-0-9.A-Z_a-z]/.test(nextChar)) {
result = attemptTokenMatch("decimal");
if (result === -1) {
result = attemptTokenMatch("integer");
}
if (result === -1) {
result = attemptTokenMatch("identifier");
const lastIndex = tokens.length - 1;
const token = tokens[lastIndex];
if (result !== -1) {
if (reserved.includes(token.value)) {
const message = `${(0,_productions_helpers_js__WEBPACK_IMPORTED_MODULE_1__.unescape)(
token.value
)} is a reserved identifier and must not be used.`;
throw new WebIDLParseError(
(0,_error_js__WEBPACK_IMPORTED_MODULE_0__.syntaxError)(tokens, lastIndex, null, message)
);
} else if (nonRegexTerminals.includes(token.value)) {
token.type = "inline";
}
}
}
} else if (nextChar === '"') {
result = attemptTokenMatch("string");
}
for (const punctuation of punctuations) {
if (str.startsWith(punctuation, lastCharIndex)) {
tokens.push({
type: "inline",
value: punctuation,
trivia,
line,
index,
});
trivia = "";
lastCharIndex += punctuation.length;
result = lastCharIndex;
break;
}
}
// other as the last try
if (result === -1) {
result = attemptTokenMatch("other");
}
if (result === -1) {
throw new Error("Token stream not progressing");
}
lastCharIndex = result;
index += 1;
}
// remaining trivia as eof
tokens.push({
type: "eof",
value: "",
trivia,
line,
index,
});
return tokens;
/**
* @param {keyof typeof tokenRe} type
* @param {object} options
* @param {boolean} [options.noFlushTrivia]
*/
function attemptTokenMatch(type, { noFlushTrivia } = {}) {
const re = tokenRe[type];
re.lastIndex = lastCharIndex;
const result = re.exec(str);
if (result) {
tokens.push({ type, value: result[0], trivia, line, index });
if (!noFlushTrivia) {
trivia = "";
}
return re.lastIndex;
}
return -1;
}
}
class Tokeniser {
/**
* @param {string} idl
*/
constructor(idl) {
this.source = tokenise(idl);
this.position = 0;
}
/**
* @param {string} message
* @return {never}
*/
error(message) {
throw new WebIDLParseError(
(0,_error_js__WEBPACK_IMPORTED_MODULE_0__.syntaxError)(this.source, this.position, this.current, message)
);
}
/**
* @param {string} type
*/
probeKind(type) {
return (
this.source.length > this.position &&
this.source[this.position].type === type
);
}
/**
* @param {string} value
*/
probe(value) {
return (
this.probeKind("inline") && this.source[this.position].value === value
);
}
/**
* @param {...string} candidates
*/
consumeKind(...candidates) {
for (const type of candidates) {
if (!this.probeKind(type)) continue;
const token = this.source[this.position];
this.position++;
return token;
}
}
/**
* @param {...string} candidates
*/
consume(...candidates) {
if (!this.probeKind("inline")) return;
const token = this.source[this.position];
for (const value of candidates) {
if (token.value !== value) continue;
this.position++;
return token;
}
}
/**
* @param {string} value
*/
consumeIdentifier(value) {
if (!this.probeKind("identifier")) {
return;
}
if (this.source[this.position].value !== value) {
return;
}
return this.consumeKind("identifier");
}
/**
* @param {number} position
*/
unconsume(position) {
this.position = position;
}
}
class WebIDLParseError extends Error {
/**
* @param {object} options
* @param {string} options.message
* @param {string} options.bareMessage
* @param {string} options.context
* @param {number} options.line
* @param {*} options.sourceName
* @param {string} options.input
* @param {*[]} options.tokens
*/
constructor({
message,
bareMessage,
context,
line,
sourceName,
input,
tokens,
}) {
super(message);
this.name = "WebIDLParseError"; // not to be mangled
this.bareMessage = bareMessage;
this.context = context;
this.line = line;
this.sourceName = sourceName;
this.input = input;
this.tokens = tokens;
}
}
/***/ }),
/* 3 */
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "syntaxError": () => (/* binding */ syntaxError),
/* harmony export */ "validationError": () => (/* binding */ validationError)
/* harmony export */ });
/**
* @param {string} text
*/
function lastLine(text) {
const splitted = text.split("\n");
return splitted[splitted.length - 1];
}
function appendIfExist(base, target) {
let result = base;
if (target) {
result += ` ${target}`;
}
return result;
}
function contextAsText(node) {
const hierarchy = [node];
while (node && node.parent) {
const { parent } = node;
hierarchy.unshift(parent);
node = parent;
}
return hierarchy.map((n) => appendIfExist(n.type, n.name)).join(" -> ");
}
/**
* @typedef {object} WebIDL2ErrorOptions
* @property {"error" | "warning"} [level]
* @property {Function} [autofix]
* @property {string} [ruleName]
*
* @typedef {ReturnType<typeof error>} WebIDLErrorData
*
* @param {string} message error message
* @param {*} position
* @param {*} current
* @param {*} message
* @param {"Syntax" | "Validation"} kind error type
* @param {WebIDL2ErrorOptions=} options
*/
function error(
source,
position,
current,
message,
kind,
{ level = "error", autofix, ruleName } = {}
) {
/**
* @param {number} count
*/
function sliceTokens(count) {
return count > 0
? source.slice(position, position + count)
: source.slice(Math.max(position + count, 0), position);
}
/**
* @param {import("./tokeniser.js").Token[]} inputs
* @param {object} [options]
* @param {boolean} [options.precedes]
* @returns
*/
function tokensToText(inputs, { precedes } = {}) {
const text = inputs.map((t) => t.trivia + t.value).join("");
const nextToken = source[position];
if (nextToken.type === "eof") {
return text;
}
if (precedes) {
return text + nextToken.trivia;
}
return text.slice(nextToken.trivia.length);
}
const maxTokens = 5; // arbitrary but works well enough
const line =
source[position].type !== "eof"
? source[position].line
: source.length > 1
? source[position - 1].line
: 1;
const precedingLastLine = lastLine(
tokensToText(sliceTokens(-maxTokens), { precedes: true })
);
const subsequentTokens = sliceTokens(maxTokens);
const subsequentText = tokensToText(subsequentTokens);
const subsequentFirstLine = subsequentText.split("\n")[0];
const spaced = " ".repeat(precedingLastLine.length) + "^";
const sourceContext = precedingLastLine + subsequentFirstLine + "\n" + spaced;
const contextType = kind === "Syntax" ? "since" : "inside";
const inSourceName = source.name ? ` in ${source.name}` : "";
const grammaticalContext =
current && current.name
? `, ${contextType} \`${current.partial ? "partial " : ""}${contextAsText(
current
)}\``
: "";
const context = `${kind} error at line ${line}${inSourceName}${grammaticalContext}:\n${sourceContext}`;
return {
message: `${context} ${message}`,
bareMessage: message,
context,
line,
sourceName: source.name,
level,
ruleName,
autofix,
input: subsequentText,
tokens: subsequentTokens,
};
}
/**
* @param {string} message error message
*/
function syntaxError(source, position, current, message) {
return error(source, position, current, message, "Syntax");
}
/**
* @param {string} message error message
* @param {WebIDL2ErrorOptions} [options]
*/
function validationError(
token,
current,
ruleName,
message,
options = {}
) {
options.ruleName = ruleName;
return error(
current.source,
token.index,
current,
message,
"Validation",
options
);
}
/***/ }),
/* 4 */
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "argument_list": () => (/* binding */ argument_list),
/* harmony export */ "autoParenter": () => (/* binding */ autoParenter),
/* harmony export */ "autofixAddExposedWindow": () => (/* binding */ autofixAddExposedWindow),
/* harmony export */ "const_data": () => (/* binding */ const_data),
/* harmony export */ "const_value": () => (/* binding */ const_value),
/* harmony export */ "findLastIndex": () => (/* binding */ findLastIndex),
/* harmony export */ "getFirstToken": () => (/* binding */ getFirstToken),
/* harmony export */ "getLastIndentation": () => (/* binding */ getLastIndentation),
/* harmony export */ "getMemberIndentation": () => (/* binding */ getMemberIndentation),
/* harmony export */ "list": () => (/* binding */ list),
/* harmony export */ "primitive_type": () => (/* binding */ primitive_type),
/* harmony export */ "return_type": () => (/* binding */ return_type),
/* harmony export */ "stringifier": () => (/* binding */ stringifier),
/* harmony export */ "type_with_extended_attributes": () => (/* binding */ type_with_extended_attributes),
/* harmony export */ "unescape": () => (/* binding */ unescape)
/* harmony export */ });
/* harmony import */ var _type_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5);
/* harmony import */ var _argument_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
/* harmony import */ var _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8);
/* harmony import */ var _operation_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13);
/* harmony import */ var _attribute_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(14);
/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(2);
/**
* @param {string} identifier
*/
function unescape(identifier) {
return identifier.startsWith("_") ? identifier.slice(1) : identifier;
}
/**
* Parses comma-separated list
* @param {import("../tokeniser.js").Tokeniser} tokeniser
* @param {object} args
* @param {Function} args.parser parser function for each item
* @param {boolean} [args.allowDangler] whether to allow dangling comma
* @param {string} [args.listName] the name to be shown on error messages
*/
function list(tokeniser, { parser, allowDangler, listName = "list" }) {
const first = parser(tokeniser);
if (!first) {
return [];
}
first.tokens.separator = tokeniser.consume(",");
const items = [first];
while (first.tokens.separator) {
const item = parser(tokeniser);
if (!item) {
if (!allowDangler) {
tokeniser.error(`Trailing comma in ${listName}`);
}
break;
}
item.tokens.separator = tokeniser.consume(",");
items.push(item);
if (!item.tokens.separator) break;
}
return items;
}
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
*/
function const_value(tokeniser) {
return (
tokeniser.consumeKind("decimal", "integer") ||
tokeniser.consume("true", "false", "Infinity", "-Infinity", "NaN")
);
}
/**
* @param {object} token
* @param {string} token.type
* @param {string} token.value
*/
function const_data({ type, value }) {
switch (type) {
case "decimal":
case "integer":
return { type: "number", value };
case "string":
return { type: "string", value: value.slice(1, -1) };
}
switch (value) {
case "true":
case "false":
return { type: "boolean", value: value === "true" };
case "Infinity":
case "-Infinity":
return { type: "Infinity", negative: value.startsWith("-") };
case "[":
return { type: "sequence", value: [] };
case "{":
return { type: "dictionary" };
default:
return { type: value };
}
}
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
*/
function primitive_type(tokeniser) {
function integer_type() {
const prefix = tokeniser.consume("unsigned");
const base = tokeniser.consume("short", "long");
if (base) {
const postfix = tokeniser.consume("long");
return new _type_js__WEBPACK_IMPORTED_MODULE_0__.Type({ source, tokens: { prefix, base, postfix } });
}
if (prefix) tokeniser.error("Failed to parse integer type");
}
function decimal_type() {
const prefix = tokeniser.consume("unrestricted");
const base = tokeniser.consume("float", "double");
if (base) {
return new _type_js__WEBPACK_IMPORTED_MODULE_0__.Type({ source, tokens: { prefix, base } });
}
if (prefix) tokeniser.error("Failed to parse float type");
}
const { source } = tokeniser;
const num_type = integer_type() || decimal_type();
if (num_type) return num_type;
const base = tokeniser.consume(
"bigint",
"boolean",
"byte",
"octet",
"undefined"
);
if (base) {
return new _type_js__WEBPACK_IMPORTED_MODULE_0__.Type({ source, tokens: { base } });
}
}
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
*/
function argument_list(tokeniser) {
return list(tokeniser, {
parser: _argument_js__WEBPACK_IMPORTED_MODULE_1__.Argument.parse,
listName: "arguments list",
});
}
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
* @param {string=} typeName (TODO: See Type.type for more details)
*/
function type_with_extended_attributes(tokeniser, typeName) {
const extAttrs = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__.ExtendedAttributes.parse(tokeniser);
const ret = _type_js__WEBPACK_IMPORTED_MODULE_0__.Type.parse(tokeniser, typeName);
if (ret) autoParenter(ret).extAttrs = extAttrs;
return ret;
}
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
* @param {string=} typeName (TODO: See Type.type for more details)
*/
function return_type(tokeniser, typeName) {
const typ = _type_js__WEBPACK_IMPORTED_MODULE_0__.Type.parse(tokeniser, typeName || "return-type");
if (typ) {
return typ;
}
const voidToken = tokeniser.consume("void");
if (voidToken) {
const ret = new _type_js__WEBPACK_IMPORTED_MODULE_0__.Type({
source: tokeniser.source,
tokens: { base: voidToken },
});
ret.type = "return-type";
return ret;
}
}
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
*/
function stringifier(tokeniser) {
const special = tokeniser.consume("stringifier");
if (!special) return;
const member =
_attribute_js__WEBPACK_IMPORTED_MODULE_4__.Attribute.parse(tokeniser, { special }) ||
_operation_js__WEBPACK_IMPORTED_MODULE_3__.Operation.parse(tokeniser, { special }) ||
tokeniser.error("Unterminated stringifier");
return member;
}
/**
* @param {string} str
*/
function getLastIndentation(str) {
const lines = str.split("\n");
// the first line visually binds to the preceding token
if (lines.length) {
const match = lines[lines.length - 1].match(/^\s+/);
if (match) {
return match[0];
}
}
return "";
}
/**
* @param {string} parentTrivia
*/
function getMemberIndentation(parentTrivia) {
const indentation = getLastIndentation(parentTrivia);
const indentCh = indentation.includes("\t") ? "\t" : " ";
return indentation + indentCh;
}
/**
* @param {import("./interface.js").Interface} def
*/
function autofixAddExposedWindow(def) {
return () => {
if (def.extAttrs.length) {
const tokeniser = new _tokeniser_js__WEBPACK_IMPORTED_MODULE_5__.Tokeniser("Exposed=Window,");
const exposed = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__.SimpleExtendedAttribute.parse(tokeniser);
exposed.tokens.separator = tokeniser.consume(",");
const existing = def.extAttrs[0];
if (!/^\s/.test(existing.tokens.name.trivia)) {
existing.tokens.name.trivia = ` ${existing.tokens.name.trivia}`;
}
def.extAttrs.unshift(exposed);
} else {
autoParenter(def).extAttrs = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__.ExtendedAttributes.parse(
new _tokeniser_js__WEBPACK_IMPORTED_MODULE_5__.Tokeniser("[Exposed=Window]")
);
const trivia = def.tokens.base.trivia;
def.extAttrs.tokens.open.trivia = trivia;
def.tokens.base.trivia = `\n${getLastIndentation(trivia)}`;
}
};
}
/**
* Get the first syntax token for the given IDL object.
* @param {*} data
*/
function getFirstToken(data) {
if (data.extAttrs.length) {
return data.extAttrs.tokens.open;
}
if (data.type === "operation" && !data.special) {
return getFirstToken(data.idlType);
}
const tokens = Object.values(data.tokens).sort((x, y) => x.index - y.index);
return tokens[0];
}
/**
* @template T
* @param {T[]} array
* @param {(item: T) => boolean} predicate
*/
function findLastIndex(array, predicate) {
const index = array.slice().reverse().findIndex(predicate);
if (index === -1) {
return index;
}
return array.length - index - 1;
}
/**
* Returns a proxy that auto-assign `parent` field.
* @template {Record<string | symbol, any>} T
* @param {T} data
* @param {*} [parent] The object that will be assigned to `parent`.
* If absent, it will be `data` by default.
* @return {T}
*/
function autoParenter(data, parent) {
if (!parent) {
// Defaults to `data` unless specified otherwise.
parent = data;
}
if (!data) {
// This allows `autoParenter(undefined)` which again allows
// `autoParenter(parse())` where the function may return nothing.
return data;
}
const proxy = new Proxy(data, {
get(target, p) {
const value = target[p];
if (Array.isArray(value) && p !== "source") {
// Wraps the array so that any added items will also automatically
// get their `parent` values.
return autoParenter(value, target);
}
return value;
},
set(target, p, value) {
// @ts-ignore https://github.com/microsoft/TypeScript/issues/47357
target[p] = value;
if (!value) {
return true;
} else if (Array.isArray(value)) {
// Assigning an array will add `parent` to its items.
for (const item of value) {
if (typeof item.parent !== "undefined") {
item.parent = parent;
}
}
} else if (typeof value.parent !== "undefined") {
value.parent = parent;
}
return true;
},
});
return proxy;
}
/***/ }),
/* 5 */
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "Type": () => (/* binding */ Type)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3);
/* harmony import */ var _validators_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(7);
/* harmony import */ var _extended_attributes_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(8);
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
* @param {string} typeName
*/
function generic_type(tokeniser, typeName) {
const base = tokeniser.consume(
"FrozenArray",
"ObservableArray",
"Promise",
"sequence",
"record"
);
if (!base) {
return;
}
const ret = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.autoParenter)(
new Type({ source: tokeniser.source, tokens: { base } })
);
ret.tokens.open =
tokeniser.consume("<") ||
tokeniser.error(`No opening bracket after ${base.value}`);
switch (base.value) {
case "Promise": {
if (tokeniser.probe("["))
tokeniser.error("Promise type cannot have extended attribute");
const subtype =
(0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.return_type)(tokeniser, typeName) ||
tokeniser.error("Missing Promise subtype");
ret.subtype.push(subtype);
break;
}
case "sequence":
case "FrozenArray":
case "ObservableArray": {
const subtype =
(0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.type_with_extended_attributes)(tokeniser, typeName) ||
tokeniser.error(`Missing ${base.value} subtype`);
ret.subtype.push(subtype);
break;
}
case "record": {
if (tokeniser.probe("["))
tokeniser.error("Record key cannot have extended attribute");
const keyType =
tokeniser.consume(..._tokeniser_js__WEBPACK_IMPORTED_MODULE_2__.stringTypes) ||
tokeniser.error(`Record key must be one of: ${_tokeniser_js__WEBPACK_IMPORTED_MODULE_2__.stringTypes.join(", ")}`);
const keyIdlType = new Type({
source: tokeniser.source,
tokens: { base: keyType },
});
keyIdlType.tokens.separator =
tokeniser.consume(",") ||
tokeniser.error("Missing comma after record key type");
keyIdlType.type = typeName;
const valueType =
(0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.type_with_extended_attributes)(tokeniser, typeName) ||
tokeniser.error("Error parsing generic type record");
ret.subtype.push(keyIdlType, valueType);
break;
}
}
if (!ret.idlType) tokeniser.error(`Error parsing generic type ${base.value}`);
ret.tokens.close =
tokeniser.consume(">") ||
tokeniser.error(`Missing closing bracket after ${base.value}`);
return ret.this;
}
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
*/
function type_suffix(tokeniser, obj) {
const nullable = tokeniser.consume("?");
if (nullable) {
obj.tokens.nullable = nullable;
}
if (tokeniser.probe("?")) tokeniser.error("Can't nullable more than once");
}
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
* @param {string} typeName
*/
function single_type(tokeniser, typeName) {
let ret = generic_type(tokeniser, typeName) || (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.primitive_type)(tokeniser);
if (!ret) {
const base =
tokeniser.consumeKind("identifier") ||
tokeniser.consume(..._tokeniser_js__WEBPACK_IMPORTED_MODULE_2__.stringTypes, ..._tokeniser_js__WEBPACK_IMPORTED_MODULE_2__.typeNameKeywords);
if (!base) {
return;
}
ret = new Type({ source: tokeniser.source, tokens: { base } });
if (tokeniser.probe("<"))
tokeniser.error(`Unsupported generic type ${base.value}`);
}
if (ret.generic === "Promise" && tokeniser.probe("?")) {
tokeniser.error("Promise type cannot be nullable");
}
ret.type = typeName || null;
type_suffix(tokeniser, ret);
if (ret.nullable && ret.idlType === "any")
tokeniser.error("Type `any` cannot be made nullable");
return ret;
}
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
* @param {string} type
*/
function union_type(tokeniser, type) {
const tokens = {};
tokens.open = tokeniser.consume("(");
if (!tokens.open) return;
const ret = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.autoParenter)(new Type({ source: tokeniser.source, tokens }));
ret.type = type || null;
while (true) {
const typ =
(0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.type_with_extended_attributes)(tokeniser) ||
tokeniser.error("No type after open parenthesis or 'or' in union type");
if (typ.idlType === "any")
tokeniser.error("Type `any` cannot be included in a union type");
if (typ.generic === "Promise")
tokeniser.error("Type `Promise` cannot be included in a union type");
ret.subtype.push(typ);
const or = tokeniser.consume("or");
if (or) {
typ.tokens.separator = or;
} else break;
}
if (ret.idlType.length < 2) {
tokeniser.error(
"At least two types are expected in a union type but found less"
);
}
tokens.close =
tokeniser.consume(")") || tokeniser.error("Unterminated union type");
type_suffix(tokeniser, ret);
return ret.this;
}
class Type extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
* @param {string} typeName
*/
static parse(tokeniser, typeName) {
return single_type(tokeniser, typeName) || union_type(tokeniser, typeName);
}
constructor({ source, tokens }) {
super({ source, tokens });
Object.defineProperty(this, "subtype", { value: [], writable: true });
this.extAttrs = new _extended_attributes_js__WEBPACK_IMPORTED_MODULE_5__.ExtendedAttributes({ source, tokens: {} });
}
get generic() {
if (this.subtype.length && this.tokens.base) {
return this.tokens.base.value;
}
return "";
}
get nullable() {
return Boolean(this.tokens.nullable);
}
get union() {
return Boolean(this.subtype.length) && !this.tokens.base;
}
get idlType() {
if (this.subtype.length) {
return this.subtype;
}
// Adding prefixes/postfixes for "unrestricted float", etc.
const name = [this.tokens.prefix, this.tokens.base, this.tokens.postfix]
.filter((t) => t)
.map((t) => t.value)
.join(" ");
return (0,_helpers_js__WEBPACK_IMPORTED_MODULE_1__.unescape)(name);
}
*validate(defs) {
yield* this.extAttrs.validate(defs);
if (this.idlType === "void") {
const message = `\`void\` is now replaced by \`undefined\`. Refer to the \
[relevant GitHub issue](https://github.com/whatwg/webidl/issues/60) \
for more information.`;
yield (0,_error_js__WEBPACK_IMPORTED_MODULE_3__.validationError)(this.tokens.base, this, "replace-void", message, {
autofix: replaceVoid(this),
});
}
/*
* If a union is nullable, its subunions cannot include a dictionary
* If not, subunions may include dictionaries if each union is not nullable
*/
const typedef = !this.union && defs.unique.get(this.idlType);
const target = this.union
? this
: typedef && typedef.type === "typedef"
? typedef.idlType
: undefined;
if (target && this.nullable) {
// do not allow any dictionary
const { reference } = (0,_validators_helpers_js__WEBPACK_IMPORTED_MODULE_4__.idlTypeIncludesDictionary)(target, defs) || {};
if (reference) {
const targetToken = (this.union ? reference : this).tokens.base;
const message = "Nullable union cannot include a dictionary type.";
yield (0,_error_js__WEBPACK_IMPORTED_MODULE_3__.validationError)(
targetToken,
this,
"no-nullable-union-dict",
message
);
}
} else {
// allow some dictionary
for (const subtype of this.subtype) {
yield* subtype.validate(defs);
}
}
}
/** @param {import("../writer.js").Writer} w */
write(w) {
const type_body = () => {
if (this.union || this.generic) {
return w.ts.wrap([
w.token(this.tokens.base, w.ts.generic),
w.token(this.tokens.open),
...this.subtype.map((t) => t.write(w)),
w.token(this.tokens.close),
]);
}
const firstToken = this.tokens.prefix || this.tokens.base;
const prefix = this.tokens.prefix
? [this.tokens.prefix.value, w.ts.trivia(this.tokens.base.trivia)]
: [];
const ref = w.reference(
w.ts.wrap([
...prefix,
this.tokens.base.value,
w.token(this.tokens.postfix),
]),
{
unescaped: /** @type {string} (because it's not union) */ (
this.idlType
),
context: this,
}
);
return w.ts.wrap([w.ts.trivia(firstToken.trivia), ref]);
};
return w.ts.wrap([
this.extAttrs.write(w),
type_body(),
w.token(this.tokens.nullable),
w.token(this.tokens.separator),
]);
}
}
/**
* @param {Type} type
*/
function replaceVoid(type) {
return () => {
type.tokens.base.value = "undefined";
};
}
/***/ }),
/* 6 */
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "Base": () => (/* binding */ Base)
/* harmony export */ });
class Base {
/**
* @param {object} initializer
* @param {Base["source"]} initializer.source
* @param {Base["tokens"]} initializer.tokens
*/
constructor({ source, tokens }) {
Object.defineProperties(this, {
source: { value: source },
tokens: { value: tokens, writable: true },
parent: { value: null, writable: true },
this: { value: this }, // useful when escaping from proxy
});
}
toJSON() {
const json = { type: undefined, name: undefined, inheritance: undefined };
let proto = this;
while (proto !== Object.prototype) {
const descMap = Object.getOwnPropertyDescriptors(proto);
for (const [key, value] of Object.entries(descMap)) {
if (value.enumerable || value.get) {
// @ts-ignore - allow indexing here
json[key] = this[key];
}
}
proto = Object.getPrototypeOf(proto);
}
return json;
}
}
/***/ }),
/* 7 */
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "dictionaryIncludesRequiredField": () => (/* binding */ dictionaryIncludesRequiredField),
/* harmony export */ "idlTypeIncludesDictionary": () => (/* binding */ idlTypeIncludesDictionary)
/* harmony export */ });
/**
* @typedef {import("../productions/dictionary.js").Dictionary} Dictionary
*
* @param {*} idlType
* @param {import("../validator.js").Definitions} defs
* @param {object} [options]
* @param {boolean} [options.useNullableInner] use when the input idlType is nullable and you want to use its inner type
* @return {{ reference: *, dictionary: Dictionary }} the type reference that ultimately includes dictionary.
*/
function idlTypeIncludesDictionary(
idlType,
defs,
{ useNullableInner } = {}
) {
if (!idlType.union) {
const def = defs.unique.get(idlType.idlType);
if (!def) {
return;
}
if (def.type === "typedef") {
const { typedefIncludesDictionary } = defs.cache;
if (typedefIncludesDictionary.has(def)) {
// Note that this also halts when it met indeterminate state
// to prevent infinite recursion
return typedefIncludesDictionary.get(def);
}
defs.cache.typedefIncludesDictionary.set(def, undefined); // indeterminate state
const result = idlTypeIncludesDictionary(def.idlType, defs);
defs.cache.typedefIncludesDictionary.set(def, result);
if (result) {
return {
reference: idlType,
dictionary: result.dictionary,
};
}
}
if (def.type === "dictionary" && (useNullableInner || !idlType.nullable)) {
return {
reference: idlType,
dictionary: def,
};
}
}
for (const subtype of idlType.subtype) {
const result = idlTypeIncludesDictionary(subtype, defs);
if (result) {
if (subtype.union) {
return result;
}
return {
reference: subtype,
dictionary: result.dictionary,
};
}
}
}
/**
* @param {*} dict dictionary type
* @param {import("../validator.js").Definitions} defs
* @return {boolean}
*/
function dictionaryIncludesRequiredField(dict, defs) {
if (defs.cache.dictionaryIncludesRequiredField.has(dict)) {
return defs.cache.dictionaryIncludesRequiredField.get(dict);
}
// Set cached result to indeterminate to short-circuit circular definitions.
// The final result will be updated to true or false.
defs.cache.dictionaryIncludesRequiredField.set(dict, undefined);
let result = dict.members.some((field) => field.required);
if (!result && dict.inheritance) {
const superdict = defs.unique.get(dict.inheritance);
if (!superdict) {
// Assume required members in the supertype if it is unknown.
result = true;
} else if (dictionaryIncludesRequiredField(superdict, defs)) {
result = true;
}
}
defs.cache.dictionaryIncludesRequiredField.set(dict, result);
return result;
}
/***/ }),
/* 8 */
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "ExtendedAttributeParameters": () => (/* binding */ ExtendedAttributeParameters),
/* harmony export */ "ExtendedAttributes": () => (/* binding */ ExtendedAttributes),
/* harmony export */ "SimpleExtendedAttribute": () => (/* binding */ SimpleExtendedAttribute)
/* harmony export */ });
/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
/* harmony import */ var _array_base_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9);
/* harmony import */ var _token_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(10);
/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(3);
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
* @param {string} tokenName
*/
function tokens(tokeniser, tokenName) {
return (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.list)(tokeniser, {
parser: _token_js__WEBPACK_IMPORTED_MODULE_2__.WrappedToken.parser(tokeniser, tokenName),
listName: tokenName + " list",
});
}
const extAttrValueSyntax = ["identifier", "decimal", "integer", "string"];
const shouldBeLegacyPrefixed = [
"NoInterfaceObject",
"LenientSetter",
"LenientThis",
"TreatNonObjectAsNull",
"Unforgeable",
];
const renamedLegacies = new Map([
.../** @type {[string, string][]} */ (
shouldBeLegacyPrefixed.map((name) => [name, `Legacy${name}`])
),
["NamedConstructor", "LegacyFactoryFunction"],
["OverrideBuiltins", "LegacyOverrideBuiltIns"],
["TreatNullAs", "LegacyNullToEmptyString"],
]);
/**
* This will allow a set of extended attribute values to be parsed.
* @param {import("../tokeniser.js").Tokeniser} tokeniser
*/
function extAttrListItems(tokeniser) {
for (const syntax of extAttrValueSyntax) {
const toks = tokens(tokeniser, syntax);
if (toks.length) {
return toks;
}
}
tokeniser.error(
`Expected identifiers, strings, decimals, or integers but none found`
);
}
class ExtendedAttributeParameters extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
*/
static parse(tokeniser) {
const tokens = { assign: tokeniser.consume("=") };
const ret = (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.autoParenter)(
new ExtendedAttributeParameters({ source: tokeniser.source, tokens })
);
ret.list = [];
if (tokens.assign) {
tokens.asterisk = tokeniser.consume("*");
if (tokens.asterisk) {
return ret.this;
}
tokens.secondaryName = tokeniser.consumeKind(...extAttrValueSyntax);
}
tokens.open = tokeniser.consume("(");
if (tokens.open) {
ret.list = ret.rhsIsList
? // [Exposed=(Window,Worker)]
extAttrListItems(tokeniser)
: // [LegacyFactoryFunction=Audio(DOMString src)] or [Constructor(DOMString str)]
(0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.argument_list)(tokeniser);
tokens.close =
tokeniser.consume(")") ||
tokeniser.error("Unexpected token in extended attribute argument list");
} else if (tokens.assign && !tokens.secondaryName) {
tokeniser.error("No right hand side to extended attribute assignment");
}
return ret.this;
}
get rhsIsList() {
return (
this.tokens.assign && !this.tokens.asterisk && !this.tokens.secondaryName
);
}
get rhsType() {
if (this.rhsIsList) {
return this.list[0].tokens.value.type + "-list";
}
if (this.tokens.asterisk) {
return "*";
}
if (this.tokens.secondaryName) {
return this.tokens.secondaryName.type;
}
return null;
}
/** @param {import("../writer.js").Writer} w */
write(w) {
const { rhsType } = this;
return w.ts.wrap([
w.token(this.tokens.assign),
w.token(this.tokens.asterisk),
w.reference_token(this.tokens.secondaryName, this.parent),
w.token(this.tokens.open),
...this.list.map((p) => {
return rhsType === "identifier-list"
? w.identifier(p, this.parent)
: p.write(w);
}),
w.token(this.tokens.close),
]);
}
}
class SimpleExtendedAttribute extends _base_js__WEBPACK_IMPORTED_MODULE_0__.Base {
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
*/
static parse(tokeniser) {
const name = tokeniser.consumeKind("identifier");
if (name) {
return new SimpleExtendedAttribute({
source: tokeniser.source,
tokens: { name },
params: ExtendedAttributeParameters.parse(tokeniser),
});
}
}
constructor({ source, tokens, params }) {
super({ source, tokens });
params.parent = this;
Object.defineProperty(this, "params", { value: params });
}
get type() {
return "extended-attribute";
}
get name() {
return this.tokens.name.value;
}
get rhs() {
const { rhsType: type, tokens, list } = this.params;
if (!type) {
return null;
}
const value = this.params.rhsIsList
? list
: this.params.tokens.secondaryName
? (0,_helpers_js__WEBPACK_IMPORTED_MODULE_3__.unescape)(tokens.secondaryName.value)
: null;
return { type, value };
}
get arguments() {
const { rhsIsList, list } = this.params;
if (!list || rhsIsList) {
return [];
}
return list;
}
*validate(defs) {
const { name } = this;
if (name === "LegacyNoInterfaceObject") {
const message = `\`[LegacyNoInterfaceObject]\` extended attribute is an \
undesirable feature that may be removed from Web IDL in the future. Refer to the \
[relevant upstream PR](https://github.com/whatwg/webidl/pull/609) for more \
information.`;
yield (0,_error_js__WEBPACK_IMPORTED_MODULE_4__.validationError)(
this.tokens.name,
this,
"no-nointerfaceobject",
message,
{ level: "warning" }
);
} else if (renamedLegacies.has(name)) {
const message = `\`[${name}]\` extended attribute is a legacy feature \
that is now renamed to \`[${renamedLegacies.get(name)}]\`. Refer to the \
[relevant upstream PR](https://github.com/whatwg/webidl/pull/870) for more \
information.`;
yield (0,_error_js__WEBPACK_IMPORTED_MODULE_4__.validationError)(this.tokens.name, this, "renamed-legacy", message, {
level: "warning",
autofix: renameLegacyExtendedAttribute(this),
});
}
for (const arg of this.arguments) {
yield* arg.validate(defs);
}
}
/** @param {import("../writer.js").Writer} w */
write(w) {
return w.ts.wrap([
w.ts.trivia(this.tokens.name.trivia),
w.ts.extendedAttribute(
w.ts.wrap([
w.ts.extendedAttributeReference(this.name),
this.params.write(w),
])
),
w.token(this.tokens.separator),
]);
}
}
/**
* @param {SimpleExtendedAttribute} extAttr
*/
function renameLegacyExtendedAttribute(extAttr) {
return () => {
const { name } = extAttr;
extAttr.tokens.name.value = renamedLegacies.get(name);
if (name === "TreatNullAs") {
extAttr.params.tokens = {};
}
};
}
// Note: we parse something simpler than the official syntax. It's all that ever
// seems to be used
class ExtendedAttributes extends _array_base_js__WEBPACK_IMPORTED_MODULE_1__.ArrayBase {
/**
* @param {import("../tokeniser.js").Tokeniser} tokeniser
*/
static parse(tokenise