blob: 9b2d324056be1f47f86306a7027f033a992a0d7d [file] [log] [blame]
Marcel van Lohuizenc24a5192018-12-11 11:50:44 +01001// Copyright 2018 The CUE Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package json
16
17import (
18 "bytes"
19 "encoding/json"
20 "fmt"
21
22 "cuelang.org/go/cue"
23 "cuelang.org/go/cue/parser"
24 "cuelang.org/go/cue/token"
25)
26
27// Compact generates the JSON-encoded src with insignificant space characters
28// elided.
29func Compact(src []byte) (string, error) {
30 dst := bytes.Buffer{}
31 if err := json.Compact(&dst, src); err != nil {
32 return "", err
33 }
34 return dst.String(), nil
35}
36
37// Indent creates an indented form of the JSON-encoded src.
38// Each element in a JSON object or array begins on a new,
39// indented line beginning with prefix followed by one or more
40// copies of indent according to the indentation nesting.
41// The data appended to dst does not begin with the prefix nor
42// any indentation, to make it easier to embed inside other formatted JSON data.
43// Although leading space characters (space, tab, carriage return, newline)
44// at the beginning of src are dropped, trailing space characters
45// at the end of src are preserved and copied to dst.
46// For example, if src has no trailing spaces, neither will dst;
47// if src ends in a trailing newline, so will dst.
48func Indent(src []byte, prefix, indent string) (string, error) {
49 dst := bytes.Buffer{}
50 if err := json.Indent(&dst, src, prefix, indent); err != nil {
51 return "", err
52 }
53 return dst.String(), nil
54}
55
56// HTMLEscape returns the JSON-encoded src with <, >, &, U+2028 and
57// U+2029 characters inside string literals changed to \u003c, \u003e, \u0026,
58// \u2028, \u2029 so that the JSON will be safe to embed inside HTML <script>
59// tags. For historical reasons, web browsers don't honor standard HTML escaping
60// within <script> tags, so an alternative JSON encoding must be used.
61func HTMLEscape(src []byte) string {
62 dst := &bytes.Buffer{}
63 json.HTMLEscape(dst, src)
64 return dst.String()
65}
66
67// Marshal returns the JSON encoding of v.
68func Marshal(v cue.Value) (string, error) {
69 b, err := json.Marshal(v)
70 return string(b), err
71}
72
73// MarshalStream turns a list into a stream of JSON objects.
74func MarshalStream(v cue.Value) (string, error) {
75 // TODO: return an io.Reader and allow asynchronous processing.
76 iter, err := v.List()
77 if err != nil {
78 return "", err
79 }
80 buf := &bytes.Buffer{}
81 for iter.Next() {
82 b, err := json.Marshal(iter.Value())
83 if err != nil {
84 return "", err
85 }
86 buf.Write(b)
87 buf.WriteByte('\n')
88 }
89 return buf.String(), nil
90}
91
92// Unmarshal parses the JSON-encoded data.
93func Unmarshal(b []byte) (*cue.Instance, error) {
94 if !json.Valid(b) {
95 return nil, fmt.Errorf("json: invalid JSON")
96 }
97 fset := token.NewFileSet()
98 expr, err := parser.ParseExpr(fset, "json", b)
99 if err != nil {
100 // NOTE: should never happen.
101 return nil, fmt.Errorf("json: could not parse JSON: %v", err)
102 }
103 return cue.FromExpr(fset, expr)
104}