Skip to content

feat: support undefined type #486

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# webidl2.js

[![NPM version](https://badge.fury.io/js/webidl2.svg)](http://badge.fury.io/js/webidl2) [![Known Vulnerabilities](https://snyk.io/test/github/w3c/webidl2.js/badge.svg)](https://snyk.io/test/github/w3c/webidl2.js/)
[![Financial Contributors on Open Collective](https://opencollective.com/webidl2js/all/badge.svg?label=financial+contributors)](https://opencollective.com/webidl2js)
[![Financial Contributors on Open Collective](https://opencollective.com/webidl2js/all/badge.svg?label=financial+contributors)](https://opencollective.com/webidl2js)

## Purpose

Expand Down Expand Up @@ -174,8 +174,8 @@ properties:
* `message`: the error message with its context. Below is what it looks like.
```
Syntax error at line 1 in callback-noparen.webidl, since `callback YourCall`:
callback YourCall = void;
^ Callback lacks parentheses for arguments
callback YourCall = undefined;
^ Callback lacks parentheses for arguments
```
* `bareMessage`: the error message without any context description like below.
```
Expand All @@ -196,6 +196,7 @@ properties:
* `no-cross-overload`: Overloading must be done within a single interface or namespace.
* `no-constructible-global`: Interfaces with `[Global]` cannot have constructors.
* `renamed-legacy`: Legacy extended attributes must use their new names.
* `replace-void`: `void` type is replaced by `undefined` type.
* `input`: a short peek at the text at the point where the error happened
* `tokens`: the five tokens at the point of error, as understood by the tokeniser
(this is the same content as `input`, but seen from the tokeniser's point of view)
Expand Down Expand Up @@ -339,7 +340,7 @@ A callback looks like this:
"generic": "",
"nullable": false,
"union": false,
"idlType": "void",
"idlType": "undefined",
"extAttrs": []
},
"arguments": [...],
Expand Down Expand Up @@ -508,7 +509,7 @@ An operation looks like this:
"generic": "",
"nullable": false,
"union": false,
"idlType": "void",
"idlType": "undefined",
"extAttrs": []
},
"name": "intersection",
Expand Down
2 changes: 1 addition & 1 deletion lib/productions/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export function primitive_type(tokeniser) {
const { source } = tokeniser;
const num_type = integer_type(tokeniser) || decimal_type(tokeniser);
if (num_type) return num_type;
const base = tokeniser.consume("boolean", "byte", "octet");
const base = tokeniser.consume("boolean", "byte", "octet", "undefined");
if (base) {
return new Type({ source, tokens: { base } });
}
Expand Down
21 changes: 20 additions & 1 deletion lib/productions/type.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,16 @@ export class Type extends Base {

*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/heycam/webidl/issues/60) \
for more information.`;
yield 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
Expand All @@ -165,7 +175,7 @@ export class Type extends Base {
const { reference } = idlTypeIncludesDictionary(target, defs) || {};
if (reference) {
const targetToken = (this.union ? reference : this).tokens.base;
const message = `Nullable union cannot include a dictionary type`;
const message = "Nullable union cannot include a dictionary type.";
yield validationError(targetToken, this, "no-nullable-union-dict", message);
}
} else {
Expand All @@ -176,3 +186,12 @@ export class Type extends Base {
}
}
}

/**
* @param {Type} type
*/
function replaceVoid(type) {
return () => {
type.tokens.base.value = "undefined";
};
}
1 change: 1 addition & 0 deletions lib/tokeniser.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ const nonRegexTerminals = [
"sequence",
"short",
"true",
"undefined",
"unsigned",
"void"
].concat(argumentNameKeywords, stringTypes, typeNameKeywords);
Expand Down
36 changes: 26 additions & 10 deletions test/autofix.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ describe("Writer template functions", () => {
dictionary A {};
[Exposed=Window]
interface B {
void op(optional A a);
undefined op(optional A a);
};
`;
const output = `
dictionary A {};
[Exposed=Window]
interface B {
void op(optional A a = {});
undefined op(optional A a = {});
};
`;
expect(autofix(input)).toBe(output);
Expand Down Expand Up @@ -195,15 +195,15 @@ describe("Writer template functions", () => {
[Exposed=Window, Constructor]
interface C {
\t// tabbed indentation
\tvoid koala();
\tundefined koala();
};
`;
const outputTabOp = `
[Exposed=Window]
interface C {
\tconstructor();
\t// tabbed indentation
\tvoid koala();
\tundefined koala();
};
`;
expect(autofix(inputTabOp)).toBe(outputTabOp);
Expand All @@ -212,15 +212,15 @@ describe("Writer template functions", () => {
[Exposed=Window, Constructor]
interface C {
\t// tabbed indentation
\tstatic void koala();
\tstatic undefined koala();
};
`;
const outputTabSpecialOp = `
[Exposed=Window]
interface C {
\tconstructor();
\t// tabbed indentation
\tstatic void koala();
\tstatic undefined koala();
};
`;
expect(autofix(inputTabSpecialOp)).toBe(outputTabSpecialOp);
Expand Down Expand Up @@ -270,7 +270,7 @@ describe("Writer template functions", () => {
};

interface mixin Container {
void op(
undefined op(
DOMString str,
Optional arg
);
Expand All @@ -282,7 +282,7 @@ describe("Writer template functions", () => {
};

interface mixin Container {
void op(
undefined op(
DOMString str,
optional Optional arg = {}
);
Expand All @@ -305,7 +305,7 @@ describe("Writer template functions", () => {
};

[TreatNonObjectAsNull]
callback TreatsNonObjectAsNull = void (DOMString s);
callback TreatsNonObjectAsNull = undefined (DOMString s);
`;
const output = `
[Exposed=Window,
Expand All @@ -320,7 +320,23 @@ describe("Writer template functions", () => {
};

[LegacyTreatNonObjectAsNull]
callback TreatsNonObjectAsNull = void (DOMString s);
callback TreatsNonObjectAsNull = undefined (DOMString s);
`;
expect(autofix(input)).toBe(output);
});

it("should replace undefined into undefined", () => {
const input = `
[Exposed=Window]
interface Foo {
void foo();
};
`;
const output = `
[Exposed=Window]
interface Foo {
undefined foo();
};
`;
expect(autofix(input)).toBe(output);
});
Expand Down
8 changes: 4 additions & 4 deletions test/invalid/baseline/argument-dict-default.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
constructor(optional Union union);
^ Optional dictionary arguments must have a default value of `{}`.
(dict-arg-default) Validation error at line 14 in argument-dict-default.webidl, inside `interface X -> operation x -> argument dict`:
void x(optional Dict dict);
^ Optional dictionary arguments must have a default value of `{}`.
undefined x(optional Dict dict);
^ Optional dictionary arguments must have a default value of `{}`.
(dict-arg-default) Validation error at line 16 in argument-dict-default.webidl, inside `interface X -> operation y -> argument union`:
(boolean or Dict) union);
^ Optional dictionary arguments must have a default value of `{}`.
(dict-arg-default) Validation error at line 18 in argument-dict-default.webidl, inside `interface X -> operation z -> argument union`:
void z(optional Union union);
^ Optional dictionary arguments must have a default value of `{}`.
undefined z(optional Union union);
^ Optional dictionary arguments must have a default value of `{}`.
(dict-arg-default) Validation error at line 22 in argument-dict-default.webidl, inside `interface X -> iterable -> argument union`:
DOMString>(optional Union union);
^ Optional dictionary arguments must have a default value of `{}`.
10 changes: 5 additions & 5 deletions test/invalid/baseline/argument-dict-nullable.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
^ Dictionary arguments cannot be nullable.
(no-nullable-union-dict) Validation error at line 15 in argument-dict-nullable.webidl:
(optional (boolean or Dict)? union =
^ Nullable union cannot include a dictionary type
^ Nullable union cannot include a dictionary type.
(no-nullable-dict-arg) Validation error at line 15 in argument-dict-nullable.webidl, inside `interface X -> operation y2 -> argument union`:
boolean or Dict)? union = {})
^ Dictionary arguments cannot be nullable.
(no-nullable-union-dict) Validation error at line 16 in argument-dict-nullable.webidl:
void z2(optional Union? union = {
^ Nullable union cannot include a dictionary type
undefined z2(optional Union? union = {
^ Nullable union cannot include a dictionary type.
(no-nullable-dict-arg) Validation error at line 16 in argument-dict-nullable.webidl, inside `interface X -> operation z2 -> argument union`:
z2(optional Union? union = {})
^ Dictionary arguments cannot be nullable.
(no-nullable-dict-arg) Validation error at line 17 in argument-dict-nullable.webidl, inside `interface X -> operation r -> argument req`:
void r(Required? req);
^ Dictionary arguments cannot be nullable.
undefined r(Required? req);
^ Dictionary arguments cannot be nullable.
(no-nullable-dict-arg) Validation error at line 19 in argument-dict-nullable.webidl, inside `interface X -> iterable -> argument dict`:
>(optional Dict? dict);
^ Dictionary arguments cannot be nullable.
16 changes: 8 additions & 8 deletions test/invalid/baseline/argument-dict-optional.txt
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
(dict-arg-optional) Validation error at line 25 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op1 -> argument shouldBeOptional`:
void op1(Optional shouldBeOptional);
^ Dictionary argument must be optional if it has no required fields
undefined op1(Optional shouldBeOptional);
^ Dictionary argument must be optional if it has no required fields
(dict-arg-optional) Validation error at line 29 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op3 -> argument union`:
(Optional or boolean) union);
^ Dictionary argument must be optional if it has no required fields
(dict-arg-optional) Validation error at line 30 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op4 -> argument union`:
void op4(OptionalUnion union);
^ Dictionary argument must be optional if it has no required fields
undefined op4(OptionalUnion union);
^ Dictionary argument must be optional if it has no required fields
(dict-arg-optional) Validation error at line 33 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op6 -> argument recursive`:
void op6(Recursive recursive);
^ Dictionary argument must be optional if it has no required fields
undefined op6(Recursive recursive);
^ Dictionary argument must be optional if it has no required fields
(dict-arg-optional) Validation error at line 36 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op8 -> argument lastRequired`:
void op8(Optional lastRequired, optional DOMString yay
^ Dictionary argument must be optional if it has no required fields
undefined op8(Optional lastRequired, optional DOMString yay
^ Dictionary argument must be optional if it has no required fields
(dict-arg-optional) Validation error at line 42 in argument-dict-optional.webidl, inside `interface ContainerInterface -> iterable -> argument shouldBeOptional`:
<DOMString>(Optional shouldBeOptional);
^ Dictionary argument must be optional if it has no required fields
22 changes: 11 additions & 11 deletions test/invalid/baseline/nullable-union-dictionary.txt
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
(no-nullable-union-dict) Validation error at line 4 in nullable-union-dictionary.webidl:
typedef (boolean or Dict)? NullableBooleanDict;
^ Nullable union cannot include a dictionary type
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 6 in nullable-union-dictionary.webidl:
boolean or (short or Dict))? NullableNestedBooleanDict
^ Nullable union cannot include a dictionary type
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 7 in nullable-union-dictionary.webidl:
boolean or (short or Dict)?) NestedNullableBooleanDict
^ Nullable union cannot include a dictionary type
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 8 in nullable-union-dictionary.webidl:
typedef BooleanDict? ReferencingNullableBooleanDict;
^ Nullable union cannot include a dictionary type
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 9 in nullable-union-dictionary.webidl:
typedef (boolean or RecursiveBooleanDict? or Dict)
^ Nullable union cannot include a dictionary type
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 16 in nullable-union-dictionary.webidl:
Callback = (boolean or Dict)? ()
^ Nullable union cannot include a dictionary type
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 19 in nullable-union-dictionary.webidl:
(boolean or Dict)? op(
^ Nullable union cannot include a dictionary type
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 20 in nullable-union-dictionary.webidl:
voidOp((boolean or Dict)? arg)
^ Nullable union cannot include a dictionary type
^ Nullable union cannot include a dictionary type.
(no-nullable-dict-arg) Validation error at line 20 in nullable-union-dictionary.webidl, inside `interface Interface -> operation voidOp -> argument arg`:
boolean or Dict)? arg);
^ Dictionary arguments cannot be nullable.
(no-nullable-union-dict) Validation error at line 21 in nullable-union-dictionary.webidl:
attribute (boolean or Dict)? attr;
^ Nullable union cannot include a dictionary type
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 23 in nullable-union-dictionary.webidl:
iterable<(boolean or Dict)?>;
^ Nullable union cannot include a dictionary type
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 27 in nullable-union-dictionary.webidl:
(boolean or Dict)? dict;
^ Nullable union cannot include a dictionary type
^ Nullable union cannot include a dictionary type.
24 changes: 12 additions & 12 deletions test/invalid/baseline/overloads.txt
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
(no-cross-overload) Validation error at line 8 in overloads.webidl, inside `partial interface Base`:
void unique(short num)
^ The operation "unique" has already been defined for the base interface "Base" either in itself or in a mixin
undefined unique(short num)
^ The operation "unique" has already been defined for the base interface "Base" either in itself or in a mixin
(no-cross-overload) Validation error at line 12 in overloads.webidl, inside `interface mixin Extension`:
void unique(string str)
^ The operation "unique" has already been defined for the base interface "Base" either in itself or in a mixin
undefined unique(string str)
^ The operation "unique" has already been defined for the base interface "Base" either in itself or in a mixin
(no-cross-overload) Validation error at line 22 in overloads.webidl, inside `interface mixin WebGL2RenderingContextBase`:
void bufferData(GLenum target,
^ The operation "bufferData" has already been defined for the base interface "WebGL2RenderingContext" either in itself or in a mixin
undefined bufferData(GLenum target,
^ The operation "bufferData" has already been defined for the base interface "WebGL2RenderingContext" either in itself or in a mixin
(no-cross-overload) Validation error at line 23 in overloads.webidl, inside `interface mixin WebGL2RenderingContextBase`:
void bufferData(GLenum target,
^ The operation "bufferData" has already been defined for the base interface "WebGL2RenderingContext" either in itself or in a mixin
undefined bufferData(GLenum target,
^ The operation "bufferData" has already been defined for the base interface "WebGL2RenderingContext" either in itself or in a mixin
(no-cross-overload) Validation error at line 24 in overloads.webidl, inside `interface mixin WebGL2RenderingContextBase`:
void bufferData(GLenum target,
^ The operation "bufferData" has already been defined for the base interface "WebGL2RenderingContext" either in itself or in a mixin
undefined bufferData(GLenum target,
^ The operation "bufferData" has already been defined for the base interface "WebGL2RenderingContext" either in itself or in a mixin
(no-cross-overload) Validation error at line 26 in overloads.webidl, inside `interface mixin WebGL2RenderingContextBase`:
void bufferData(GLenum target,
^ The operation "bufferData" has already been defined for the base interface "WebGL2RenderingContext" either in itself or in a mixin
undefined bufferData(GLenum target,
^ The operation "bufferData" has already been defined for the base interface "WebGL2RenderingContext" either in itself or in a mixin
8 changes: 4 additions & 4 deletions test/invalid/baseline/recursive-type.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(dict-arg-default) Validation error at line 9 in recursive-type.webidl, inside `interface X -> operation recursive -> argument r`:
void recursive(optional Recursive r);
^ Optional dictionary arguments must have a default value of `{}`.
undefined recursive(optional Recursive r);
^ Optional dictionary arguments must have a default value of `{}`.
(dict-arg-default) Validation error at line 10 in recursive-type.webidl, inside `interface X -> operation recursive2 -> argument f`:
void recursive2(optional FriendX f);
^ Optional dictionary arguments must have a default value of `{}`.
undefined recursive2(optional FriendX f);
^ Optional dictionary arguments must have a default value of `{}`.
3 changes: 3 additions & 0 deletions test/invalid/baseline/void-keyword.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(replace-void) Validation error at line 3 in void-keyword.webidl:
void foo();
^ `void` is now replaced by `undefined`. Refer to the [relevant GitHub issue](https://github.com/heycam/webidl/issues/60) for more information.
14 changes: 7 additions & 7 deletions test/invalid/idl/argument-dict-default.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ typedef (short or Dict) Union;
[Exposed=Window]
interface X {
constructor(optional Union union);
void x(optional Dict dict);
void x2(optional Dict dict = {});
void y(optional (boolean or Dict) union);
void y2(optional (boolean or Dict) union = {});
void z(optional Union union);
void z2(optional Union union = {});
void r(Required req);
undefined x(optional Dict dict);
undefined x2(optional Dict dict = {});
undefined y(optional (boolean or Dict) union);
undefined y2(optional (boolean or Dict) union = {});
undefined z(optional Union union);
undefined z2(optional Union union = {});
undefined r(Required req);

async iterable<DOMString>(optional Union union);
};
Loading