Repository: w3c/webidl2.js
Pull request #289 (2019-03-16 06:51:24)

refactor: generic type as a class
Reaching to the end of this work 🚴‍♀️


Patch:
diff --git a/lib/webidl2.js b/lib/webidl2.js
index 16eb4ce..5e8458f 100644
--- a/lib/webidl2.js
+++ b/lib/webidl2.js
@@ -522,63 +522,59 @@
       }
     }
 
-    function generic_type(typeName) {
-      const name = consume("FrozenArray", "Promise", "sequence", "record");
-      if (!name) {
-        return;
-      }
-      const ret = {
-        baseName: name.value,
-        escapedBaseName: name.value,
-        generic: { value: name.value, trivia: {} },
-        trivia: { base: name.trivia }
-      };
-      const open = consume("<") || error(`No opening bracket after ${name.type}`);
-      ret.generic.trivia.open = open.trivia;
-      switch (name.type) {
-        case "Promise": {
-          if (probe("[")) error("Promise type cannot have extended attribute");
-          const subtype = return_type(typeName) || error("Missing Promise subtype");
-          ret.idlType = [subtype];
-          break;
-        }
-        case "sequence":
-        case "FrozenArray": {
-          const subtype = type_with_extended_attributes(typeName) || error(`Missing ${name.type} subtype`);
-          ret.idlType = [subtype];
-          break;
+    class GenericType extends Type {
+      static parse(typeName) {
+        const base = consume("FrozenArray", "Promise", "sequence", "record");
+        if (!base) {
+          return;
         }
-        case "record": {
-          if (probe("[")) error("Record key cannot have extended attribute");
-          ret.idlType = [];
-          const keyType = consume(...stringTypes);
-          if (!keyType) error(`Record key must be a string type`);
-          const separator = untyped_consume(",") || error("Missing comma after record key type");
-          ret.idlType.push(Object.assign({ type: typeName }, EMPTY_IDLTYPE, {
-            baseName: keyType.value,
-            escapedBaseName: keyType.value,
-            idlType: keyType.value,
-            separator,
-            trivia: {
-              base: keyType.trivia
-            }
-          }));
-          const valueType = type_with_extended_attributes(typeName) || error("Error parsing generic type record");
-          ret.idlType.push(valueType);
-          break;
+        const ret = new GenericType({ tokens: { base } });
+        ret.tokens.open = optional_consume("<") || error(`No opening bracket after ${base.type}`);
+        switch (base.type) {
+          case "Promise": {
+            if (probe("[")) error("Promise type cannot have extended attribute");
+            const subtype = return_type(typeName) || error("Missing Promise subtype");
+            ret.subtype.push(subtype);
+            break;
+          }
+          case "sequence":
+          case "FrozenArray": {
+            const subtype = type_with_extended_attributes(typeName) || error(`Missing ${base.type} subtype`);
+            ret.subtype.push(subtype);
+            break;
+          }
+          case "record": {
+            if (probe("[")) error("Record key cannot have extended attribute");
+            const keyType = consume(...stringTypes) || error(`Record key must be one of: ${stringTypes.join(", ")}`);
+            const keyIdlType = new Type({ tokens: { base: keyType }});
+            keyIdlType.tokens.separator = optional_consume(",") || error("Missing comma after record key type");
+            keyIdlType.type = typeName;
+            const valueType = type_with_extended_attributes(typeName) || error("Error parsing generic type record");
+            ret.subtype.push(keyIdlType, valueType);
+            break;
+          }
         }
+        if (!ret.idlType) error(`Error parsing generic type ${base.type}`);
+        ret.tokens.close = optional_consume(">") || error(`Missing closing bracket after ${base.type}`);
+        return ret;
+      }
+
+      get generic() {
+        return {
+          value: this.baseName,
+          trivia: {
+            open: this.tokens.open.trivia,
+            close: this.tokens.close.trivia,
+          }
+        };
       }
-      if (!ret.idlType) error(`Error parsing generic type ${name.type}`);
-      const close = consume(">") || error(`Missing closing bracket after ${name.type}`);
-      ret.generic.trivia.close = close.trivia;
-      return ret;
     }
 
     function single_type(typeName) {
-      const ret = Object.assign({ type: typeName || null }, EMPTY_IDLTYPE, { trivia: {} });
-      const base = generic_type(typeName) || primitive_type();
+      const ret = Object.assign({ type: null }, EMPTY_IDLTYPE, { trivia: {} });
+      const base = GenericType.parse(typeName) || primitive_type();
       if (base) {
-        Object.assign(ret, base);
+        Object.assign(ret, base.generic ? base.toJSON() : base);
       } else {
         const name = consume(ID, ...stringTypes);
         if (!name) {
@@ -592,6 +588,7 @@
       if (ret.generic && ret.generic.value === "Promise" && probe("?")) {
         error("Promise type cannot be nullable");
       }
+      ret.type = typeName || null;
       type_suffix(ret);
       if (ret.nullable && ret.idlType === "any") error("Type `any` cannot be made nullable");
       return ret;


Test patch:
diff --git a/test/invalid/baseline/record-key.txt b/test/invalid/baseline/record-key.txt
index 0d5ef7f..4beabae 100644
--- a/test/invalid/baseline/record-key.txt
+++ b/test/invalid/baseline/record-key.txt
@@ -1,3 +1,3 @@
 Syntax error at line 2, since `interface Foo`:
   void foo(record<octet, any> param
-                  ^ Record key must be a string type
+                  ^ Record key must be one of: ByteString, DOMString, USVString
diff --git a/test/syntax/baseline/record.json b/test/syntax/baseline/record.json
index aef4b60..b0e32b1 100644
--- a/test/syntax/baseline/record.json
+++ b/test/syntax/baseline/record.json
@@ -59,6 +59,7 @@
                                         "idlType": [
                                             {
                                                 "type": "argument-type",
+                                                "extAttrs": null,
                                                 "generic": null,
                                                 "nullable": null,
                                                 "union": false,
@@ -71,7 +72,6 @@
                                                     "value": ",",
                                                     "trivia": ""
                                                 },
-                                                "extAttrs": null,
                                                 "trivia": {
                                                     "base": ""
                                                 }
@@ -156,6 +156,7 @@
                         "idlType": [
                             {
                                 "type": "return-type",
+                                "extAttrs": null,
                                 "generic": null,
                                 "nullable": null,
                                 "union": false,
@@ -168,7 +169,6 @@
                                     "value": ",",
                                     "trivia": ""
                                 },
-                                "extAttrs": null,
                                 "trivia": {
                                     "base": ""
                                 }
@@ -277,6 +277,7 @@
                                     "idlType": [
                                         {
                                             "type": "argument-type",
+                                            "extAttrs": null,
                                             "generic": null,
                                             "nullable": null,
                                             "union": false,
@@ -289,7 +290,6 @@
                                                 "value": ",",
                                                 "trivia": ""
                                             },
-                                            "extAttrs": null,
                                             "trivia": {
                                                 "base": ""
                                             }
@@ -383,6 +383,7 @@
                         "idlType": [
                             {
                                 "type": "return-type",
+                                "extAttrs": null,
                                 "generic": null,
                                 "nullable": null,
                                 "union": false,
@@ -395,7 +396,6 @@
                                     "value": ",",
                                     "trivia": ""
                                 },
-                                "extAttrs": null,
                                 "trivia": {
                                     "base": ""
                                 }