Skip to content
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

feat(productions/type): no nullable dictionaries at all #571

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
22 changes: 11 additions & 11 deletions lib/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ function appendIfExist(base, target) {
}

function contextAsText(node) {
const hierarchy = [node];
while (node && node.parent) {
const { parent } = node;
hierarchy.unshift(parent);
node = parent;
const hierarchy = [];
while (node) {
if (node.type) {
hierarchy.unshift(node);
}
node = node.parent;
}
return hierarchy.map((n) => appendIfExist(n.type, n.name)).join(" -> ");
}
Expand Down Expand Up @@ -83,12 +84,11 @@ function error(

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 grammaticalContext = current
? `, ${contextType} \`${current.partial ? "partial " : ""}${contextAsText(
current
)}\``
: "";
const context = `${kind} error at line ${line}${inSourceName}${grammaticalContext}:\n${sourceContext}`;
return {
message: `${context} ${message}`,
Expand Down
10 changes: 1 addition & 9 deletions lib/productions/argument.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,7 @@ export class Argument extends Base {
useNullableInner: true,
});
if (result) {
if (this.idlType.nullable) {
const message = `Dictionary arguments cannot be nullable.`;
yield validationError(
this.tokens.name,
this,
"no-nullable-dict-arg",
message
);
} else if (!this.optional) {
if (!this.optional) {
if (
this.parent &&
!dictionaryIncludesRequiredField(result.dictionary, defs) &&
Expand Down
24 changes: 11 additions & 13 deletions lib/productions/type.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,34 +203,32 @@ for more information.`;
});
}

const ref = !this.union && defs.unique.get(this.idlType);
const target = ref && ref.type === "typedef" ? ref.idlType : 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 } = idlTypeIncludesDictionary(target, defs) || {};
const { reference } =
idlTypeIncludesDictionary(target, defs, { useNullableInner: true }) ||
{};
if (reference) {
const targetToken = (this.union ? reference : this).tokens.base;
const message = "Nullable union cannot include a dictionary type.";
const message = "A dictionary type can never be nullable";
yield validationError(
targetToken,
this,
"no-nullable-union-dict",
message
);
}
} else {
// allow some dictionary
for (const subtype of this.subtype) {
yield* subtype.validate(defs);
}
}

for (const subtype of this.subtype) {
yield* subtype.validate(defs);
}
}

Expand Down
41 changes: 22 additions & 19 deletions test/invalid/baseline/argument-dict-nullable.txt
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
(no-nullable-dict-arg) Validation error at line 13 in argument-dict-nullable.webidl, inside `interface X -> operation x1 -> argument dict`:
(no-nullable-union-dict) Validation error at line 13 in argument-dict-nullable.webidl, inside `interface X -> operation x1 -> argument dict -> argument-type`:
undefined x1(optional Dict? dict);
^ A dictionary type can never be nullable
(dict-arg-default) Validation error at line 13 in argument-dict-nullable.webidl, inside `interface X -> operation x1 -> argument dict`:
x1(optional Dict? dict);
^ Dictionary arguments cannot be nullable.
(no-nullable-dict-arg) Validation error at line 14 in argument-dict-nullable.webidl, inside `interface X -> operation x2 -> argument dict`:
x2(optional Dict? dict = {})
^ Dictionary arguments cannot be nullable.
(no-nullable-union-dict) Validation error at line 15 in argument-dict-nullable.webidl:
^ Optional dictionary arguments must have a default value of `{}`.
(no-nullable-union-dict) Validation error at line 14 in argument-dict-nullable.webidl, inside `interface X -> operation x2 -> argument dict -> argument-type`:
undefined x2(optional Dict? dict = {
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 15 in argument-dict-nullable.webidl, inside `interface X -> operation y2 -> argument union -> argument-type`:
(optional (boolean or Dict)? union =
^ 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:
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 16 in argument-dict-nullable.webidl, inside `interface X -> operation y3 -> argument union -> argument-type`:
(optional (boolean or Dict?) union)
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 17 in argument-dict-nullable.webidl, inside `interface X -> operation z2 -> argument union -> argument-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`:
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 18 in argument-dict-nullable.webidl, inside `interface X -> operation r -> argument req -> argument-type`:
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`:
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 20 in argument-dict-nullable.webidl, inside `interface X -> iterable -> argument dict -> argument-type`:
<DOMString>(optional Dict? dict);
^ A dictionary type can never be nullable
(dict-arg-default) Validation error at line 20 in argument-dict-nullable.webidl, inside `interface X -> iterable -> argument dict`:
>(optional Dict? dict);
^ Dictionary arguments cannot be nullable.
^ Optional dictionary arguments must have a default value of `{}`.
3 changes: 3 additions & 0 deletions test/invalid/baseline/argument-dict-optional.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
(no-nullable-union-dict) Validation error at line 22 in argument-dict-optional.webidl, inside `typedef NullableUnion -> typedef-type`:
typedef (DOMString or Optional?) NullableUnion;
^ A dictionary type can never be nullable
(dict-arg-optional) Validation error at line 25 in argument-dict-optional.webidl, inside `interface mixin Container -> operation op1 -> argument shouldBeOptional`:
undefined op1(Optional shouldBeOptional);
^ Dictionary argument must be optional if it has no required fields
Expand Down
51 changes: 27 additions & 24 deletions test/invalid/baseline/nullable-union-dictionary.txt
Original file line number Diff line number Diff line change
@@ -1,39 +1,42 @@
(no-nullable-union-dict) Validation error at line 4 in nullable-union-dictionary.webidl:
(no-nullable-union-dict) Validation error at line 4 in nullable-union-dictionary.webidl, inside `typedef NullableBooleanDict -> typedef-type`:
typedef (boolean or Dict)? NullableBooleanDict;
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 6 in nullable-union-dictionary.webidl:
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 6 in nullable-union-dictionary.webidl, inside `typedef NullableNestedBooleanDict -> typedef-type`:
boolean or (short or Dict))? NullableNestedBooleanDict
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 7 in nullable-union-dictionary.webidl:
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 7 in nullable-union-dictionary.webidl, inside `typedef NestedNullableBooleanDict -> typedef-type`:
boolean or (short or Dict)?) NestedNullableBooleanDict
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 8 in nullable-union-dictionary.webidl:
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 8 in nullable-union-dictionary.webidl, inside `typedef ReferencingNullableBooleanDict -> typedef-type`:
typedef BooleanDict? ReferencingNullableBooleanDict;
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 9 in nullable-union-dictionary.webidl:
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 9 in nullable-union-dictionary.webidl, inside `typedef RecursiveBooleanDict -> typedef-type`:
typedef (boolean or RecursiveBooleanDict? or Dict)
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 16 in nullable-union-dictionary.webidl:
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 14 in nullable-union-dictionary.webidl, inside `typedef NullableBooleanNullableDict -> typedef-type`:
typedef (boolean or Dict?)? NullableBooleanNullableDict
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 16 in nullable-union-dictionary.webidl, inside `callback Callback -> return-type`:
Callback = (boolean or Dict)? ()
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 19 in nullable-union-dictionary.webidl:
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 19 in nullable-union-dictionary.webidl, inside `interface Interface -> operation op -> return-type`:
(boolean or Dict)? op(
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 20 in nullable-union-dictionary.webidl:
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 20 in nullable-union-dictionary.webidl, inside `interface Interface -> operation voidOp -> argument arg -> argument-type`:
voidOp((boolean or Dict)? arg)
^ 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`:
^ A dictionary type can never be nullable
(dict-arg-optional) 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:
^ Dictionary argument must be optional if it has no required fields
(no-nullable-union-dict) Validation error at line 21 in nullable-union-dictionary.webidl, inside `interface Interface -> attribute attr -> attribute-type`:
attribute (boolean or Dict)? attr;
^ Nullable union cannot include a dictionary type.
^ A dictionary type can never be nullable
(attr-invalid-type) Validation error at line 21 in nullable-union-dictionary.webidl, inside `interface Interface -> attribute attr`:
attribute (boolean or Dict
^ Attributes cannot accept dictionary types.
(no-nullable-union-dict) Validation error at line 23 in nullable-union-dictionary.webidl:
(no-nullable-union-dict) Validation error at line 23 in nullable-union-dictionary.webidl, inside `interface Interface -> iterable`:
iterable<(boolean or Dict)?>;
^ Nullable union cannot include a dictionary type.
(no-nullable-union-dict) Validation error at line 27 in nullable-union-dictionary.webidl:
^ A dictionary type can never be nullable
(no-nullable-union-dict) Validation error at line 27 in nullable-union-dictionary.webidl, inside `dictionary AnotherDict -> field dict -> dictionary-type`:
(boolean or Dict)? dict;
^ Nullable union cannot include a dictionary type.
^ A dictionary type can never be nullable
4 changes: 2 additions & 2 deletions test/invalid/baseline/operation-nameless.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(incomplete-op) Validation error at line 3 in operation-nameless.webidl:
(incomplete-op) Validation error at line 3 in operation-nameless.webidl, inside `interface Anonymity -> operation`:
copy();
^ Regular or static operations must have both a return type and an identifier.
(incomplete-op) Validation error at line 4 in operation-nameless.webidl:
(incomplete-op) Validation error at line 4 in operation-nameless.webidl, inside `interface Anonymity -> operation`:
static create();
^ Regular or static operations must have both a return type and an identifier.
2 changes: 1 addition & 1 deletion test/invalid/baseline/void-keyword.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
(replace-void) Validation error at line 3 in void-keyword.webidl:
(replace-void) Validation error at line 3 in void-keyword.webidl, inside `interface Foo -> operation foo -> return-type`:
void foo();
^ `void` is now replaced by `undefined`. Refer to the [relevant GitHub issue](https://github.com/heycam/webidl/issues/60) for more information.
1 change: 1 addition & 0 deletions test/invalid/idl/argument-dict-nullable.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface X {
undefined x1(optional Dict? dict);
undefined x2(optional Dict? dict = {});
undefined y2(optional (boolean or Dict)? union = {});
undefined y3(optional (boolean or Dict?) union);
undefined z2(optional Union? union = {});
undefined r(Required? req);

Expand Down