1 #ifndef SRC_JSON_UTILS_H_
2 #define SRC_JSON_UTILS_H_
3
4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6 #include <iomanip>
7 #include <limits>
8 #include <ostream>
9 #include <string>
10 #include <string_view>
11
12 namespace node {
13
NeedsJsonEscape(std::string_view str)14 constexpr bool NeedsJsonEscape(std::string_view str) {
15 for (const char c : str) {
16 if (c == '\\' || c == '"' || c < 0x20) return true;
17 }
18 return false;
19 }
20
21 std::string EscapeJsonChars(std::string_view str);
22 std::string Reindent(const std::string& str, int indentation);
23
24 // JSON compiler definitions.
25 class JSONWriter {
26 public:
JSONWriter(std::ostream & out,bool compact)27 JSONWriter(std::ostream& out, bool compact)
28 : out_(out), compact_(compact) {}
29
30 private:
indent()31 inline void indent() { indent_ += 2; }
deindent()32 inline void deindent() { indent_ -= 2; }
advance()33 inline void advance() {
34 if (compact_) return;
35 for (int i = 0; i < indent_; i++) out_ << ' ';
36 }
write_one_space()37 inline void write_one_space() {
38 if (compact_) return;
39 out_ << ' ';
40 }
write_new_line()41 inline void write_new_line() {
42 if (compact_) return;
43 out_ << '\n';
44 }
45
46 public:
json_start()47 inline void json_start() {
48 if (state_ == kAfterValue) out_ << ',';
49 write_new_line();
50 advance();
51 out_ << '{';
52 indent();
53 state_ = kObjectStart;
54 }
55
json_end()56 inline void json_end() {
57 write_new_line();
58 deindent();
59 advance();
60 out_ << '}';
61 state_ = kAfterValue;
62 }
63 template <typename T>
json_objectstart(T key)64 inline void json_objectstart(T key) {
65 if (state_ == kAfterValue) out_ << ',';
66 write_new_line();
67 advance();
68 write_string(key);
69 out_ << ':';
70 write_one_space();
71 out_ << '{';
72 indent();
73 state_ = kObjectStart;
74 }
75
76 template <typename T>
json_arraystart(T key)77 inline void json_arraystart(T key) {
78 if (state_ == kAfterValue) out_ << ',';
79 write_new_line();
80 advance();
81 write_string(key);
82 out_ << ':';
83 write_one_space();
84 out_ << '[';
85 indent();
86 state_ = kObjectStart;
87 }
json_objectend()88 inline void json_objectend() {
89 write_new_line();
90 deindent();
91 advance();
92 out_ << '}';
93 if (indent_ == 0) {
94 // Top-level object is complete, so end the line.
95 out_ << '\n';
96 }
97 state_ = kAfterValue;
98 }
99
json_arrayend()100 inline void json_arrayend() {
101 write_new_line();
102 deindent();
103 advance();
104 out_ << ']';
105 state_ = kAfterValue;
106 }
107 template <typename T, typename U>
json_keyvalue(const T & key,const U & value)108 inline void json_keyvalue(const T& key, const U& value) {
109 if (state_ == kAfterValue) out_ << ',';
110 write_new_line();
111 advance();
112 write_string(key);
113 out_ << ':';
114 write_one_space();
115 write_value(value);
116 state_ = kAfterValue;
117 }
118
119 template <typename U>
json_element(const U & value)120 inline void json_element(const U& value) {
121 if (state_ == kAfterValue) out_ << ',';
122 write_new_line();
123 advance();
124 write_value(value);
125 state_ = kAfterValue;
126 }
127
128 struct Null {}; // Usable as a JSON value.
129
130 struct ForeignJSON {
131 std::string as_string;
132 };
133
134 private:
135 template <typename T,
136 typename test_for_number = typename std::
137 enable_if<std::numeric_limits<T>::is_specialized, bool>::type>
write_value(T number)138 inline void write_value(T number) {
139 if constexpr (std::is_same<T, bool>::value)
140 out_ << (number ? "true" : "false");
141 else
142 out_ << number;
143 }
144
write_value(Null null)145 inline void write_value(Null null) { out_ << "null"; }
write_value(std::string_view str)146 inline void write_value(std::string_view str) { write_string(str); }
147
write_value(const ForeignJSON & json)148 inline void write_value(const ForeignJSON& json) {
149 out_ << Reindent(json.as_string, indent_);
150 }
151
write_string(std::string_view str)152 inline void write_string(std::string_view str) {
153 out_ << '"';
154 if (NeedsJsonEscape(str)) // only create temporary std::string if necessary
155 out_ << EscapeJsonChars(str);
156 else
157 out_ << str;
158 out_ << '"';
159 }
160
161 enum JSONState { kObjectStart, kAfterValue };
162 std::ostream& out_;
163 bool compact_;
164 int indent_ = 0;
165 int state_ = kObjectStart;
166 };
167
168 } // namespace node
169
170 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
171
172 #endif // SRC_JSON_UTILS_H_
173