diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
new file mode 100644
index 0000000..985f399
--- /dev/null
+++ b/.github/workflows/test.yaml
@@ -0,0 +1,43 @@
+name: Test
+
+on:
+ pull_request:
+ branches:
+ - main
+ types:
+ - opened
+ - edited
+ - synchronize
+ - reopened
+
+jobs:
+ build:
+ name: Conventional pull request names
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5.5.3
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ build-test:
+ name: Build & Test
+ if: ${{ github.event.pull_request.draft == false }}
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ submodules: true
+ - name: Set up Go
+ uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
+ with:
+ go-version-file: "go.mod"
+ - name: Set up Node
+ uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
+ with:
+ node-version: "18.x"
+ registry-url: "https://registry.npmjs.org"
+ - name: Set up gotestfmt
+ run: go install github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest
+ - name: Build
+ run: go build ./...
+ - run: go test -json -v -p 1 ./... | gotestfmt
\ No newline at end of file
diff --git a/integration_test.go b/integration_test.go
index e46eeae..79db502 100644
--- a/integration_test.go
+++ b/integration_test.go
@@ -54,11 +54,17 @@ func TestJSONPathComplianceTestSuite(t *testing.T) {
// Test case for a valid selector
jp, err := jsonpath.NewPath(test.Selector)
if test.InvalidSelector {
- require.Error(t, err, "Expected an error for invalid selector, but got none")
+ require.Error(t, err, "Expected an error for invalid selector, but got none for path", jp.String())
return
} else {
- require.NoError(t, err, "Failed to parse JSONPath selector")
+ require.NoError(t, err, "Failed to parse JSONPath selector", jp.String())
}
+
+ // expect stability of ToString()
+ stringified := jp.String()
+ recursive, err := jsonpath.NewPath(stringified)
+ require.NoError(t, err, "Failed to parse recursive JSONPath selector. expected=%s got=%s", test.Selector, jp.String())
+ require.Equal(t, stringified, recursive.String(), "JSONPath selector does not match test case")
// interface{} to yaml.Node
toYAML := func(i interface{}) *yaml.Node {
o, err := yaml.Marshal(i)
diff --git a/pkg/jsonpath/filter.go b/pkg/jsonpath/filter.go
index 5ecf3ff..2f17c24 100644
--- a/pkg/jsonpath/filter.go
+++ b/pkg/jsonpath/filter.go
@@ -1,6 +1,10 @@
package jsonpath
-import "gopkg.in/yaml.v3"
+import (
+ "gopkg.in/yaml.v3"
+ "strconv"
+ "strings"
+)
// filter-selector = "?" S logical-expr
type filterSelector struct {
@@ -8,28 +12,72 @@ type filterSelector struct {
expression *logicalOrExpr
}
+func (s filterSelector) ToString() string {
+ return s.expression.ToString()
+}
+
// logical-or-expr = logical-and-expr *(S "||" S logical-and-expr)
type logicalOrExpr struct {
expressions []*logicalAndExpr
}
+func (e logicalOrExpr) ToString() string {
+ builder := strings.Builder{}
+ for i, expr := range e.expressions {
+ if i > 0 {
+ builder.WriteString(" || ")
+ }
+ builder.WriteString(expr.ToString())
+ }
+ return builder.String()
+}
+
// logical-and-expr = basic-expr *(S "&&" S basic-expr)
type logicalAndExpr struct {
expressions []*basicExpr
}
+func (e logicalAndExpr) ToString() string {
+ builder := strings.Builder{}
+ for i, expr := range e.expressions {
+ if i > 0 {
+ builder.WriteString(" && ")
+ }
+ builder.WriteString(expr.ToString())
+ }
+ return builder.String()
+}
+
// relQuery rel-query = current-node-identifier segments
// current-node-identifier = "@"
type relQuery struct {
segments []*segment
}
+func (q relQuery) ToString() string {
+ builder := strings.Builder{}
+ builder.WriteString("@")
+ for _, segment := range q.segments {
+ builder.WriteString(segment.ToString())
+ }
+ return builder.String()
+}
+
// filterQuery filter-query = rel-query / jsonpath-query
type filterQuery struct {
relQuery *relQuery
jsonPathQuery *jsonPathAST
}
+func (q filterQuery) ToString() string {
+ if q.relQuery != nil {
+ return q.relQuery.ToString()
+ } else if q.jsonPathQuery != nil {
+ return q.jsonPathQuery.ToString()
+ }
+ return ""
+}
+
// functionArgument function-argument = literal /
//
// filter-query / ; (includes singular-query)
@@ -80,6 +128,20 @@ func (a functionArgument) Eval(node *yaml.Node, root *yaml.Node) resolvedArgumen
return resolvedArgument{}
}
+func (a functionArgument) ToString() string {
+ builder := strings.Builder{}
+ if a.literal != nil {
+ builder.WriteString(a.literal.ToString())
+ } else if a.filterQuery != nil {
+ builder.WriteString(a.filterQuery.ToString())
+ } else if a.logicalExpr != nil {
+ builder.WriteString(a.logicalExpr.ToString())
+ } else if a.functionExpr != nil {
+ builder.WriteString(a.functionExpr.ToString())
+ }
+ return builder.String()
+}
+
//function-name = function-name-first *function-name-char
//function-name-first = LCALPHA
//function-name-char = function-name-first / "_" / DIGIT
@@ -120,6 +182,20 @@ type functionExpr struct {
args []*functionArgument
}
+func (e functionExpr) ToString() string {
+ builder := strings.Builder{}
+ builder.WriteString(e.funcType.String())
+ builder.WriteString("(")
+ for i, arg := range e.args {
+ if i > 0 {
+ builder.WriteString(", ")
+ }
+ builder.WriteString(arg.ToString())
+ }
+ builder.WriteString(")")
+ return builder.String()
+}
+
// testExpr test-expr = [logical-not-op S]
//
// (filter-query / ; existence/non-existence
@@ -130,6 +206,19 @@ type testExpr struct {
functionExpr *functionExpr
}
+func (e testExpr) ToString() string {
+ builder := strings.Builder{}
+ if e.not {
+ builder.WriteString("!")
+ }
+ if e.filterQuery != nil {
+ builder.WriteString(e.filterQuery.ToString())
+ } else if e.functionExpr != nil {
+ builder.WriteString(e.functionExpr.ToString())
+ }
+ return builder.String()
+}
+
// basicExpr basic-expr =
//
// paren-expr /
@@ -141,6 +230,17 @@ type basicExpr struct {
testExpr *testExpr
}
+func (e basicExpr) ToString() string {
+ if e.parenExpr != nil {
+ return e.parenExpr.ToString()
+ } else if e.comparisonExpr != nil {
+ return e.comparisonExpr.ToString()
+ } else if e.testExpr != nil {
+ return e.testExpr.ToString()
+ }
+ return ""
+}
+
// literal literal = number /
// . string-literal /
// . true / false / null
@@ -154,14 +254,102 @@ type literal struct {
node *yaml.Node
}
+func (l literal) ToString() string {
+ if l.integer != nil {
+ return strconv.Itoa(*l.integer)
+ } else if l.float64 != nil {
+ return strconv.FormatFloat(*l.float64, 'f', -1, 64)
+ } else if l.string != nil {
+ builder := strings.Builder{}
+ builder.WriteString("'")
+ builder.WriteString(escapeString(*l.string))
+ builder.WriteString("'")
+ return builder.String()
+ } else if l.bool != nil {
+ if *l.bool {
+ return "true"
+ } else {
+ return "false"
+ }
+ } else if l.null != nil {
+ if *l.null {
+ return "null"
+ } else {
+ return "null"
+ }
+ } else if l.node != nil {
+ switch l.node.Kind {
+ case yaml.ScalarNode:
+ return l.node.Value
+ case yaml.SequenceNode:
+ builder := strings.Builder{}
+ builder.WriteString("[")
+ for i, child := range l.node.Content {
+ if i > 0 {
+ builder.WriteString(",")
+ }
+ builder.WriteString(literal{node: child}.ToString())
+ }
+ builder.WriteString("]")
+ return builder.String()
+ case yaml.MappingNode:
+ builder := strings.Builder{}
+ builder.WriteString("{")
+ for i, child := range l.node.Content {
+ if i > 0 {
+ builder.WriteString(",")
+ }
+ builder.WriteString(literal{node: child}.ToString())
+ }
+ builder.WriteString("}")
+ return builder.String()
+ }
+ }
+ return ""
+}
+
+func escapeString(value string) string {
+ b := strings.Builder{}
+ for i := 0; i < len(value); i++ {
+ if value[i] == '\n' {
+ b.WriteString("\\\\n")
+ } else if value[i] == '\\' {
+ b.WriteString("\\\\")
+ } else if value[i] == '\'' {
+ b.WriteString("\\'")
+ } else {
+ b.WriteByte(value[i])
+ }
+ }
+ return b.String()
+}
+
type absQuery jsonPathAST
+func (q absQuery) ToString() string {
+ builder := strings.Builder{}
+ builder.WriteString("$")
+ for _, segment := range q.segments {
+ builder.WriteString(segment.ToString())
+ }
+ return builder.String()
+}
+
// singularQuery singular-query = rel-singular-query / abs-singular-query
type singularQuery struct {
relQuery *relQuery
absQuery *absQuery
}
+func (q singularQuery) ToString() string {
+ if q.relQuery != nil {
+ return q.relQuery.ToString()
+ } else if q.absQuery != nil {
+ return q.absQuery.ToString()
+ }
+ return ""
+}
+
// comparable
//
// comparable = literal /
@@ -173,6 +361,17 @@ type comparable struct {
functionExpr *functionExpr
}
+func (c comparable) ToString() string {
+ if c.literal != nil {
+ return c.literal.ToString()
+ } else if c.singularQuery != nil {
+ return c.singularQuery.ToString()
+ } else if c.functionExpr != nil {
+ return c.functionExpr.ToString()
+ }
+ return ""
+}
+
// comparisonExpr represents a comparison expression
//
// comparison-expr = comparable S comparison-op S comparable
@@ -190,6 +389,16 @@ type comparisonExpr struct {
right *comparable
}
+func (e comparisonExpr) ToString() string {
+ builder := strings.Builder{}
+ builder.WriteString(e.left.ToString())
+ builder.WriteString(" ")
+ builder.WriteString(e.op.ToString())
+ builder.WriteString(" ")
+ builder.WriteString(e.right.ToString())
+ return builder.String()
+}
+
// existExpr represents an existence expression
type existExpr struct {
query string
@@ -205,6 +414,17 @@ type parenExpr struct {
expr *logicalOrExpr
}
+func (e parenExpr) ToString() string {
+ builder := strings.Builder{}
+ if e.not {
+ builder.WriteString("!")
+ }
+ builder.WriteString("(")
+ builder.WriteString(e.expr.ToString())
+ builder.WriteString(")")
+ return builder.String()
+}
+
// comparisonOperator represents a comparison operator
type comparisonOperator int
@@ -216,3 +436,21 @@ const (
greaterThan
greaterThanEqualTo
)
+
+func (o comparisonOperator) ToString() string {
+ switch o {
+ case equalTo:
+ return "=="
+ case notEqualTo:
+ return "!="
+ case lessThan:
+ return "<"
+ case lessThanEqualTo:
+ return "<="
+ case greaterThan:
+ return ">"
+ case greaterThanEqualTo:
+ return ">="
+ }
+ return ""
+}
diff --git a/pkg/jsonpath/jsonpath.go b/pkg/jsonpath/jsonpath.go
index 3922d1d..22d2192 100644
--- a/pkg/jsonpath/jsonpath.go
+++ b/pkg/jsonpath/jsonpath.go
@@ -25,3 +25,10 @@ func NewPath(input string) (*JSONPath, error) {
func (p *JSONPath) Query(root *yaml.Node) []*yaml.Node {
return p.ast.Query(root, root)
}
+
+func (p *JSONPath) String() string {
+ if p == nil {
+ return ""
+ }
+ return p.ast.ToString()
+}
diff --git a/pkg/jsonpath/parser.go b/pkg/jsonpath/parser.go
index 242fa04..af233cd 100644
--- a/pkg/jsonpath/parser.go
+++ b/pkg/jsonpath/parser.go
@@ -133,7 +133,7 @@ func (p *JSONPath) parseInnerSegment() (retValue *innerSegment, err error) {
} else if firstToken.Token == token.BRACKET_LEFT {
prior := p.current
p.current += 1
- selectors := []*Selector{}
+ selectors := []*selector{}
for p.current < len(p.tokens) {
innerSelector, err := p.parseSelector()
if err != nil {
@@ -157,7 +157,7 @@ func (p *JSONPath) parseInnerSegment() (retValue *innerSegment, err error) {
return nil, p.parseFailure(&firstToken, "unexpected token when parsing inner segment")
}
-func (p *JSONPath) parseSelector() (retSelector *Selector, err error) {
+func (p *JSONPath) parseSelector() (retSelector *selector, err error) {
//selector = name-selector /
// wildcard-selector /
// slice-selector /
@@ -166,10 +166,10 @@ func (p *JSONPath) parseSelector() (retSelector *Selector, err error) {
initial := p.current
defer func() {
if p.mode[len(p.mode)-1] == modeSingular && retSelector != nil {
- if retSelector.Kind == SelectorSubKindWildcard {
+ if retSelector.kind == selectorSubKindWildcard {
err = p.parseFailure(&p.tokens[initial], "unexpected wildcard in singular query")
retSelector = nil
- } else if retSelector.Kind == SelectorSubKindArraySlice {
+ } else if retSelector.kind == selectorSubKindArraySlice {
err = p.parseFailure(&p.tokens[initial], "unexpected slice in singular query")
retSelector = nil
}
@@ -180,11 +180,11 @@ func (p *JSONPath) parseSelector() (retSelector *Selector, err error) {
if p.tokens[p.current].Token == token.STRING_LITERAL {
name := p.tokens[p.current].Literal
p.current++
- return &Selector{Kind: SelectorSubKindName, name: name}, nil
+ return &selector{kind: selectorSubKindName, name: name}, nil
// wildcard-selector = "*"
} else if p.tokens[p.current].Token == token.WILDCARD {
p.current++
- return &Selector{Kind: SelectorSubKindWildcard}, nil
+ return &selector{kind: selectorSubKindWildcard}, nil
} else if p.tokens[p.current].Token == token.INTEGER {
// peek ahead to see if it's a slice
if p.peek(token.ARRAY_SLICE) {
@@ -192,7 +192,7 @@ func (p *JSONPath) parseSelector() (retSelector *Selector, err error) {
if err != nil {
return nil, err
}
- return &Selector{Kind: SelectorSubKindArraySlice, slice: slice}, nil
+ return &selector{kind: selectorSubKindArraySlice, slice: slice}, nil
}
// peek ahead to see if we close the array index properly
if !p.peek(token.BRACKET_RIGHT) && !p.peek(token.COMMA) {
@@ -216,13 +216,13 @@ func (p *JSONPath) parseSelector() (retSelector *Selector, err error) {
p.current++
- return &Selector{Kind: SelectorSubKindArrayIndex, index: int(i)}, nil
+ return &selector{kind: selectorSubKindArrayIndex, index: int(i)}, nil
} else if p.tokens[p.current].Token == token.ARRAY_SLICE {
slice, err := p.parseSliceSelector()
if err != nil {
return nil, err
}
- return &Selector{Kind: SelectorSubKindArraySlice, slice: slice}, nil
+ return &selector{kind: selectorSubKindArraySlice, slice: slice}, nil
} else if p.tokens[p.current].Token == token.FILTER {
return p.parseFilterSelector()
}
@@ -230,7 +230,7 @@ func (p *JSONPath) parseSelector() (retSelector *Selector, err error) {
return nil, p.parseFailure(&p.tokens[p.current], "unexpected token when parsing selector")
}
-func (p *JSONPath) parseSliceSelector() (*Slice, error) {
+func (p *JSONPath) parseSliceSelector() (*slice, error) {
// slice-selector = [start S] ":" S [end S] [":" [S step]]
var start, end, step *int
@@ -294,7 +294,7 @@ func (p *JSONPath) parseSliceSelector() (*Slice, error) {
return nil, p.parseFailure(&p.tokens[p.current], "expected ']'")
}
- return &Slice{Start: start, End: end, Step: step}, nil
+ return &slice{start: start, end: end, step: step}, nil
}
func (p *JSONPath) checkSafeInteger(i int, literal string) error {
@@ -307,7 +307,7 @@ func (p *JSONPath) checkSafeInteger(i int, literal string) error {
return nil
}
-func (p *JSONPath) parseFilterSelector() (*Selector, error) {
+func (p *JSONPath) parseFilterSelector() (*selector, error) {
if p.tokens[p.current].Token != token.FILTER {
return nil, p.parseFailure(&p.tokens[p.current], "expected '?'")
@@ -319,7 +319,7 @@ func (p *JSONPath) parseFilterSelector() (*Selector, error) {
return nil, err
}
- return &Selector{Kind: SelectorSubKindFilter, filter: &filterSelector{expr}}, nil
+ return &selector{kind: selectorSubKindFilter, filter: &filterSelector{expr}}, nil
}
func (p *JSONPath) parseLogicalOrExpr() (*logicalOrExpr, error) {
@@ -372,6 +372,12 @@ func (p *JSONPath) parseBasicExpr() (*basicExpr, error) {
if err != nil {
return nil, err
}
+ // Inspect if the expr is topped by a parenExpr -- if so we can simplify
+ if len(expr.expressions) == 1 && len(expr.expressions[0].expressions) == 1 && expr.expressions[0].expressions[0].parenExpr != nil {
+ child := expr.expressions[0].expressions[0].parenExpr
+ child.not = !child.not
+ return &basicExpr{parenExpr: child}, nil
+ }
return &basicExpr{parenExpr: &parenExpr{not: true, expr: expr}}, nil
case token.PAREN_LEFT:
p.current++
diff --git a/pkg/jsonpath/segment.go b/pkg/jsonpath/segment.go
index 5e3d22a..42876df 100644
--- a/pkg/jsonpath/segment.go
+++ b/pkg/jsonpath/segment.go
@@ -15,7 +15,7 @@ type segmentSubKind int
const (
segmentDotWildcard segmentSubKind = iota // .*
segmentDotMemberName // .property
- segmentLongHand // [ Selector[] ]
+ segmentLongHand // [ selector[] ]
)
func (s segment) ToString() string {
@@ -35,7 +35,7 @@ func (s segment) ToString() string {
type innerSegment struct {
kind segmentSubKind
dotName string
- selectors []*Selector
+ selectors []*selector
}
func (s innerSegment) ToString() string {
@@ -52,7 +52,7 @@ func (s innerSegment) ToString() string {
for i, selector := range s.selectors {
builder.WriteString(selector.ToString())
if i < len(s.selectors)-1 {
- builder.WriteString(",")
+ builder.WriteString(", ")
}
}
builder.WriteString("]")
diff --git a/pkg/jsonpath/selector.go b/pkg/jsonpath/selector.go
index 52cc354..401b976 100644
--- a/pkg/jsonpath/selector.go
+++ b/pkg/jsonpath/selector.go
@@ -3,41 +3,61 @@ package jsonpath
import (
"fmt"
"strconv"
+ "strings"
)
-type SelectorSubKind int
+type selectorSubKind int
const (
- SelectorSubKindWildcard SelectorSubKind = iota
- SelectorSubKindName
- SelectorSubKindArraySlice
- SelectorSubKindArrayIndex
- SelectorSubKindFilter
+ selectorSubKindWildcard selectorSubKind = iota
+ selectorSubKindName
+ selectorSubKindArraySlice
+ selectorSubKindArrayIndex
+ selectorSubKindFilter
)
-type Slice struct {
- Start *int
- End *int
- Step *int
+type slice struct {
+ start *int
+ end *int
+ step *int
}
-type Selector struct {
- Kind SelectorSubKind
+type selector struct {
+ kind selectorSubKind
name string
index int
- slice *Slice
+ slice *slice
filter *filterSelector
}
-func (s Selector) ToString() string {
- switch s.Kind {
- case SelectorSubKindName:
- return "\"" + s.name + "\""
- case SelectorSubKindArrayIndex:
+func (s selector) ToString() string {
+ switch s.kind {
+ case selectorSubKindName:
+ return "'" + escapeString(s.name) + "'"
+ case selectorSubKindArrayIndex:
// int to string
- return "[" + strconv.Itoa(s.index) + "]"
+ return strconv.Itoa(s.index)
+ case selectorSubKindFilter:
+ return "?" + s.filter.ToString()
+ case selectorSubKindWildcard:
+ return "*"
+ case selectorSubKindArraySlice:
+ builder := strings.Builder{}
+ if s.slice.start != nil {
+ builder.WriteString(strconv.Itoa(*s.slice.start))
+ }
+ builder.WriteString(":")
+ if s.slice.end != nil {
+ builder.WriteString(strconv.Itoa(*s.slice.end))
+ }
+
+ if s.slice.step != nil {
+ builder.WriteString(":")
+ builder.WriteString(strconv.Itoa(*s.slice.step))
+ }
+ return builder.String()
default:
- panic(fmt.Sprintf("unimplemented selector kind: %v", s.Kind))
+ panic(fmt.Sprintf("unimplemented selector kind: %v", s.kind))
}
return ""
}
diff --git a/pkg/jsonpath/token/token.go b/pkg/jsonpath/token/token.go
index 22822d3..5b621df 100644
--- a/pkg/jsonpath/token/token.go
+++ b/pkg/jsonpath/token/token.go
@@ -639,7 +639,7 @@ func (t *Tokenizer) scanNumber() {
tokenType = ILLEGAL
}
// conformance spec
- if len(literal) > 1 && literal[0] == '0' {
+ if len(literal) > 1 && literal[0] == '0' && !dotSeen {
// no leading zero
tokenType = ILLEGAL
} else if len(literal) > 2 && literal[0] == '-' && literal[1] == '0' && !dotSeen {
diff --git a/pkg/jsonpath/yaml_query.go b/pkg/jsonpath/yaml_query.go
index 2ea0b61..fa6684a 100644
--- a/pkg/jsonpath/yaml_query.go
+++ b/pkg/jsonpath/yaml_query.go
@@ -110,9 +110,9 @@ func (s innerSegment) Query(value *yaml.Node, root *yaml.Node) []*yaml.Node {
}
-func (s Selector) Query(value *yaml.Node, root *yaml.Node) []*yaml.Node {
- switch s.Kind {
- case SelectorSubKindName:
+func (s selector) Query(value *yaml.Node, root *yaml.Node) []*yaml.Node {
+ switch s.kind {
+ case selectorSubKindName:
if value.Kind != yaml.MappingNode {
return nil
}
@@ -127,7 +127,7 @@ func (s Selector) Query(value *yaml.Node, root *yaml.Node) []*yaml.Node {
return []*yaml.Node{child}
}
}
- case SelectorSubKindArrayIndex:
+ case selectorSubKindArrayIndex:
if value.Kind != yaml.SequenceNode {
return nil
}
@@ -140,7 +140,7 @@ func (s Selector) Query(value *yaml.Node, root *yaml.Node) []*yaml.Node {
return []*yaml.Node{value.Content[len(value.Content)+s.index]}
}
return []*yaml.Node{value.Content[s.index]}
- case SelectorSubKindWildcard:
+ case selectorSubKindWildcard:
if value.Kind == yaml.SequenceNode {
return value.Content
} else if value.Kind == yaml.MappingNode {
@@ -153,7 +153,7 @@ func (s Selector) Query(value *yaml.Node, root *yaml.Node) []*yaml.Node {
return result
}
return nil
- case SelectorSubKindArraySlice:
+ case selectorSubKindArraySlice:
if value.Kind != yaml.SequenceNode {
return nil
}
@@ -161,14 +161,14 @@ func (s Selector) Query(value *yaml.Node, root *yaml.Node) []*yaml.Node {
return nil
}
step := 1
- if s.slice.Step != nil {
- step = *s.slice.Step
+ if s.slice.step != nil {
+ step = *s.slice.step
}
if step == 0 {
return nil
}
- start, end := s.slice.Start, s.slice.End
+ start, end := s.slice.start, s.slice.end
lower, upper := bounds(start, end, step, len(value.Content))
var result []*yaml.Node
@@ -183,7 +183,7 @@ func (s Selector) Query(value *yaml.Node, root *yaml.Node) []*yaml.Node {
}
return result
- case SelectorSubKindFilter:
+ case selectorSubKindFilter:
var result []*yaml.Node
switch value.Kind {
case yaml.MappingNode:
diff --git a/web/src/Playground.tsx b/web/src/Playground.tsx
index 8edb93f..12e6c21 100644
--- a/web/src/Playground.tsx
+++ b/web/src/Playground.tsx
@@ -149,7 +149,7 @@ function Playground() {
OpenAPI Overlay Specification
{" "}
- lets you update arbitrary values in an YAML document using{" "}
+ lets you update arbitrary values in a YAML document using{" "}
jsonpath