diff --git a/lib/error.js b/lib/error.js index dcbb7e6e..4b1f53dc 100644 --- a/lib/error.js +++ b/lib/error.js @@ -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(" -> "); } @@ -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}`, diff --git a/lib/productions/argument.js b/lib/productions/argument.js index 1882a05d..c86868ca 100644 --- a/lib/productions/argument.js +++ b/lib/productions/argument.js @@ -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) && diff --git a/lib/productions/type.js b/lib/productions/type.js index 1746499b..0528c3ec 100644 --- a/lib/productions/type.js +++ b/lib/productions/type.js @@ -203,22 +203,21 @@ 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, @@ -226,11 +225,10 @@ for more information.`; 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); } } diff --git a/test/invalid/baseline/argument-dict-nullable.txt b/test/invalid/baseline/argument-dict-nullable.txt index 9ade1218..74464e36 100644 --- a/test/invalid/baseline/argument-dict-nullable.txt +++ b/test/invalid/baseline/argument-dict-nullable.txt @@ -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`: +(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 `{}`. diff --git a/test/invalid/baseline/argument-dict-optional.txt b/test/invalid/baseline/argument-dict-optional.txt index 35b5b244..32cf41cc 100644 --- a/test/invalid/baseline/argument-dict-optional.txt +++ b/test/invalid/baseline/argument-dict-optional.txt @@ -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 diff --git a/test/invalid/baseline/nullable-union-dictionary.txt b/test/invalid/baseline/nullable-union-dictionary.txt index e8efd350..e17f9871 100644 --- a/test/invalid/baseline/nullable-union-dictionary.txt +++ b/test/invalid/baseline/nullable-union-dictionary.txt @@ -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 diff --git a/test/invalid/baseline/operation-nameless.txt b/test/invalid/baseline/operation-nameless.txt index 97ee26a4..c7dbe69b 100644 --- a/test/invalid/baseline/operation-nameless.txt +++ b/test/invalid/baseline/operation-nameless.txt @@ -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. diff --git a/test/invalid/baseline/void-keyword.txt b/test/invalid/baseline/void-keyword.txt index 37f4c118..692fb3a7 100644 --- a/test/invalid/baseline/void-keyword.txt +++ b/test/invalid/baseline/void-keyword.txt @@ -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. diff --git a/test/invalid/idl/argument-dict-nullable.webidl b/test/invalid/idl/argument-dict-nullable.webidl index 087fe8ea..fd7bac13 100644 --- a/test/invalid/idl/argument-dict-nullable.webidl +++ b/test/invalid/idl/argument-dict-nullable.webidl @@ -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);