Skip to content
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ properties:
* `sourceName`: the source name you passed to `parse()`.
* `level`: `"error"` by default, can be `"warning"` for some validations for e.g. potential future deprecations.
* `ruleName`: Only for validations. Currently the followings are supported:
* `async-iterable-idl-to-js`: `async_iterable` types cannot be returned from the IDL to JS.
* `attr-invalid-type`: Attributes cannot have sequences, records, nor dictionaries.
* `dict-arg-default`: Optional dictionary type arguments must have a default value of `{}`.
* `dict-arg-optional`: Dictionary type arguments must be optional if the type does not include a required field.
Expand Down Expand Up @@ -236,7 +237,7 @@ attached to a field called `idlType`:
Where the fields are as follows:

* `type`: String indicating where this type is used. Can be `null` if not applicable.
* `generic`: String indicating the generic type (e.g. "Promise", "sequence").
* `generic`: String indicating the generic type (e.g. "Promise", "sequence", "async_sequence").
* `idlType`: String indicating the type name, or array of subtypes if the type is
generic or a union.
* `nullable`: `true` if the type is nullable.
Expand Down
4 changes: 3 additions & 1 deletion lib/productions/attribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ export class Attribute extends Base {
yield* this.extAttrs.validate(defs);
yield* this.idlType.validate(defs);

if (["sequence", "record"].includes(this.idlType.generic)) {
if (
["async_sequence", "sequence", "record"].includes(this.idlType.generic)
) {
const message = `Attributes cannot accept ${this.idlType.generic} types.`;
yield validationError(
this.tokens.name,
Expand Down
13 changes: 13 additions & 0 deletions lib/productions/callback.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
unescape,
autoParenter,
} from "./helpers.js";
import { validationError } from "../error.js";

export class CallbackFunction extends Base {
/**
Expand Down Expand Up @@ -44,6 +45,18 @@ export class CallbackFunction extends Base {

*validate(defs) {
yield* this.extAttrs.validate(defs);
for (const arg of this.arguments) {
yield* arg.validate(defs);
if (arg.idlType.generic === "async_sequence") {
const message = `async_sequence types cannot be returned as a callback argument.`;
yield validationError(
arg.tokens.name,
arg,
"async-sequence-idl-to-js",
message,
);
}
}
yield* this.idlType.validate(defs);
}

Expand Down
9 changes: 9 additions & 0 deletions lib/productions/operation.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ export class Operation extends Base {
yield validationError(this.tokens.open, this, "incomplete-op", message);
}
if (this.idlType) {
if (this.idlType.generic === "async_sequence") {
const message = `async_sequence types cannot be returned by an operation.`;
yield validationError(
this.idlType.tokens.base,
this,
"async-sequence-idl-to-js",
message,
);
}
yield* this.idlType.validate(defs);
}
for (const argument of this.arguments) {
Expand Down
2 changes: 2 additions & 0 deletions lib/productions/type.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ function generic_type(tokeniser, typeName) {
"FrozenArray",
"ObservableArray",
"Promise",
"async_sequence",
"sequence",
"record",
);
Expand All @@ -42,6 +43,7 @@ function generic_type(tokeniser, typeName) {
ret.subtype.push(subtype);
break;
}
case "async_sequence":
case "sequence":
case "FrozenArray":
case "ObservableArray": {
Expand Down
1 change: 1 addition & 0 deletions lib/tokeniser.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const nonRegexTerminals = [
"ObservableArray",
"Promise",
"async_iterable",
"async_sequence",
"bigint",
"boolean",
"byte",
Expand Down
3 changes: 3 additions & 0 deletions test/invalid/baseline/async-sequence-const.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Syntax error at line 3 in async-sequence-const.webidl, since `interface AsyncSequence`:
const async_sequence<long, short
^ Const lacks a type
9 changes: 9 additions & 0 deletions test/invalid/baseline/async-sequence-idl-to-js.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
(attr-invalid-type) Validation error at line 3 in async-sequence-idl-to-js.webidl, inside `interface asyncIterableAsAttribute -> attribute invalid`:
attribute async_sequence<short> invalid;
^ Attributes cannot accept async_sequence types.
(async-sequence-idl-to-js) Validation error at line 5 in async-sequence-idl-to-js.webidl, inside `interface asyncIterableAsAttribute -> operation invalidOp`:
async_sequence<DOMString> invalidOp
^ async_sequence types cannot be returned by an operation.
(async-sequence-idl-to-js) Validation error at line 8 in async-sequence-idl-to-js.webidl, inside `callback DoSomething -> argument bool`:
(async_sequence<DOMString> bool);
^ async_sequence types cannot be returned as a callback argument.
3 changes: 3 additions & 0 deletions test/invalid/baseline/async-sequence-two-params.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Syntax error at line 3 in async-sequence-two-params.webidl, since `interface AsyncSequence`:
async_sequence<long, short> foo(
^ Missing closing bracket after async_sequence
4 changes: 4 additions & 0 deletions test/invalid/idl/async-sequence-const.webidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[Exposed=Window]
interface AsyncSequence {
const async_sequence<long, short> ASYNC_SEQUENCE = 0;
};
9 changes: 9 additions & 0 deletions test/invalid/idl/async-sequence-idl-to-js.webidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[Exposed=Window]
interface asyncIterableAsAttribute {
attribute async_sequence<short> invalid;
attribute (async_sequence<short> or boolean) invalidUnion; // TODO
async_sequence<DOMString> invalidOp();
};

callback DoSomething = Promise<DOMString> (async_sequence<DOMString> bool);

4 changes: 4 additions & 0 deletions test/invalid/idl/async-sequence-two-params.webidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[Exposed=Window]
interface AsyncSequence {
async_sequence<long, short> foo();
};
131 changes: 131 additions & 0 deletions test/syntax/baseline/async-sequence.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
[
{
"type": "interface",
"name": "Canvas",
"inheritance": null,
"members": [
{
"type": "operation",
"name": "drawPolygonAsync",
"idlType": {
"type": "return-type",
"extAttrs": [],
"generic": "Promise",
"nullable": false,
"union": false,
"idlType": [
{
"type": "return-type",
"extAttrs": [],
"generic": "",
"nullable": false,
"union": false,
"idlType": "undefined"
}
]
},
"arguments": [
{
"type": "argument",
"name": "coordinates",
"extAttrs": [],
"idlType": {
"type": "argument-type",
"extAttrs": [],
"generic": "async_sequence",
"nullable": false,
"union": false,
"idlType": [
{
"type": "argument-type",
"extAttrs": [],
"generic": "",
"nullable": false,
"union": false,
"idlType": "float"
}
]
},
"default": null,
"optional": false,
"variadic": false
}
],
"extAttrs": [],
"special": ""
}
],
"extAttrs": [],
"partial": false
},
{
"type": "interface",
"name": "I",
"inheritance": null,
"members": [
{
"type": "operation",
"name": "f1",
"idlType": {
"type": "return-type",
"extAttrs": [],
"generic": "Promise",
"nullable": false,
"union": false,
"idlType": [
{
"type": "return-type",
"extAttrs": [],
"generic": "",
"nullable": false,
"union": false,
"idlType": "undefined"
}
]
},
"arguments": [
{
"type": "argument",
"name": "arg",
"extAttrs": [],
"idlType": {
"type": "argument-type",
"extAttrs": [],
"generic": "async_sequence",
"nullable": false,
"union": false,
"idlType": [
{
"type": "argument-type",
"extAttrs": [
{
"type": "extended-attribute",
"name": "XAttr",
"rhs": null,
"arguments": []
}
],
"generic": "",
"nullable": false,
"union": false,
"idlType": "float"
}
]
},
"default": null,
"optional": false,
"variadic": false
}
],
"extAttrs": [],
"special": ""
}
],
"extAttrs": [],
"partial": false
},
{
"type": "eof",
"value": ""
}
]
7 changes: 7 additions & 0 deletions test/syntax/idl/async-sequence.webidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
interface Canvas {
Promise<undefined> drawPolygonAsync(async_sequence<float> coordinates);
};

interface I {
Promise<undefined> f1(async_sequence<[XAttr] float> arg);
};