Repository: w3c/webidl2.js
Pull request #163 (2018-05-20 04:45:33)

fix: prevent incorrect union types
https://heycam.github.io/webidl/#prod-UnionType

```
UnionType ::
    ( UnionMemberType or UnionMemberType UnionMemberTypes )
UnionMemberType ::
    ExtendedAttributeList NonAnyType
    UnionType Null
UnionMemberTypes ::
    or UnionMemberType UnionMemberTypes
    ε
```

```webidl
typedef (OnlyOne) UnionOne; // shouldn't pass, at least two types are required inside a union
```

Also it turns out we don't have any tests for incorrect union types so I added some.


Patch:
diff --git a/lib/webidl2.js b/lib/webidl2.js
index 2ca27b6..a1b6927 100644
--- a/lib/webidl2.js
+++ b/lib/webidl2.js
@@ -327,12 +327,12 @@
     function union_type(typeName) {
       if (!consume(OTHER, "(")) return;
       const ret = Object.assign({ type: typeName || null }, EMPTY_IDLTYPE, { union: true, idlType: [] });
-      const fst = type_with_extended_attributes() || error("Union type with no content");
-      ret.idlType.push(fst);
-      while (true) {
-        if (!consume("or")) break;
-        const typ = type_with_extended_attributes() || error("No type after 'or' in union type");
+      do {
+        const typ = type_with_extended_attributes() || error("No type after open parenthesis or 'or' in union type");
         ret.idlType.push(typ);
+      } while(consume("or"));
+      if (ret.idlType.length < 2) {
+        error("At least two types are expected in a union type but found less");
       }
       if (!consume(OTHER, ")")) error("Unterminated union type");
       type_suffix(ret);


Test patch:
diff --git a/test/invalid/idl/union-dangling-or.widl b/test/invalid/idl/union-dangling-or.widl
new file mode 100644
index 0000000..0aa043e
--- /dev/null
+++ b/test/invalid/idl/union-dangling-or.widl
@@ -0,0 +1,1 @@
+typedef (One or Two or) UnionOr;
diff --git a/test/invalid/idl/union-one.widl b/test/invalid/idl/union-one.widl
new file mode 100644
index 0000000..86ee96f
--- /dev/null
+++ b/test/invalid/idl/union-one.widl
@@ -0,0 +1,1 @@
+typedef (OnlyOne) UnionOne;
diff --git a/test/invalid/idl/union-zero.widl b/test/invalid/idl/union-zero.widl
new file mode 100644
index 0000000..177fc4c
--- /dev/null
+++ b/test/invalid/idl/union-zero.widl
@@ -0,0 +1,1 @@
+typedef () UnionZero;
diff --git a/test/invalid/json/union-dangling-or.json b/test/invalid/json/union-dangling-or.json
new file mode 100644
index 0000000..68dfd8b
--- /dev/null
+++ b/test/invalid/json/union-dangling-or.json
@@ -0,0 +1,4 @@
+{
+    "message": "Got an error before parsing any named definition: No type after open parenthesis or 'or' in union type",
+    "line": 1
+}
diff --git a/test/invalid/json/union-one.json b/test/invalid/json/union-one.json
new file mode 100644
index 0000000..476403d
--- /dev/null
+++ b/test/invalid/json/union-one.json
@@ -0,0 +1,4 @@
+{
+    "message": "Got an error before parsing any named definition: At least two types are expected in a union type but found less",
+    "line": 1
+}
diff --git a/test/invalid/json/union-zero.json b/test/invalid/json/union-zero.json
new file mode 100644
index 0000000..68dfd8b
--- /dev/null
+++ b/test/invalid/json/union-zero.json
@@ -0,0 +1,4 @@
+{
+    "message": "Got an error before parsing any named definition: No type after open parenthesis or 'or' in union type",
+    "line": 1
+}