pkg: added some manually crafted builtins
Change-Id: I1e5d8b987b2fbd2605a9ff5853dc3b1e7eb9b620
diff --git a/pkg/encoding/json/manual.go b/pkg/encoding/json/manual.go
new file mode 100644
index 0000000..9b2d324
--- /dev/null
+++ b/pkg/encoding/json/manual.go
@@ -0,0 +1,104 @@
+// Copyright 2018 The CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package json
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+
+ "cuelang.org/go/cue"
+ "cuelang.org/go/cue/parser"
+ "cuelang.org/go/cue/token"
+)
+
+// Compact generates the JSON-encoded src with insignificant space characters
+// elided.
+func Compact(src []byte) (string, error) {
+ dst := bytes.Buffer{}
+ if err := json.Compact(&dst, src); err != nil {
+ return "", err
+ }
+ return dst.String(), nil
+}
+
+// Indent creates an indented form of the JSON-encoded src.
+// Each element in a JSON object or array begins on a new,
+// indented line beginning with prefix followed by one or more
+// copies of indent according to the indentation nesting.
+// The data appended to dst does not begin with the prefix nor
+// any indentation, to make it easier to embed inside other formatted JSON data.
+// Although leading space characters (space, tab, carriage return, newline)
+// at the beginning of src are dropped, trailing space characters
+// at the end of src are preserved and copied to dst.
+// For example, if src has no trailing spaces, neither will dst;
+// if src ends in a trailing newline, so will dst.
+func Indent(src []byte, prefix, indent string) (string, error) {
+ dst := bytes.Buffer{}
+ if err := json.Indent(&dst, src, prefix, indent); err != nil {
+ return "", err
+ }
+ return dst.String(), nil
+}
+
+// HTMLEscape returns the JSON-encoded src with <, >, &, U+2028 and
+// U+2029 characters inside string literals changed to \u003c, \u003e, \u0026,
+// \u2028, \u2029 so that the JSON will be safe to embed inside HTML <script>
+// tags. For historical reasons, web browsers don't honor standard HTML escaping
+// within <script> tags, so an alternative JSON encoding must be used.
+func HTMLEscape(src []byte) string {
+ dst := &bytes.Buffer{}
+ json.HTMLEscape(dst, src)
+ return dst.String()
+}
+
+// Marshal returns the JSON encoding of v.
+func Marshal(v cue.Value) (string, error) {
+ b, err := json.Marshal(v)
+ return string(b), err
+}
+
+// MarshalStream turns a list into a stream of JSON objects.
+func MarshalStream(v cue.Value) (string, error) {
+ // TODO: return an io.Reader and allow asynchronous processing.
+ iter, err := v.List()
+ if err != nil {
+ return "", err
+ }
+ buf := &bytes.Buffer{}
+ for iter.Next() {
+ b, err := json.Marshal(iter.Value())
+ if err != nil {
+ return "", err
+ }
+ buf.Write(b)
+ buf.WriteByte('\n')
+ }
+ return buf.String(), nil
+}
+
+// Unmarshal parses the JSON-encoded data.
+func Unmarshal(b []byte) (*cue.Instance, error) {
+ if !json.Valid(b) {
+ return nil, fmt.Errorf("json: invalid JSON")
+ }
+ fset := token.NewFileSet()
+ expr, err := parser.ParseExpr(fset, "json", b)
+ if err != nil {
+ // NOTE: should never happen.
+ return nil, fmt.Errorf("json: could not parse JSON: %v", err)
+ }
+ return cue.FromExpr(fset, expr)
+}