| 146 | } |
| 147 | |
| 148 | func promptJSON(reader io.Reader, line string) (string, error) { |
| 149 | var data bytes.Buffer |
| 150 | for { |
| 151 | _, _ = data.WriteString(line) |
| 152 | var rawMessage json.RawMessage |
| 153 | err := json.Unmarshal(data.Bytes(), &rawMessage) |
| 154 | if err != nil { |
| 155 | if err.Error() != "unexpected end of JSON input" { |
| 156 | // If a real syntax error occurs in JSON, |
| 157 | // we want to return that partial line to the user. |
| 158 | err = nil |
| 159 | line = data.String() |
| 160 | break |
| 161 | } |
| 162 | |
| 163 | // Read line-by-line. We can't use a JSON decoder |
| 164 | // here because it doesn't work by newline, so |
| 165 | // reads will block. |
| 166 | line, err = readUntil(reader, '\n') |
| 167 | if err != nil { |
| 168 | break |
| 169 | } |
| 170 | continue |
| 171 | } |
| 172 | // Compacting the JSON makes it easier for parsing and testing. |
| 173 | rawJSON := data.Bytes() |
| 174 | data.Reset() |
| 175 | err = json.Compact(&data, rawJSON) |
| 176 | if err != nil { |
| 177 | return line, xerrors.Errorf("compact json: %w", err) |
| 178 | } |
| 179 | return data.String(), nil |
| 180 | } |
| 181 | return line, nil |
| 182 | } |
| 183 | |
| 184 | // readUntil the first occurrence of delim in the input, returning a string containing the data up |
| 185 | // to and including the delimiter. Unlike `bufio`, it only reads until the delimiter and no further |