Skip to content

Commit 89aa286

Browse files
committed
compiler: support arbitrary string js tags
Javascript allows for arbitrary strings to be used as index values on an Object. A good example of where this comes up is React where "data-*" and "aria-*" indexes are used on objects (https://reactjs.org/docs/dom-elements.html). By switching from property selectors to the index operator for *js.Object special field access we can support arbitrary string values in js tags. Fixes #778
1 parent 82b3220 commit 89aa286

File tree

3 files changed

+27
-4
lines changed

3 files changed

+27
-4
lines changed

compiler/expressions.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -516,9 +516,9 @@ func (c *funcContext) translateExpr(expr ast.Expr) *expression {
516516
fields, jsTag := c.translateSelection(sel, e.Pos())
517517
if jsTag != "" {
518518
if _, ok := sel.Type().(*types.Signature); ok {
519-
return c.formatExpr("$internalize(%1e.%2s.%3s, %4s, %1e.%2s)", e.X, strings.Join(fields, "."), jsTag, c.typeName(sel.Type()))
519+
return c.formatExpr("$internalize(%1e.%2s[\"%3s\"], %4s, %1e.%2s)", e.X, strings.Join(fields, "."), jsTag, c.typeName(sel.Type()))
520520
}
521-
return c.internalize(c.formatExpr("%e.%s.%s", e.X, strings.Join(fields, "."), jsTag), sel.Type())
521+
return c.internalize(c.formatExpr("%e.%s[\"%s\"]", e.X, strings.Join(fields, "."), jsTag), sel.Type())
522522
}
523523
return c.formatExpr("%e.%s", e.X, strings.Join(fields, "."))
524524
case types.MethodVal:
@@ -669,7 +669,7 @@ func (c *funcContext) translateExpr(expr ast.Expr) *expression {
669669
case types.FieldVal:
670670
fields, jsTag := c.translateSelection(sel, f.Pos())
671671
if jsTag != "" {
672-
call := c.formatExpr("%e.%s.%s(%s)", f.X, strings.Join(fields, "."), jsTag, externalizeArgs(e.Args))
672+
call := c.formatExpr("%e.%s[\"%s\"](%s)", f.X, strings.Join(fields, "."), jsTag, externalizeArgs(e.Args))
673673
switch sig.Results().Len() {
674674
case 0:
675675
return call

compiler/statements.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ func (c *funcContext) translateAssign(lhs, rhs ast.Expr, define bool) string {
703703
}
704704
fields, jsTag := c.translateSelection(sel, l.Pos())
705705
if jsTag != "" {
706-
return fmt.Sprintf("%s.%s.%s = %s;", c.translateExpr(l.X), strings.Join(fields, "."), jsTag, c.externalize(rhsExpr.String(), sel.Type()))
706+
return fmt.Sprintf("%s.%s[\"%s\"] = %s;", c.translateExpr(l.X), strings.Join(fields, "."), jsTag, c.externalize(rhsExpr.String(), sel.Type()))
707707
}
708708
return fmt.Sprintf("%s.%s = %s;", c.translateExpr(l.X), strings.Join(fields, "."), rhsExpr)
709709
case *ast.StarExpr:

js/js_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,3 +597,26 @@ func TestTypeSwitchJSObject(t *testing.T) {
597597
}
598598
}
599599
}
600+
601+
type StructWithNonIdentifierJsTags struct {
602+
object *js.Object
603+
Name string `js:"my name"`
604+
}
605+
606+
func TestStructWithNonIdentifierJsTags(t *testing.T) {
607+
s := StructWithNonIdentifierJsTags{
608+
object: js.Global.Get("Object").New(),
609+
}
610+
611+
const want = "Paul"
612+
613+
// externalise a value
614+
s.Name = want
615+
616+
// internalise again
617+
got := s.Name
618+
619+
if want != got {
620+
t.Errorf("Value via non-identifier js tag field gave %q, want %q", got, want)
621+
}
622+
}

0 commit comments

Comments
 (0)