Repository: w3c/webidl2.js
Pull request #207 (2018-06-14 08:18:39)

Add trivia for enums and typedefs
Exposes `trivia` field for enum values.


Patch:
diff --git a/lib/webidl2.js b/lib/webidl2.js
index e287317..0a38852 100644
--- a/lib/webidl2.js
+++ b/lib/webidl2.js
@@ -211,7 +211,7 @@
         .slice(consume_position, consume_position + maxTokens)
         .map(t => t.trivia + t.value).join("");
       // Count newlines preceding the actual erroneous token
-      if (tokens.length) {
+      if (tokens[consume_position]) {
         line += count(tokens[consume_position].trivia, "\n");
       }
 
@@ -1039,20 +1039,28 @@
     }
 
     function enum_() {
-      if (!consume("enum")) return;
+      const base = consume("enum");
+      if (!base) return;
+      const trivia = { base: base.trivia };
       const name = consume(ID) || error("No name for enum");
+      trivia.name = name.trivia;
       const vals = [];
       const ret = current = {
         type: "enum",
         name: sanitize_name(name.value, "enum"),
-        values: vals
+        values: vals,
+        trivia
       };
-      consume("{") || error("No curly for enum");
+      const open = consume("{") || error("Bodyless enum");
+      trivia.open = open.trivia;
       let value_expected = true;
       while (true) {
-        if (consume("}")) {
+        const close = consume("}");
+        if (close) {
+          trivia.close = close.trivia;
           if (!ret.values.length) error("No value in enum");
-          consume(";") || error("No semicolon after enum");
+          const termination = consume(";") || error("No semicolon after enum");
+          trivia.termination = termination.trivia;
           return ret;
         }
         else if (!value_expected) {
@@ -1060,23 +1068,28 @@
         }
         const val = consume(STR) || error("Unexpected value in enum");
         val.value = val.value.slice(1, -1);
-        // No trivia exposure yet
-        val.trivia = undefined;
         ret.values.push(val);
-        value_expected = !!consume(",");
+        val.separator = untyped_consume(",");
+
+        value_expected = !!val.separator;
       }
     }
 
     function typedef() {
-      if (!consume("typedef")) return;
+      const base = consume("typedef");
+      if (!base) return;
+      const trivia = { base: base.trivia };
       const ret = {
         type: "typedef"
       };
       ret.idlType = type_with_extended_attributes("typedef-type") || error("No type in typedef");
       const name = consume(ID) || error("No name in typedef");
       ret.name = sanitize_name(name.value, "typedef");
+      trivia.name = name.trivia;
       current = ret;
-      consume(";") || error("Unterminated typedef");
+      const termination = consume(";") || error("Unterminated typedef");
+      trivia.termination = termination.trivia;
+      ret.trivia = trivia;
       return ret;
     }
 
diff --git a/lib/writer.js b/lib/writer.js
index f9e65e4..a2132cf 100644
--- a/lib/writer.js
+++ b/lib/writer.js
@@ -139,7 +139,7 @@
     }
     function typedef(it) {
       const ret = extended_attributes(it.extAttrs);
-      return `${ret}typedef${type(it.idlType)} ${it.name};`;
+      return `${ret}${it.trivia.base}typedef${type(it.idlType)}${it.trivia.name}${it.name}${it.trivia.termination};`;
     }
     function implements_(it) {
       const ret = extended_attributes(it.extAttrs);
@@ -158,8 +158,11 @@
     }
     function enum_(it) {
       const ext = extended_attributes(it.extAttrs);
-      const values = it.values.map(v => `"${v.value}",`).join("");
-      return `${ext}enum ${it.name} {${values}};`;
+      const values = it.values.map(v => {
+        const body = `${v.trivia}"${v.value}"`;
+        return v.separator ? `${body}${v.separator.trivia}${v.separator.value}` : body;
+      }).join("");
+      return `${ext}${it.trivia.base}enum${it.trivia.name}${it.name}${it.trivia.open}{${values}${it.trivia.close}}${it.trivia.termination};`;
     }
     function iterable_like(it) {
       const readonly = it.readonly ? `${it.readonly.trivia}readonly` : "";


Test patch:
diff --git a/test/invalid/idl/enum-bodyless.widl b/test/invalid/idl/enum-bodyless.widl
new file mode 100644
index 0000000..23f4873
--- /dev/null
+++ b/test/invalid/idl/enum-bodyless.widl
@@ -0,0 +1,1 @@
+enum X
diff --git a/test/invalid/json/enum-bodyless.json b/test/invalid/json/enum-bodyless.json
new file mode 100644
index 0000000..00fd697
--- /dev/null
+++ b/test/invalid/json/enum-bodyless.json
@@ -0,0 +1,4 @@
+{
+    "message": "Got an error during or right after parsing `enum X`: Bodyless enum",
+    "line": 1
+}
diff --git a/test/syntax/json/enum.json b/test/syntax/json/enum.json
index 4f4d999..f5fa094 100644
--- a/test/syntax/json/enum.json
+++ b/test/syntax/json/enum.json
@@ -5,17 +5,35 @@
         "values": [
             {
                 "type": "string",
-                "value": "rice"
+                "value": "rice",
+                "trivia": " ",
+                "separator": {
+                    "value": ",",
+                    "trivia": ""
+                }
             },
             {
                 "type": "string",
-                "value": "noodles"
+                "value": "noodles",
+                "trivia": " ",
+                "separator": {
+                    "value": ",",
+                    "trivia": ""
+                }
             },
             {
                 "type": "string",
-                "value": "other"
+                "value": "other",
+                "trivia": " "
             }
         ],
+        "trivia": {
+            "base": "",
+            "name": " ",
+            "open": " ",
+            "close": " ",
+            "termination": ""
+        },
         "extAttrs": null
     },
     {
@@ -197,17 +215,39 @@
         "values": [
             {
                 "type": "string",
-                "value": "rice"
+                "value": "rice",
+                "trivia": " ",
+                "separator": {
+                    "value": ",",
+                    "trivia": ""
+                }
             },
             {
                 "type": "string",
-                "value": "noodles"
+                "value": "noodles",
+                "trivia": " ",
+                "separator": {
+                    "value": ",",
+                    "trivia": ""
+                }
             },
             {
                 "type": "string",
-                "value": "other"
+                "value": "other",
+                "trivia": " ",
+                "separator": {
+                    "value": ",",
+                    "trivia": ""
+                }
             }
         ],
+        "trivia": {
+            "base": "\n\n",
+            "name": " ",
+            "open": " ",
+            "close": " ",
+            "termination": ""
+        },
         "extAttrs": null
     }
 ]
diff --git a/test/syntax/json/identifier-qualified-names.json b/test/syntax/json/identifier-qualified-names.json
index c55cbc3..0fa2857 100644
--- a/test/syntax/json/identifier-qualified-names.json
+++ b/test/syntax/json/identifier-qualified-names.json
@@ -17,6 +17,11 @@
             }
         },
         "name": "number",
+        "trivia": {
+            "base": "// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06\n  // Typedef identifier: \"number\"\n  // Qualified name:    \"::framework::number\"\n  ",
+            "name": " ",
+            "termination": ""
+        },
         "extAttrs": null
     },
     {
diff --git a/test/syntax/json/typedef-union.json b/test/syntax/json/typedef-union.json
index 0c919f3..0e9a4f3 100644
--- a/test/syntax/json/typedef-union.json
+++ b/test/syntax/json/typedef-union.json
@@ -88,6 +88,11 @@
             }
         },
         "name": "TexImageSource",
+        "trivia": {
+            "base": "  ",
+            "name": " ",
+            "termination": ""
+        },
         "extAttrs": null
     }
 ]
diff --git a/test/syntax/json/typedef.json b/test/syntax/json/typedef.json
index 61cc083..e420235 100644
--- a/test/syntax/json/typedef.json
+++ b/test/syntax/json/typedef.json
@@ -115,6 +115,11 @@
             }
         },
         "name": "PointSequence",
+        "trivia": {
+            "base": "\n\n      ",
+            "name": " ",
+            "termination": ""
+        },
         "extAttrs": null
     },
     {
@@ -410,6 +415,11 @@
             }
         },
         "name": "value",
+        "trivia": {
+            "base": "\n\n  ",
+            "name": " ",
+            "termination": ""
+        },
         "extAttrs": null
     }
 ]