Use JSON escaping for JSON string output

The previous code used Value::ToString to convert GN strings into quoted
JSON strings, but this caused incorrect escaping behavior. For example,
the string "$" needs to be escaped in Ninja to prevent accidental
variable expansion but not in JSON.

Change-Id: I91c8e9b2486a67af5a3ba41efdb731aa31cc6df3
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/18900
Commit-Queue: Takuto Ikuta <tikuta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
diff --git a/src/gn/output_conversion.cc b/src/gn/output_conversion.cc
index 971e740..3bfbb10 100644
--- a/src/gn/output_conversion.cc
+++ b/src/gn/output_conversion.cc
@@ -4,6 +4,7 @@
 
 #include "gn/output_conversion.h"
 
+#include "gn/escape.h"
 #include "gn/settings.h"
 #include "gn/value.h"
 
@@ -37,8 +38,10 @@
       RenderScopeToJSON(value, out, indent + 1);
     else if (value.type() == Value::LIST)
       RenderListToJSON(value, out, indent + 1);
+    else if (value.type() == Value::STRING)
+      EscapeJSONStringToStream(out, value.ToString(false), EscapeOptions());
     else
-      out << value.ToString(true);
+      out << value.ToString(false);
     first = false;
   }
   out << "\n";
@@ -61,8 +64,11 @@
       RenderScopeToJSON(pair.second, out, indent + 1);
     else if (pair.second.type() == Value::LIST)
       RenderListToJSON(pair.second, out, indent + 1);
+    else if (pair.second.type() == Value::STRING)
+      EscapeJSONStringToStream(out, pair.second.ToString(false),
+                               EscapeOptions());
     else
-      out << pair.second.ToString(true);
+      out << pair.second.ToString(false);
     first = false;
   }
   out << "\n";
diff --git a/src/gn/output_conversion_unittest.cc b/src/gn/output_conversion_unittest.cc
index 43fdad5..1eaf2ab 100644
--- a/src/gn/output_conversion_unittest.cc
+++ b/src/gn/output_conversion_unittest.cc
@@ -186,8 +186,11 @@
   auto c_scope = std::make_unique<Scope>(settings());
   Value e_value(nullptr, Value::LIST);
   e_value.list_value().push_back(Value(nullptr, "bar"));
+  e_value.list_value().push_back(Value(nullptr, "$"));
 
   auto e_value_scope = std::make_unique<Scope>(settings());
+  Value d_value(nullptr, "$");
+  e_value_scope->SetValue("d", d_value, nullptr);
   Value f_value(nullptr, "baz");
   e_value_scope->SetValue("f", f_value, nullptr);
   e_value.list_value().push_back(Value(nullptr, std::move(e_value_scope)));
@@ -202,7 +205,9 @@
   "c": {
     "e": [
       "bar",
+      "$",
       {
+        "d": "$",
         "f": "baz"
       }
     ]