From 73c5dac18ccb90b54f146f2a42c37024d720c1af Mon Sep 17 00:00:00 2001
From: DinoChiesa <dchiesa@google.com>
Date: Fri, 3 Jan 2025 19:17:47 +0000
Subject: [PATCH] feat: jsonnetfmt remove newlines after ObjectField id

---
 formatter/formatter_test.go               |   8 +-
 formatter/testdata/json-to-xml.fmt.golden |  17 ++++
 formatter/testdata/json-to-xml.jsonnet    |  21 +++++
 internal/formatter/fix_newlines.go        | 102 ++++++++++++++++------
 4 files changed, 122 insertions(+), 26 deletions(-)
 create mode 100644 formatter/testdata/json-to-xml.fmt.golden
 create mode 100644 formatter/testdata/json-to-xml.jsonnet

diff --git a/formatter/formatter_test.go b/formatter/formatter_test.go
index 36bfb03c8..6d4fac5ec 100644
--- a/formatter/formatter_test.go
+++ b/formatter/formatter_test.go
@@ -74,7 +74,13 @@ func runTest(t *testing.T, test *formatterTest, changedGoldensList *ChangedGolde
 			return
 		}
 		if diff, hasDiff := testutils.CompareWithGolden(outData, golden); hasDiff {
-			t.Error(fmt.Errorf("golden file %v has diff:\n%v", test.input, diff))
+			if strings.HasPrefix(outData, string(golden)) ||
+				strings.HasPrefix(string(golden), outData) {
+				// The difference can be a trailing newline, invisible in text format.
+				fmt.Printf("actual:\n%v\n", []byte(outData))
+				fmt.Printf("expected:\n%v\n", golden)
+			}
+			t.Error(fmt.Errorf("golden file for %v has diff:\n%v", test.input, diff))
 		}
 	}
 }
diff --git a/formatter/testdata/json-to-xml.fmt.golden b/formatter/testdata/json-to-xml.fmt.golden
new file mode 100644
index 000000000..5ddebad2f
--- /dev/null
+++ b/formatter/testdata/json-to-xml.fmt.golden
@@ -0,0 +1,17 @@
+local c =
+  import "json2xml.libjsonnet";
+
+local d = {
+  name: "foo",
+
+  children: ["bar", "bam"],
+
+  attrs: {
+    class1: "abc",
+    numbers: [1, 2, 3, 4],
+  },
+};
+
+{
+  output: c.manifestXml(d, "elements"),
+}
diff --git a/formatter/testdata/json-to-xml.jsonnet b/formatter/testdata/json-to-xml.jsonnet
new file mode 100644
index 000000000..0b11f00a7
--- /dev/null
+++ b/formatter/testdata/json-to-xml.jsonnet
@@ -0,0 +1,21 @@
+local c =
+  import "json2xml.libjsonnet";
+
+local d = {
+  name:
+
+    "foo",
+
+  children:
+ ["bar", "bam"],
+
+  attrs: {
+    class1: "abc",
+    numbers: [1, 2, 3, 4],
+  },
+};
+
+{
+  output:
+  c.manifestXml(d, "elements"),
+}
diff --git a/internal/formatter/fix_newlines.go b/internal/formatter/fix_newlines.go
index 322edf605..ceff90b6a 100644
--- a/internal/formatter/fix_newlines.go
+++ b/internal/formatter/fix_newlines.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2019 Google Inc. All rights reserved.
+Copyright 2019,2024 Google LLC. All rights reserved.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -30,10 +30,12 @@ import (
 //
 // It only looks shallowly at the AST nodes, so there may be some newlines deeper that
 // don't affect expanding. For example:
-// [{
-//     'a': 'b',
-//     'c': 'd',
-// }]
+//
+//	[{
+//		    'a': 'b',
+//		    'c': 'd',
+//	}]
+//
 // The outer array can stay unexpanded, because there are no newlines between
 // the square brackets and the braces.
 type FixNewlines struct {
@@ -197,19 +199,26 @@ func (c *FixNewlines) Parens(p pass.ASTPass, parens *ast.Parens, ctx pass.Contex
 
 // Parameters handles parameters
 // Example2:
-//   f(1, 2,
-//     3)
+//
+//	f(1, 2,
+//	  3)
+//
 // Should be expanded to:
-//   f(1,
-//     2,
-//     3)
+//
+//	f(1,
+//	  2,
+//	  3)
+//
 // And:
-//   foo(
-//       1, 2, 3)
+//
+//	foo(
+//	    1, 2, 3)
+//
 // Should be expanded to:
-//   foo(
-//       1, 2, 3
-//   )
+//
+//	foo(
+//	    1, 2, 3
+//	)
 func (c *FixNewlines) Parameters(p pass.ASTPass, l *ast.Fodder, params *[]ast.Parameter, r *ast.Fodder, ctx pass.Context) {
 	shouldExpandBetween := false
 	shouldExpandNearParens := false
@@ -243,19 +252,26 @@ func (c *FixNewlines) Parameters(p pass.ASTPass, l *ast.Fodder, params *[]ast.Pa
 
 // Arguments handles parameters
 // Example2:
-//   f(1, 2,
-//     3)
+//
+//	f(1, 2,
+//	  3)
+//
 // Should be expanded to:
-//   f(1,
-//     2,
-//     3)
+//
+//	f(1,
+//	  2,
+//	  3)
+//
 // And:
-//   foo(
-//       1, 2, 3)
+//
+//	foo(
+//	    1, 2, 3)
+//
 // Should be expanded to:
-//   foo(
-//       1, 2, 3
-//   )
+//
+//	foo(
+//	    1, 2, 3
+//	)
 func (c *FixNewlines) Arguments(p pass.ASTPass, l *ast.Fodder, args *ast.Arguments, r *ast.Fodder, ctx pass.Context) {
 	shouldExpandBetween := false
 	shouldExpandNearParens := false
@@ -303,3 +319,39 @@ func (c *FixNewlines) Arguments(p pass.ASTPass, l *ast.Fodder, args *ast.Argumen
 	}
 	c.Base.Arguments(p, l, args, r, ctx)
 }
+
+// ObjectField eliminates newlines after the colon, before the expression
+//
+// Example:
+//
+//	local d = {
+//	  name:
+//
+//	    "foo",
+//	  children:
+//	 ["bar", "bam"],
+//	};
+//
+// should be formatted as:
+//
+//	local d = {
+//	  name: "foo",
+//	  children: ["bar", "bam"],
+//	};
+func (c *FixNewlines) ObjectField(p pass.ASTPass, field *ast.ObjectField, ctx pass.Context) {
+
+	switch field.Kind {
+	case ast.ObjectLocal:
+
+	case ast.ObjectFieldID:
+		removeInitialNewlines(field.Expr2)
+
+	case ast.ObjectFieldStr:
+
+	case ast.ObjectFieldExpr:
+
+	case ast.ObjectAssert:
+	}
+
+	c.Base.ObjectField(p, field, ctx)
+}