github.com/vanus-labs/vanus/lib@v0.0.0-20231221070800-1334a7b9605e/json/path/parse.go (about)

     1  // Copyright 2023 Linkall Inc.
     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  
    15  package path
    16  
    17  import (
    18  	// standard libraries.
    19  	"errors"
    20  	"strings"
    21  	"unicode/utf8"
    22  
    23  	// this project.
    24  	"github.com/vanus-labs/vanus/lib/bytes"
    25  	"github.com/vanus-labs/vanus/lib/json/parse"
    26  )
    27  
    28  var errInvalidJSONPath = errors.New("invalid JSON path")
    29  
    30  func Parse(text string) (Path, error) {
    31  	s := bytes.NewMarkScanner(bytes.UnsafeFromString(text))
    32  	if bytes.ExpectChar(s, '$') != nil { // root identifier
    33  		return nil, errInvalidJSONPath
    34  	}
    35  	segments, err := ConsumeSegments(s)
    36  	if err != nil {
    37  		return nil, errInvalidJSONPath
    38  	}
    39  	return &rootPath{segments: segments}, nil
    40  }
    41  
    42  func ConsumeExt(c byte, s *bytes.MarkScanner) (Path, error) {
    43  	if c != '$' {
    44  		return nil, errInvalidJSONPath
    45  	}
    46  	segments, err := ConsumeSegments(s)
    47  	if err != nil {
    48  		return nil, errInvalidJSONPath
    49  	}
    50  	return &rootPath{segments: segments}, nil
    51  }
    52  
    53  func ConsumeSegments(s *bytes.MarkScanner) ([]Segment, error) {
    54  	var segments []Segment
    55  	for {
    56  		m := s.Mark(0)
    57  		segment, err := consumeSegment(s)
    58  		if err != nil {
    59  			_ = s.Resume(m)
    60  			if len(segments) == 0 {
    61  				return nil, err
    62  			}
    63  			return segments, nil
    64  		}
    65  		segments = append(segments, segment)
    66  	}
    67  }
    68  
    69  func consumeSegment(s *bytes.MarkScanner) (Segment, error) {
    70  	c, err := s.ReadByte()
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	switch c {
    76  	case '[':
    77  		return consumeBracketedSelection(s)
    78  	case '.':
    79  		return consumeDotSegment(s)
    80  	default:
    81  		return nil, errInvalidJSONPath
    82  	}
    83  }
    84  
    85  func consumeBracketedSelection(s *bytes.MarkScanner) (Segment, error) {
    86  	var selectors []Selector
    87  	for {
    88  		_, c, err := parse.SkipWhitespace(s)
    89  		if err != nil {
    90  			return nil, err
    91  		}
    92  
    93  		selector, err := consumeSelectorExt(c, s)
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  
    98  		selectors = append(selectors, selector)
    99  
   100  		_, c, err = parse.SkipWhitespace(s)
   101  		if err != nil {
   102  			return nil, err
   103  		}
   104  
   105  		switch c {
   106  		case ']': // end of bracketed selection
   107  			return &bracketedSelection{selectors: selectors}, nil
   108  		case ',': // continue
   109  		default:
   110  			return nil, errInvalidJSONPath
   111  		}
   112  	}
   113  }
   114  
   115  func consumeSelectorExt(c byte, s *bytes.MarkScanner) (Selector, error) {
   116  	switch c {
   117  	case '\'': // name selector
   118  		var b strings.Builder
   119  		if err := parse.ConsumeSingleQuotedString(s, &b); err != nil {
   120  			return nil, err
   121  		}
   122  		return &nameSelector{member: b.String()}, nil
   123  	case '"': // name selector
   124  		var b strings.Builder
   125  		if err := parse.ConsumeDoubleQuotedString(s, &b); err != nil {
   126  			return nil, err
   127  		}
   128  		return &nameSelector{member: b.String()}, nil
   129  	case '*': // wildcard selector
   130  		return &wildcardSelector{}, nil
   131  	case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
   132  		return consumeIndexOrSliceSelector(c, s)
   133  	case ':': // array slice selector
   134  		return consumeSliceSelector(nil, s)
   135  	case '?': // filter selector
   136  		// TODO(james.yin)
   137  		return nil, errors.New("not implemented filter selector")
   138  	}
   139  	return nil, errInvalidJSONPath
   140  }
   141  
   142  func consumeIndexOrSliceSelector(c byte, s *bytes.MarkScanner) (Selector, error) {
   143  	indexOrStart, err := parse.ExpectIntegerExt(c, s)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	m := s.Mark(0)
   149  	if _, c, err = parse.SkipWhitespace(s); err != nil {
   150  		return nil, err
   151  	}
   152  
   153  	// array slice selector
   154  	if c == ':' {
   155  		return consumeSliceSelector(&indexOrStart, s)
   156  	}
   157  
   158  	_ = s.Resume(m)
   159  	return &indexSelector{index: indexOrStart}, nil
   160  }
   161  
   162  func consumeSliceSelector(start *int, s *bytes.MarkScanner) (*arraySliceSelector, error) {
   163  	m := s.Mark(0)
   164  	_, c, err := parse.SkipWhitespace(s)
   165  	if err != nil {
   166  		_ = s.Resume(m)
   167  		return nil, err
   168  	}
   169  
   170  	var end *int
   171  
   172  	me := s.Mark(0)
   173  	e, err := parse.ExpectIntegerExt(c, s)
   174  	if err != nil {
   175  		_ = s.Resume(me)
   176  	} else {
   177  		end = &e
   178  		m = s.Mark(0)
   179  		if _, c, err = parse.SkipWhitespace(s); err != nil {
   180  			return nil, err
   181  		}
   182  	}
   183  
   184  	step := 1
   185  	if c == ':' {
   186  		m = s.Mark(0)
   187  		if _, c, err = parse.SkipWhitespace(s); err != nil {
   188  			return nil, err
   189  		}
   190  		if step, err = parse.ExpectIntegerExt(c, s); err != nil {
   191  			step = 1
   192  			_ = s.Resume(m)
   193  		}
   194  	} else {
   195  		_ = s.Resume(m)
   196  	}
   197  
   198  	return &arraySliceSelector{
   199  		start: start,
   200  		end:   end,
   201  		step:  step,
   202  	}, nil
   203  }
   204  
   205  func consumeDotSegment(s *bytes.MarkScanner) (Segment, error) {
   206  	r, _ := bytes.ReadRune(s)
   207  	switch r {
   208  	case '*': // wildcard selector
   209  		return &wildcardSelector{}, nil
   210  	case '.': // descendant segment
   211  		// TODO(james.yin)
   212  		return nil, errors.New("not implemented descendant segment")
   213  	default: // member-name-shorthand
   214  		return consumeMemberNameShorthandExt(r, s)
   215  	}
   216  }
   217  
   218  func consumeMemberNameShorthandExt(r rune, s *bytes.MarkScanner) (Segment, error) {
   219  	var b strings.Builder
   220  
   221  	if r == utf8.RuneError || !parse.ExceptNameFirst(r) {
   222  		return nil, errInvalidJSONPath
   223  	}
   224  	if _, err := b.WriteRune(r); err != nil {
   225  		return nil, err
   226  	}
   227  
   228  	for {
   229  		m := s.Mark(0)
   230  		r, _ = bytes.ReadRune(s)
   231  		if r == utf8.RuneError || !parse.ExceptNameChar(r) {
   232  			_ = s.Resume(m)
   233  			return &nameSelector{member: b.String()}, nil
   234  		}
   235  		if _, err := b.WriteRune(r); err != nil {
   236  			return nil, err
   237  		}
   238  	}
   239  }