dawn/node: Fix missing validation errors

Derived interfaces were not exposing their base interface's attributes / methods / constants.

By fixing this, we now correctly expose the `message` property on interfaces deriving from `GPUError`.

Change-Id: I2f8cb4145b589a7b148495ad36f1ae00e388a99e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/106881
Auto-Submit: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/dawn/node/interop/WebGPU.cpp.tmpl b/src/dawn/node/interop/WebGPU.cpp.tmpl
index f711b1e..a8f8bc8 100644
--- a/src/dawn/node/interop/WebGPU.cpp.tmpl
+++ b/src/dawn/node/interop/WebGPU.cpp.tmpl
@@ -138,6 +138,9 @@
 */ -}}
 {{- define "Wrapper"}}
   struct W{{$.Name}} : public Napi::ObjectWrap<W{{$.Name}}> {
+{{-  $attributes := FlattenedAttributesOf $ }}
+{{-  $constants  := FlattenedConstantsOf  $ }}
+{{-  $methods    := FlattenedMethodsOf    $ }}
 {{-  if IsInterface $}}
     std::unique_ptr<{{$.Name}}> impl;
 {{-  end}}
@@ -147,17 +150,17 @@
         InstanceMethod("has", &W{{$.Name}}::has),
         InstanceMethod("keys", &W{{$.Name}}::keys),
 {{-  end}}
-{{-  range $m := MethodsOf $}}
+{{-  range $m := $methods}}
         InstanceMethod("{{$m.Name}}", &W{{$.Name}}::{{$m.Name}}),
 {{-  end}}
-{{-  range $a := AttributesOf $}}
+{{-  range $a := $attributes}}
 {{-   if not (HasAnnotation $a "SameObject")}}
         InstanceAccessor("{{$a.Name}}", &W{{$.Name}}::get{{Title $a.Name}},
 {{-    if $a.Readonly}} nullptr{{else}} &W{{$.Name}}::set{{Title $a.Name}}{{end -}}
         ),
 {{-   end}}
 {{-  end}}
-{{-  range $c := ConstantsOf $}}
+{{-  range $c := $constants}}
         StaticValue("{{$c.Name}}", ToJS(env, {{$.Name}}::{{$c.Name}}), napi_default_jsproperty),
 {{-  end}}
       });
@@ -165,7 +168,7 @@
 
     W{{$.Name}}(const Napi::CallbackInfo& info) : ObjectWrap(info) {}
 
-{{   if $s := SetlikeOf $}}
+{{-  if $s := SetlikeOf $}}
     Napi::Value has(const Napi::CallbackInfo& info) {
       std::tuple<{{template "Type" $s.Elem}}> args;
       auto res = FromJS(info, args);
@@ -179,7 +182,7 @@
       return ToJS(info.Env(), impl->keys(info.Env()));
     }
 {{-  end}}
-{{-  range $m := MethodsOf $}}
+{{-  range $m := $methods}}
     Napi::Value {{$m.Name}}(const Napi::CallbackInfo& info) {
       std::string error;
 {{-    range $overload_idx, $o := $m.Overloads}}
@@ -222,7 +225,7 @@
     }
 {{-  end}}
 
-{{-  range $a := AttributesOf $}}
+{{-  range $a := $attributes}}
 {{-   if not (HasAnnotation $a "SameObject")}}
     Napi::Value get{{Title $a.Name}}(const Napi::CallbackInfo& info) {
       return ToJS(info.Env(), impl->get{{Title $a.Name}}(info.Env()));
diff --git a/src/dawn/node/tools/src/cmd/idlgen/main.go b/src/dawn/node/tools/src/cmd/idlgen/main.go
index a465591..4fd6cbf 100644
--- a/src/dawn/node/tools/src/cmd/idlgen/main.go
+++ b/src/dawn/node/tools/src/cmd/idlgen/main.go
@@ -113,6 +113,9 @@
 		"EnumEntryName":              enumEntryName,
 		"Eval":                       g.eval,
 		"HasAnnotation":              hasAnnotation,
+		"FlattenedAttributesOf":      g.flattenedAttributesOf,
+		"FlattenedConstantsOf":       g.flattenedConstantsOf,
+		"FlattenedMethodsOf":         g.flattenedMethodsOf,
 		"Include":                    g.include,
 		"IsBasicLiteral":             is(ast.BasicLiteral{}),
 		"IsInitializer":              isInitializer,
@@ -571,6 +574,22 @@
 	return out
 }
 
+// flattenedMethodsOf returns all the methods of the given WebIDL
+// interface or namespace, as well as all the methods of the full inheritance
+// chain
+func (g *generator) flattenedMethodsOf(obj interface{}) []*Method {
+	switch obj := obj.(type) {
+	case *ast.Interface:
+		out := methodsOf(obj)
+		if base := g.lookup(obj.Inherits); base != nil {
+			out = append(out, g.flattenedMethodsOf(base)...)
+		}
+		return out
+	default:
+		return methodsOf(obj)
+	}
+}
+
 // attributesOf returns all the attributes of the given WebIDL interface or
 // namespace.
 func attributesOf(obj interface{}) []*ast.Member {
@@ -580,6 +599,7 @@
 			out = append(out, m)
 		}
 	}
+
 	switch obj := obj.(type) {
 	case *ast.Interface:
 		for _, m := range obj.Members {
@@ -595,6 +615,22 @@
 	return out
 }
 
+// flattenedAttributesOf returns all the attributes of the given WebIDL
+// interface or namespace, as well as all the attributes of the full inheritance
+// chain
+func (g *generator) flattenedAttributesOf(obj interface{}) []*ast.Member {
+	switch obj := obj.(type) {
+	case *ast.Interface:
+		out := attributesOf(obj)
+		if base := g.lookup(obj.Inherits); base != nil {
+			out = append(out, g.flattenedAttributesOf(base)...)
+		}
+		return out
+	default:
+		return attributesOf(obj)
+	}
+}
+
 // constantsOf returns all the constant values of the given WebIDL interface or
 // namespace.
 func constantsOf(obj interface{}) []*ast.Member {
@@ -619,6 +655,22 @@
 	return out
 }
 
+// flattenedConstantsOf returns all the constants of the given WebIDL
+// interface or namespace, as well as all the constants of the full inheritance
+// chain
+func (g *generator) flattenedConstantsOf(obj interface{}) []*ast.Member {
+	switch obj := obj.(type) {
+	case *ast.Interface:
+		out := constantsOf(obj)
+		if base := g.lookup(obj.Inherits); base != nil {
+			out = append(out, g.flattenedConstantsOf(base)...)
+		}
+		return out
+	default:
+		return constantsOf(obj)
+	}
+}
+
 // setlikeOf returns the setlike ast.Pattern, if obj is a setlike interface.
 func setlikeOf(obj interface{}) *ast.Pattern {
 	iface, ok := obj.(*ast.Interface)