...

Source file src/github.com/evanphx/json-patch/patch.go

Documentation: github.com/evanphx/json-patch

     1  package jsonpatch
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/pkg/errors"
    11  )
    12  
    13  const (
    14  	eRaw = iota
    15  	eDoc
    16  	eAry
    17  )
    18  
    19  var (
    20  	// SupportNegativeIndices decides whether to support non-standard practice of
    21  	// allowing negative indices to mean indices starting at the end of an array.
    22  	// Default to true.
    23  	SupportNegativeIndices bool = true
    24  	// AccumulatedCopySizeLimit limits the total size increase in bytes caused by
    25  	// "copy" operations in a patch.
    26  	AccumulatedCopySizeLimit int64 = 0
    27  )
    28  
    29  var (
    30  	ErrTestFailed   = errors.New("test failed")
    31  	ErrMissing      = errors.New("missing value")
    32  	ErrUnknownType  = errors.New("unknown object type")
    33  	ErrInvalid      = errors.New("invalid state detected")
    34  	ErrInvalidIndex = errors.New("invalid index referenced")
    35  )
    36  
    37  type lazyNode struct {
    38  	raw   *json.RawMessage
    39  	doc   partialDoc
    40  	ary   partialArray
    41  	which int
    42  }
    43  
    44  // Operation is a single JSON-Patch step, such as a single 'add' operation.
    45  type Operation map[string]*json.RawMessage
    46  
    47  // Patch is an ordered collection of Operations.
    48  type Patch []Operation
    49  
    50  type partialDoc map[string]*lazyNode
    51  type partialArray []*lazyNode
    52  
    53  type container interface {
    54  	get(key string) (*lazyNode, error)
    55  	set(key string, val *lazyNode) error
    56  	add(key string, val *lazyNode) error
    57  	remove(key string) error
    58  }
    59  
    60  func newLazyNode(raw *json.RawMessage) *lazyNode {
    61  	return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw}
    62  }
    63  
    64  func (n *lazyNode) MarshalJSON() ([]byte, error) {
    65  	switch n.which {
    66  	case eRaw:
    67  		return json.Marshal(n.raw)
    68  	case eDoc:
    69  		return json.Marshal(n.doc)
    70  	case eAry:
    71  		return json.Marshal(n.ary)
    72  	default:
    73  		return nil, ErrUnknownType
    74  	}
    75  }
    76  
    77  func (n *lazyNode) UnmarshalJSON(data []byte) error {
    78  	dest := make(json.RawMessage, len(data))
    79  	copy(dest, data)
    80  	n.raw = &dest
    81  	n.which = eRaw
    82  	return nil
    83  }
    84  
    85  func deepCopy(src *lazyNode) (*lazyNode, int, error) {
    86  	if src == nil {
    87  		return nil, 0, nil
    88  	}
    89  	a, err := src.MarshalJSON()
    90  	if err != nil {
    91  		return nil, 0, err
    92  	}
    93  	sz := len(a)
    94  	ra := make(json.RawMessage, sz)
    95  	copy(ra, a)
    96  	return newLazyNode(&ra), sz, nil
    97  }
    98  
    99  func (n *lazyNode) intoDoc() (*partialDoc, error) {
   100  	if n.which == eDoc {
   101  		return &n.doc, nil
   102  	}
   103  
   104  	if n.raw == nil {
   105  		return nil, ErrInvalid
   106  	}
   107  
   108  	err := json.Unmarshal(*n.raw, &n.doc)
   109  
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	n.which = eDoc
   115  	return &n.doc, nil
   116  }
   117  
   118  func (n *lazyNode) intoAry() (*partialArray, error) {
   119  	if n.which == eAry {
   120  		return &n.ary, nil
   121  	}
   122  
   123  	if n.raw == nil {
   124  		return nil, ErrInvalid
   125  	}
   126  
   127  	err := json.Unmarshal(*n.raw, &n.ary)
   128  
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	n.which = eAry
   134  	return &n.ary, nil
   135  }
   136  
   137  func (n *lazyNode) compact() []byte {
   138  	buf := &bytes.Buffer{}
   139  
   140  	if n.raw == nil {
   141  		return nil
   142  	}
   143  
   144  	err := json.Compact(buf, *n.raw)
   145  
   146  	if err != nil {
   147  		return *n.raw
   148  	}
   149  
   150  	return buf.Bytes()
   151  }
   152  
   153  func (n *lazyNode) tryDoc() bool {
   154  	if n.raw == nil {
   155  		return false
   156  	}
   157  
   158  	err := json.Unmarshal(*n.raw, &n.doc)
   159  
   160  	if err != nil {
   161  		return false
   162  	}
   163  
   164  	n.which = eDoc
   165  	return true
   166  }
   167  
   168  func (n *lazyNode) tryAry() bool {
   169  	if n.raw == nil {
   170  		return false
   171  	}
   172  
   173  	err := json.Unmarshal(*n.raw, &n.ary)
   174  
   175  	if err != nil {
   176  		return false
   177  	}
   178  
   179  	n.which = eAry
   180  	return true
   181  }
   182  
   183  func (n *lazyNode) equal(o *lazyNode) bool {
   184  	if n.which == eRaw {
   185  		if !n.tryDoc() && !n.tryAry() {
   186  			if o.which != eRaw {
   187  				return false
   188  			}
   189  
   190  			return bytes.Equal(n.compact(), o.compact())
   191  		}
   192  	}
   193  
   194  	if n.which == eDoc {
   195  		if o.which == eRaw {
   196  			if !o.tryDoc() {
   197  				return false
   198  			}
   199  		}
   200  
   201  		if o.which != eDoc {
   202  			return false
   203  		}
   204  
   205  		if len(n.doc) != len(o.doc) {
   206  			return false
   207  		}
   208  
   209  		for k, v := range n.doc {
   210  			ov, ok := o.doc[k]
   211  
   212  			if !ok {
   213  				return false
   214  			}
   215  
   216  			if (v == nil) != (ov == nil) {
   217  				return false
   218  			}
   219  
   220  			if v == nil && ov == nil {
   221  				continue
   222  			}
   223  
   224  			if !v.equal(ov) {
   225  				return false
   226  			}
   227  		}
   228  
   229  		return true
   230  	}
   231  
   232  	if o.which != eAry && !o.tryAry() {
   233  		return false
   234  	}
   235  
   236  	if len(n.ary) != len(o.ary) {
   237  		return false
   238  	}
   239  
   240  	for idx, val := range n.ary {
   241  		if !val.equal(o.ary[idx]) {
   242  			return false
   243  		}
   244  	}
   245  
   246  	return true
   247  }
   248  
   249  // Kind reads the "op" field of the Operation.
   250  func (o Operation) Kind() string {
   251  	if obj, ok := o["op"]; ok && obj != nil {
   252  		var op string
   253  
   254  		err := json.Unmarshal(*obj, &op)
   255  
   256  		if err != nil {
   257  			return "unknown"
   258  		}
   259  
   260  		return op
   261  	}
   262  
   263  	return "unknown"
   264  }
   265  
   266  // Path reads the "path" field of the Operation.
   267  func (o Operation) Path() (string, error) {
   268  	if obj, ok := o["path"]; ok && obj != nil {
   269  		var op string
   270  
   271  		err := json.Unmarshal(*obj, &op)
   272  
   273  		if err != nil {
   274  			return "unknown", err
   275  		}
   276  
   277  		return op, nil
   278  	}
   279  
   280  	return "unknown", errors.Wrapf(ErrMissing, "operation missing path field")
   281  }
   282  
   283  // From reads the "from" field of the Operation.
   284  func (o Operation) From() (string, error) {
   285  	if obj, ok := o["from"]; ok && obj != nil {
   286  		var op string
   287  
   288  		err := json.Unmarshal(*obj, &op)
   289  
   290  		if err != nil {
   291  			return "unknown", err
   292  		}
   293  
   294  		return op, nil
   295  	}
   296  
   297  	return "unknown", errors.Wrapf(ErrMissing, "operation, missing from field")
   298  }
   299  
   300  func (o Operation) value() *lazyNode {
   301  	if obj, ok := o["value"]; ok {
   302  		return newLazyNode(obj)
   303  	}
   304  
   305  	return nil
   306  }
   307  
   308  // ValueInterface decodes the operation value into an interface.
   309  func (o Operation) ValueInterface() (interface{}, error) {
   310  	if obj, ok := o["value"]; ok && obj != nil {
   311  		var v interface{}
   312  
   313  		err := json.Unmarshal(*obj, &v)
   314  
   315  		if err != nil {
   316  			return nil, err
   317  		}
   318  
   319  		return v, nil
   320  	}
   321  
   322  	return nil, errors.Wrapf(ErrMissing, "operation, missing value field")
   323  }
   324  
   325  func isArray(buf []byte) bool {
   326  Loop:
   327  	for _, c := range buf {
   328  		switch c {
   329  		case ' ':
   330  		case '\n':
   331  		case '\t':
   332  			continue
   333  		case '[':
   334  			return true
   335  		default:
   336  			break Loop
   337  		}
   338  	}
   339  
   340  	return false
   341  }
   342  
   343  func findObject(pd *container, path string) (container, string) {
   344  	doc := *pd
   345  
   346  	split := strings.Split(path, "/")
   347  
   348  	if len(split) < 2 {
   349  		return nil, ""
   350  	}
   351  
   352  	parts := split[1 : len(split)-1]
   353  
   354  	key := split[len(split)-1]
   355  
   356  	var err error
   357  
   358  	for _, part := range parts {
   359  
   360  		next, ok := doc.get(decodePatchKey(part))
   361  
   362  		if next == nil || ok != nil || next.raw == nil {
   363  			return nil, ""
   364  		}
   365  
   366  		if isArray(*next.raw) {
   367  			doc, err = next.intoAry()
   368  
   369  			if err != nil {
   370  				return nil, ""
   371  			}
   372  		} else {
   373  			doc, err = next.intoDoc()
   374  
   375  			if err != nil {
   376  				return nil, ""
   377  			}
   378  		}
   379  	}
   380  
   381  	return doc, decodePatchKey(key)
   382  }
   383  
   384  func (d *partialDoc) set(key string, val *lazyNode) error {
   385  	(*d)[key] = val
   386  	return nil
   387  }
   388  
   389  func (d *partialDoc) add(key string, val *lazyNode) error {
   390  	(*d)[key] = val
   391  	return nil
   392  }
   393  
   394  func (d *partialDoc) get(key string) (*lazyNode, error) {
   395  	return (*d)[key], nil
   396  }
   397  
   398  func (d *partialDoc) remove(key string) error {
   399  	_, ok := (*d)[key]
   400  	if !ok {
   401  		return errors.Wrapf(ErrMissing, "Unable to remove nonexistent key: %s", key)
   402  	}
   403  
   404  	delete(*d, key)
   405  	return nil
   406  }
   407  
   408  // set should only be used to implement the "replace" operation, so "key" must
   409  // be an already existing index in "d".
   410  func (d *partialArray) set(key string, val *lazyNode) error {
   411  	idx, err := strconv.Atoi(key)
   412  	if err != nil {
   413  		return err
   414  	}
   415  
   416  	if idx < 0 {
   417  		if !SupportNegativeIndices {
   418  			return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
   419  		}
   420  		if idx < -len(*d) {
   421  			return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
   422  		}
   423  		idx += len(*d)
   424  	}
   425  
   426  	(*d)[idx] = val
   427  	return nil
   428  }
   429  
   430  func (d *partialArray) add(key string, val *lazyNode) error {
   431  	if key == "-" {
   432  		*d = append(*d, val)
   433  		return nil
   434  	}
   435  
   436  	idx, err := strconv.Atoi(key)
   437  	if err != nil {
   438  		return errors.Wrapf(err, "value was not a proper array index: '%s'", key)
   439  	}
   440  
   441  	sz := len(*d) + 1
   442  
   443  	ary := make([]*lazyNode, sz)
   444  
   445  	cur := *d
   446  
   447  	if idx >= len(ary) {
   448  		return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
   449  	}
   450  
   451  	if idx < 0 {
   452  		if !SupportNegativeIndices {
   453  			return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
   454  		}
   455  		if idx < -len(ary) {
   456  			return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
   457  		}
   458  		idx += len(ary)
   459  	}
   460  
   461  	copy(ary[0:idx], cur[0:idx])
   462  	ary[idx] = val
   463  	copy(ary[idx+1:], cur[idx:])
   464  
   465  	*d = ary
   466  	return nil
   467  }
   468  
   469  func (d *partialArray) get(key string) (*lazyNode, error) {
   470  	idx, err := strconv.Atoi(key)
   471  
   472  	if err != nil {
   473  		return nil, err
   474  	}
   475  
   476  	if idx < 0 {
   477  		if !SupportNegativeIndices {
   478  			return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
   479  		}
   480  		if idx < -len(*d) {
   481  			return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
   482  		}
   483  		idx += len(*d)
   484  	}
   485  
   486  	if idx >= len(*d) {
   487  		return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
   488  	}
   489  
   490  	return (*d)[idx], nil
   491  }
   492  
   493  func (d *partialArray) remove(key string) error {
   494  	idx, err := strconv.Atoi(key)
   495  	if err != nil {
   496  		return err
   497  	}
   498  
   499  	cur := *d
   500  
   501  	if idx >= len(cur) {
   502  		return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
   503  	}
   504  
   505  	if idx < 0 {
   506  		if !SupportNegativeIndices {
   507  			return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
   508  		}
   509  		if idx < -len(cur) {
   510  			return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
   511  		}
   512  		idx += len(cur)
   513  	}
   514  
   515  	ary := make([]*lazyNode, len(cur)-1)
   516  
   517  	copy(ary[0:idx], cur[0:idx])
   518  	copy(ary[idx:], cur[idx+1:])
   519  
   520  	*d = ary
   521  	return nil
   522  
   523  }
   524  
   525  func (p Patch) add(doc *container, op Operation) error {
   526  	path, err := op.Path()
   527  	if err != nil {
   528  		return errors.Wrapf(ErrMissing, "add operation failed to decode path")
   529  	}
   530  
   531  	con, key := findObject(doc, path)
   532  
   533  	if con == nil {
   534  		return errors.Wrapf(ErrMissing, "add operation does not apply: doc is missing path: \"%s\"", path)
   535  	}
   536  
   537  	err = con.add(key, op.value())
   538  	if err != nil {
   539  		return errors.Wrapf(err, "error in add for path: '%s'", path)
   540  	}
   541  
   542  	return nil
   543  }
   544  
   545  func (p Patch) remove(doc *container, op Operation) error {
   546  	path, err := op.Path()
   547  	if err != nil {
   548  		return errors.Wrapf(ErrMissing, "remove operation failed to decode path")
   549  	}
   550  
   551  	con, key := findObject(doc, path)
   552  
   553  	if con == nil {
   554  		return errors.Wrapf(ErrMissing, "remove operation does not apply: doc is missing path: \"%s\"", path)
   555  	}
   556  
   557  	err = con.remove(key)
   558  	if err != nil {
   559  		return errors.Wrapf(err, "error in remove for path: '%s'", path)
   560  	}
   561  
   562  	return nil
   563  }
   564  
   565  func (p Patch) replace(doc *container, op Operation) error {
   566  	path, err := op.Path()
   567  	if err != nil {
   568  		return errors.Wrapf(err, "replace operation failed to decode path")
   569  	}
   570  
   571  	if path == "" {
   572  		val := op.value()
   573  
   574  		if val.which == eRaw {
   575  			if !val.tryDoc() {
   576  				if !val.tryAry() {
   577  					return errors.Wrapf(err, "replace operation value must be object or array")
   578  				}
   579  			}
   580  		}
   581  
   582  		switch val.which {
   583  		case eAry:
   584  			*doc = &val.ary
   585  		case eDoc:
   586  			*doc = &val.doc
   587  		case eRaw:
   588  			return errors.Wrapf(err, "replace operation hit impossible case")
   589  		}
   590  
   591  		return nil
   592  	}
   593  
   594  	con, key := findObject(doc, path)
   595  
   596  	if con == nil {
   597  		return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing path: %s", path)
   598  	}
   599  
   600  	_, ok := con.get(key)
   601  	if ok != nil {
   602  		return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing key: %s", path)
   603  	}
   604  
   605  	err = con.set(key, op.value())
   606  	if err != nil {
   607  		return errors.Wrapf(err, "error in remove for path: '%s'", path)
   608  	}
   609  
   610  	return nil
   611  }
   612  
   613  func (p Patch) move(doc *container, op Operation) error {
   614  	from, err := op.From()
   615  	if err != nil {
   616  		return errors.Wrapf(err, "move operation failed to decode from")
   617  	}
   618  
   619  	con, key := findObject(doc, from)
   620  
   621  	if con == nil {
   622  		return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing from path: %s", from)
   623  	}
   624  
   625  	val, err := con.get(key)
   626  	if err != nil {
   627  		return errors.Wrapf(err, "error in move for path: '%s'", key)
   628  	}
   629  
   630  	err = con.remove(key)
   631  	if err != nil {
   632  		return errors.Wrapf(err, "error in move for path: '%s'", key)
   633  	}
   634  
   635  	path, err := op.Path()
   636  	if err != nil {
   637  		return errors.Wrapf(err, "move operation failed to decode path")
   638  	}
   639  
   640  	con, key = findObject(doc, path)
   641  
   642  	if con == nil {
   643  		return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing destination path: %s", path)
   644  	}
   645  
   646  	err = con.add(key, val)
   647  	if err != nil {
   648  		return errors.Wrapf(err, "error in move for path: '%s'", path)
   649  	}
   650  
   651  	return nil
   652  }
   653  
   654  func (p Patch) test(doc *container, op Operation) error {
   655  	path, err := op.Path()
   656  	if err != nil {
   657  		return errors.Wrapf(err, "test operation failed to decode path")
   658  	}
   659  
   660  	if path == "" {
   661  		var self lazyNode
   662  
   663  		switch sv := (*doc).(type) {
   664  		case *partialDoc:
   665  			self.doc = *sv
   666  			self.which = eDoc
   667  		case *partialArray:
   668  			self.ary = *sv
   669  			self.which = eAry
   670  		}
   671  
   672  		if self.equal(op.value()) {
   673  			return nil
   674  		}
   675  
   676  		return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
   677  	}
   678  
   679  	con, key := findObject(doc, path)
   680  
   681  	if con == nil {
   682  		return errors.Wrapf(ErrMissing, "test operation does not apply: is missing path: %s", path)
   683  	}
   684  
   685  	val, err := con.get(key)
   686  	if err != nil {
   687  		return errors.Wrapf(err, "error in test for path: '%s'", path)
   688  	}
   689  
   690  	if val == nil {
   691  		if op.value() == nil || op.value().raw == nil {
   692  			return nil
   693  		}
   694  		return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
   695  	} else if op.value() == nil {
   696  		return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
   697  	}
   698  
   699  	if val.equal(op.value()) {
   700  		return nil
   701  	}
   702  
   703  	return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
   704  }
   705  
   706  func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64) error {
   707  	from, err := op.From()
   708  	if err != nil {
   709  		return errors.Wrapf(err, "copy operation failed to decode from")
   710  	}
   711  
   712  	con, key := findObject(doc, from)
   713  
   714  	if con == nil {
   715  		return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing from path: %s", from)
   716  	}
   717  
   718  	val, err := con.get(key)
   719  	if err != nil {
   720  		return errors.Wrapf(err, "error in copy for from: '%s'", from)
   721  	}
   722  
   723  	path, err := op.Path()
   724  	if err != nil {
   725  		return errors.Wrapf(ErrMissing, "copy operation failed to decode path")
   726  	}
   727  
   728  	con, key = findObject(doc, path)
   729  
   730  	if con == nil {
   731  		return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing destination path: %s", path)
   732  	}
   733  
   734  	valCopy, sz, err := deepCopy(val)
   735  	if err != nil {
   736  		return errors.Wrapf(err, "error while performing deep copy")
   737  	}
   738  
   739  	(*accumulatedCopySize) += int64(sz)
   740  	if AccumulatedCopySizeLimit > 0 && *accumulatedCopySize > AccumulatedCopySizeLimit {
   741  		return NewAccumulatedCopySizeError(AccumulatedCopySizeLimit, *accumulatedCopySize)
   742  	}
   743  
   744  	err = con.add(key, valCopy)
   745  	if err != nil {
   746  		return errors.Wrapf(err, "error while adding value during copy")
   747  	}
   748  
   749  	return nil
   750  }
   751  
   752  // Equal indicates if 2 JSON documents have the same structural equality.
   753  func Equal(a, b []byte) bool {
   754  	ra := make(json.RawMessage, len(a))
   755  	copy(ra, a)
   756  	la := newLazyNode(&ra)
   757  
   758  	rb := make(json.RawMessage, len(b))
   759  	copy(rb, b)
   760  	lb := newLazyNode(&rb)
   761  
   762  	return la.equal(lb)
   763  }
   764  
   765  // DecodePatch decodes the passed JSON document as an RFC 6902 patch.
   766  func DecodePatch(buf []byte) (Patch, error) {
   767  	var p Patch
   768  
   769  	err := json.Unmarshal(buf, &p)
   770  
   771  	if err != nil {
   772  		return nil, err
   773  	}
   774  
   775  	return p, nil
   776  }
   777  
   778  // Apply mutates a JSON document according to the patch, and returns the new
   779  // document.
   780  func (p Patch) Apply(doc []byte) ([]byte, error) {
   781  	return p.ApplyIndent(doc, "")
   782  }
   783  
   784  // ApplyIndent mutates a JSON document according to the patch, and returns the new
   785  // document indented.
   786  func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
   787  	if len(doc) == 0 {
   788  		return doc, nil
   789  	}
   790  
   791  	var pd container
   792  	if doc[0] == '[' {
   793  		pd = &partialArray{}
   794  	} else {
   795  		pd = &partialDoc{}
   796  	}
   797  
   798  	err := json.Unmarshal(doc, pd)
   799  
   800  	if err != nil {
   801  		return nil, err
   802  	}
   803  
   804  	err = nil
   805  
   806  	var accumulatedCopySize int64
   807  
   808  	for _, op := range p {
   809  		switch op.Kind() {
   810  		case "add":
   811  			err = p.add(&pd, op)
   812  		case "remove":
   813  			err = p.remove(&pd, op)
   814  		case "replace":
   815  			err = p.replace(&pd, op)
   816  		case "move":
   817  			err = p.move(&pd, op)
   818  		case "test":
   819  			err = p.test(&pd, op)
   820  		case "copy":
   821  			err = p.copy(&pd, op, &accumulatedCopySize)
   822  		default:
   823  			err = fmt.Errorf("Unexpected kind: %s", op.Kind())
   824  		}
   825  
   826  		if err != nil {
   827  			return nil, err
   828  		}
   829  	}
   830  
   831  	if indent != "" {
   832  		return json.MarshalIndent(pd, "", indent)
   833  	}
   834  
   835  	return json.Marshal(pd)
   836  }
   837  
   838  // From http://tools.ietf.org/html/rfc6901#section-4 :
   839  //
   840  // Evaluation of each reference token begins by decoding any escaped
   841  // character sequence.  This is performed by first transforming any
   842  // occurrence of the sequence '~1' to '/', and then transforming any
   843  // occurrence of the sequence '~0' to '~'.
   844  
   845  var (
   846  	rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
   847  )
   848  
   849  func decodePatchKey(k string) string {
   850  	return rfc6901Decoder.Replace(k)
   851  }
   852  

View as plain text