mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-07 12:33:47 +08:00
This change makes it easier to run the script from directly `roll_py.deps` without having to fetch the dependencies first. This also makes it easier to track which dependencies our tooling have. Change-Id: I1ce55074ee6a1fffa6f2a2f05a56d0d74b4aca90 Bug: 1255619 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/3431346 Reviewed-by: Mathias Bynens <mathias@chromium.org> Commit-Queue: Johan Bay <jobay@chromium.org>
124 lines
3.4 KiB
JavaScript
124 lines
3.4 KiB
JavaScript
// @ts-check
|
|
|
|
import { validationError } from "../error.js";
|
|
import { idlTypeIncludesDictionary } from "../validators/helpers.js";
|
|
import { Base } from "./base.js";
|
|
import {
|
|
type_with_extended_attributes,
|
|
unescape,
|
|
autoParenter,
|
|
} from "./helpers.js";
|
|
|
|
export class Attribute extends Base {
|
|
/**
|
|
* @param {import("../tokeniser.js").Tokeniser} tokeniser
|
|
* @param {object} [options]
|
|
* @param {import("../tokeniser.js").Token} [options.special]
|
|
* @param {boolean} [options.noInherit]
|
|
* @param {boolean} [options.readonly]
|
|
*/
|
|
static parse(
|
|
tokeniser,
|
|
{ special, noInherit = false, readonly = false } = {}
|
|
) {
|
|
const start_position = tokeniser.position;
|
|
const tokens = { special };
|
|
const ret = autoParenter(
|
|
new Attribute({ source: tokeniser.source, tokens })
|
|
);
|
|
if (!special && !noInherit) {
|
|
tokens.special = tokeniser.consume("inherit");
|
|
}
|
|
if (ret.special === "inherit" && tokeniser.probe("readonly")) {
|
|
tokeniser.error("Inherited attributes cannot be read-only");
|
|
}
|
|
tokens.readonly = tokeniser.consume("readonly");
|
|
if (readonly && !tokens.readonly && tokeniser.probe("attribute")) {
|
|
tokeniser.error("Attributes must be readonly in this context");
|
|
}
|
|
tokens.base = tokeniser.consume("attribute");
|
|
if (!tokens.base) {
|
|
tokeniser.unconsume(start_position);
|
|
return;
|
|
}
|
|
ret.idlType =
|
|
type_with_extended_attributes(tokeniser, "attribute-type") ||
|
|
tokeniser.error("Attribute lacks a type");
|
|
tokens.name =
|
|
tokeniser.consumeKind("identifier") ||
|
|
tokeniser.consume("async", "required") ||
|
|
tokeniser.error("Attribute lacks a name");
|
|
tokens.termination =
|
|
tokeniser.consume(";") ||
|
|
tokeniser.error("Unterminated attribute, expected `;`");
|
|
return ret.this;
|
|
}
|
|
|
|
get type() {
|
|
return "attribute";
|
|
}
|
|
get special() {
|
|
if (!this.tokens.special) {
|
|
return "";
|
|
}
|
|
return this.tokens.special.value;
|
|
}
|
|
get readonly() {
|
|
return !!this.tokens.readonly;
|
|
}
|
|
get name() {
|
|
return unescape(this.tokens.name.value);
|
|
}
|
|
|
|
*validate(defs) {
|
|
yield* this.extAttrs.validate(defs);
|
|
yield* this.idlType.validate(defs);
|
|
|
|
switch (this.idlType.generic) {
|
|
case "sequence":
|
|
case "record": {
|
|
const message = `Attributes cannot accept ${this.idlType.generic} types.`;
|
|
yield validationError(
|
|
this.tokens.name,
|
|
this,
|
|
"attr-invalid-type",
|
|
message
|
|
);
|
|
break;
|
|
}
|
|
default: {
|
|
const { reference } =
|
|
idlTypeIncludesDictionary(this.idlType, defs) || {};
|
|
if (reference) {
|
|
const targetToken = (this.idlType.union ? reference : this.idlType)
|
|
.tokens.base;
|
|
const message = "Attributes cannot accept dictionary types.";
|
|
yield validationError(
|
|
targetToken,
|
|
this,
|
|
"attr-invalid-type",
|
|
message
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @param {import("../writer.js").Writer} w */
|
|
write(w) {
|
|
const { parent } = this;
|
|
return w.ts.definition(
|
|
w.ts.wrap([
|
|
this.extAttrs.write(w),
|
|
w.token(this.tokens.special),
|
|
w.token(this.tokens.readonly),
|
|
w.token(this.tokens.base),
|
|
w.ts.type(this.idlType.write(w)),
|
|
w.name_token(this.tokens.name, { data: this, parent }),
|
|
w.token(this.tokens.termination),
|
|
]),
|
|
{ data: this, parent }
|
|
);
|
|
}
|
|
}
|