chore: migrate to gitea
Some checks failed
golangci-lint / lint (push) Failing after 1m30s
Test / test (push) Failing after 2m17s

This commit is contained in:
2026-01-27 00:40:46 +01:00
parent 1e05874160
commit f8df24c29d
3169 changed files with 1216434 additions and 1587 deletions

31
vendor/github.com/goccy/go-yaml/.codecov.yml generated vendored Normal file
View File

@@ -0,0 +1,31 @@
codecov:
require_ci_to_pass: yes
coverage:
precision: 2
round: down
range: "70...100"
status:
project:
default:
target: 75%
threshold: 2%
patch: off
changes: no
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: "header,diff"
behavior: default
require_changes: no
ignore:
- ast

3
vendor/github.com/goccy/go-yaml/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
bin/
.idea/
cover.out

65
vendor/github.com/goccy/go-yaml/.golangci.yml generated vendored Normal file
View File

@@ -0,0 +1,65 @@
version: "2"
linters:
default: none
enable:
- errcheck
- govet
- ineffassign
- misspell
- perfsprint
- staticcheck
- unused
settings:
errcheck:
without_tests: true
govet:
disable:
- tests
misspell:
locale: US
perfsprint:
int-conversion: false
err-error: false
errorf: true
sprintf1: false
strconcat: false
staticcheck:
checks:
- -ST1000
- -ST1005
- all
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- staticcheck
path: _test\.go
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gci
- gofmt
settings:
gci:
sections:
- standard
- default
- prefix(github.com/goccy/go-yaml)
- blank
- dot
gofmt:
simplify: true
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

186
vendor/github.com/goccy/go-yaml/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,186 @@
# 1.11.2 - 2023-09-15
### Fix bugs
- Fix quoted comments ( #370 )
- Fix handle of space at start or last ( #376 )
- Fix sequence with comment ( #390 )
# 1.11.1 - 2023-09-14
### Fix bugs
- Handle `\r` in a double-quoted string the same as `\n` ( #372 )
- Replace loop with n.Values = append(n.Values, target.Values...) ( #380 )
- Skip encoding an inline field if it is null ( #386 )
- Fix comment parsing with null value ( #388 )
# 1.11.0 - 2023-04-03
### Features
- Supports dynamically switch encode and decode processing for a given type
# 1.10.1 - 2023-03-28
### Features
- Quote YAML 1.1 bools at encoding time for compatibility with other legacy parsers
- Add support of 32-bit architecture
### Fix bugs
- Don't trim all space characters in block style sequence
- Support strings starting with `@`
# 1.10.0 - 2023-03-01
### Fix bugs
Reversible conversion of comments was not working in various cases, which has been corrected.
**Breaking Change** exists in the comment map interface. However, if you are dealing with CommentMap directly, there is no problem.
# 1.9.8 - 2022-12-19
### Fix feature
- Append new line at the end of file ( #329 )
### Fix bugs
- Fix custom marshaler ( #333, #334 )
- Fix behavior when struct fields conflicted( #335 )
- Fix position calculation for literal, folded and raw folded strings ( #330 )
# 1.9.7 - 2022-12-03
### Fix bugs
- Fix handling of quoted map key ( #328 )
- Fix resusing process of scanning context ( #322 )
## v1.9.6 - 2022-10-26
### New Features
- Introduce MapKeyNode interface to limit node types for map key ( #312 )
### Fix bugs
- Quote strings with special characters in flow mode ( #270 )
- typeError implements PrettyPrinter interface ( #280 )
- Fix incorrect const type ( #284 )
- Fix large literals type inference on 32 bits ( #293 )
- Fix UTF-8 characters ( #294 )
- Fix decoding of unknown aliases ( #317 )
- Fix stream encoder for insert a separator between each encoded document ( #318 )
### Update
- Update golang.org/x/sys ( #289 )
- Update Go version in CI ( #295 )
- Add test cases for missing keys to struct literals ( #300 )
## v1.9.5 - 2022-01-12
### New Features
* Add UseSingleQuote option ( #265 )
### Fix bugs
* Preserve defaults while decoding nested structs ( #260 )
* Fix minor typo in decodeInit error ( #264 )
* Handle empty sequence entries ( #275 )
* Fix encoding of sequence with multiline string ( #276 )
* Fix encoding of BytesMarshaler type ( #277 )
* Fix indentState logic for multi-line value ( #278 )
## v1.9.4 - 2021-10-12
### Fix bugs
* Keep prev/next reference between tokens containing comments when filtering comment tokens ( #257 )
* Supports escaping reserved keywords in PathBuilder ( #258 )
## v1.9.3 - 2021-09-07
### New Features
* Support encoding and decoding `time.Duration` fields ( #246 )
* Allow reserved characters for key name in YAMLPath ( #251 )
* Support getting YAMLPath from ast.Node ( #252 )
* Support CommentToMap option ( #253 )
### Fix bugs
* Fix encoding nested sequences with `yaml.IndentSequence` ( #241 )
* Fix error reporting on inline structs in strict mode ( #244, #245 )
* Fix encoding of large floats ( #247 )
### Improve workflow
* Migrate CI from CircleCI to GitHub Action ( #249 )
* Add workflow for ycat ( #250 )
## v1.9.2 - 2021-07-26
### Support WithComment option ( #238 )
`yaml.WithComment` is a option for encoding with comment.
The position where you want to add a comment is represented by YAMLPath, and it is the key of `yaml.CommentMap`.
Also, you can select `Head` comment or `Line` comment as the comment type.
## v1.9.1 - 2021-07-20
### Fix DecodeFromNode ( #237 )
- Fix YAML handling where anchor exists
## v1.9.0 - 2021-07-19
### New features
- Support encoding of comment node ( #233 )
- Support `yaml.NodeToValue(ast.Node, interface{}, ...DecodeOption) error` ( #236 )
- Can convert a AST node to a value directly
### Fix decoder for comment
- Fix parsing of literal with comment ( #234 )
### Rename API ( #235 )
- Rename `MarshalWithContext` to `MarshalContext`
- Rename `UnmarshalWithContext` to `UnmarshalContext`
## v1.8.10 - 2021-07-02
### Fixed bugs
- Fix searching anchor by alias name ( #212 )
- Fixing Issue 186, scanner should account for newline characters when processing multi-line text. Without this source annotations line/column number (for this and all subsequent tokens) is inconsistent with plain text editors. e.g. https://github.com/goccy/go-yaml/issues/186. This addresses the issue specifically for single and double quote text only. ( #210 )
- Add error for unterminated flow mapping node ( #213 )
- Handle missing required field validation ( #221 )
- Nicely format unexpected node type errors ( #229 )
- Support to encode map which has defined type key ( #231 )
### New features
- Support sequence indentation by EncodeOption ( #232 )
## v1.8.9 - 2021-03-01
### Fixed bugs
- Fix origin buffer for DocumentHeader and DocumentEnd and Directive
- Fix origin buffer for anchor value
- Fix syntax error about map value
- Fix parsing MergeKey ('<<') characters
- Fix encoding of float value
- Fix incorrect column annotation when single or double quotes are used
### New features
- Support to encode/decode of ast.Node directly

21
vendor/github.com/goccy/go-yaml/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Masaaki Goshima
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

55
vendor/github.com/goccy/go-yaml/Makefile generated vendored Normal file
View File

@@ -0,0 +1,55 @@
## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
TESTMOD := testdata/go_test.mod
$(LOCALBIN):
mkdir -p $(LOCALBIN)
.PHONY: test
test:
go test -v -race ./...
go test -v -race ./testdata -modfile=$(TESTMOD)
.PHONY: simple-test
simple-test:
go test -v ./...
go test -v ./testdata -modfile=$(TESTMOD)
.PHONY: fuzz
fuzz:
go test -fuzz=Fuzz -fuzztime 60s
.PHONY: cover
cover:
go test -coverpkg=.,./ast,./lexer,./parser,./printer,./scanner,./token -coverprofile=cover.out -modfile=$(TESTMOD) ./... ./testdata
.PHONY: cover-html
cover-html: cover
go tool cover -html=cover.out
.PHONY: ycat/build
ycat/build: $(LOCALBIN)
cd ./cmd/ycat && go build -o $(LOCALBIN)/ycat .
.PHONY: lint
lint: golangci-lint ## Run golangci-lint
@$(GOLANGCI_LINT) run
.PHONY: fmt
fmt: golangci-lint ## Ensure consistent code style
@go mod tidy
@go fmt ./...
@$(GOLANGCI_LINT) run --fix
## Tool Binaries
GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint
## Tool Versions
GOLANGCI_VERSION := 2.1.2
.PHONY: golangci-lint
.PHONY: $(GOLANGCI_LINT)
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
@test -s $(LOCALBIN)/golangci-lint && $(LOCALBIN)/golangci-lint version --short | grep -q $(GOLANGCI_VERSION) || \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(LOCALBIN) v$(GOLANGCI_VERSION)

420
vendor/github.com/goccy/go-yaml/README.md generated vendored Normal file
View File

@@ -0,0 +1,420 @@
# YAML support for the Go language
[![PkgGoDev](https://pkg.go.dev/badge/github.com/goccy/go-yaml)](https://pkg.go.dev/github.com/goccy/go-yaml)
![Go](https://github.com/goccy/go-yaml/workflows/Go/badge.svg)
[![codecov](https://codecov.io/gh/goccy/go-yaml/branch/master/graph/badge.svg)](https://codecov.io/gh/goccy/go-yaml)
[![Go Report Card](https://goreportcard.com/badge/github.com/goccy/go-yaml)](https://goreportcard.com/report/github.com/goccy/go-yaml)
<img width="300px" src="https://user-images.githubusercontent.com/209884/67159116-64d94b80-f37b-11e9-9b28-f8379636a43c.png"></img>
## This library has **NO** relation to the go-yaml/yaml library
> [!IMPORTANT]
> This library is developed from scratch to replace [`go-yaml/yaml`](https://github.com/go-yaml/yaml).
> If you're looking for a better YAML library, this one should be helpful.
# Why a new library?
As of this writing, there already exists a de facto standard library for YAML processing for Go: [https://github.com/go-yaml/yaml](https://github.com/go-yaml/yaml). However, we believe that a new YAML library is necessary for the following reasons:
- Not actively maintained
- `go-yaml/yaml` has ported the libyaml written in C to Go, so the source code is not written in Go style
- There is a lot of content that cannot be parsed
- YAML is often used for configuration, and it is common to include validation along with it. However, the errors in `go-yaml/yaml` are not intuitive, and it is difficult to provide meaningful validation errors
- When creating tools that use YAML, there are cases where reversible transformation of YAML is required. However, to perform reversible transformations of content that includes Comments or Anchors/Aliases, manipulating the AST is the only option
- Non-intuitive [Marshaler](https://pkg.go.dev/gopkg.in/yaml.v3#Marshaler) / [Unmarshaler](https://pkg.go.dev/gopkg.in/yaml.v3#Unmarshaler)
By the way, libraries such as [ghodss/yaml](https://github.com/ghodss/yaml) and [sigs.k8s.io/yaml](https://github.com/kubernetes-sigs/yaml) also depend on go-yaml/yaml, so if you are using these libraries, the same issues apply: they cannot parse things that go-yaml/yaml cannot parse, and they inherit many of the problems that go-yaml/yaml has.
# Features
- No dependencies
- A better parser than `go-yaml/yaml`.
- [Support recursive processing](https://github.com/apple/device-management/blob/release/docs/schema.yaml)
- Higher coverage in the [YAML Test Suite](https://github.com/yaml/yaml-test-suite?tab=readme-ov-file)
- YAML Test Suite consists of 402 cases in total, of which `gopkg.in/yaml.v3` passes `295`. In addition to passing all those test cases, `goccy/go-yaml` successfully passes nearly 60 additional test cases ( 2024/12/15 )
- The test code is [here](https://github.com/goccy/go-yaml/blob/master/yaml_test_suite_test.go#L77)
- Ease and sustainability of maintenance
- The main maintainer is [@goccy](https://github.com/goccy), but we are also building a system to develop as a team with trusted developers
- Since it is written from scratch, the code is easy to read for Gophers
- An API structure that allows the use of not only `Encoder`/`Decoder` but also `Tokenizer` and `Parser` functionalities.
- [lexer.Tokenize](https://pkg.go.dev/github.com/goccy/go-yaml@v1.15.4/lexer#Tokenize)
- [parser.Parse](https://pkg.go.dev/github.com/goccy/go-yaml@v1.15.4/parser#Parse)
- Filtering, replacing, and merging YAML content using YAML Path
- Reversible transformation without using the AST for YAML that includes Anchors, Aliases, and Comments
- Customize the Marshal/Unmarshal behavior for primitive types and third-party library types ([RegisterCustomMarshaler](https://pkg.go.dev/github.com/goccy/go-yaml#RegisterCustomMarshaler), [RegisterCustomUnmarshaler](https://pkg.go.dev/github.com/goccy/go-yaml#RegisterCustomUnmarshaler))
- Respects `encoding/json` behavior
- Accept the `json` tag. Note that not all options from the `json` tag will have significance when parsing YAML documents. If both tags exist, `yaml` tag will take precedence.
- [json.Marshaler](https://pkg.go.dev/encoding/json#Marshaler) style [marshaler](https://pkg.go.dev/github.com/goccy/go-yaml#BytesMarshaler)
- [json.Unmarshaler](https://pkg.go.dev/encoding/json#Unmarshaler) style [unmarshaler](https://pkg.go.dev/github.com/goccy/go-yaml#BytesUnmarshaler)
- Options for using `MarshalJSON` and `UnmarshalJSON` ([UseJSONMarshaler](https://pkg.go.dev/github.com/goccy/go-yaml#UseJSONMarshaler), [UseJSONUnmarshaler](https://pkg.go.dev/github.com/goccy/go-yaml#UseJSONUnmarshaler))
- Pretty format for error notifications
- Smart validation processing combined with [go-playground/validator](https://github.com/go-playground/validator)
- [example test code is here](https://github.com/goccy/go-yaml/blob/45889c98b0a0967240eb595a1bd6896e2f575106/testdata/validate_test.go#L12)
- Allow referencing elements declared in another file via anchors
# Users
The repositories that use goccy/go-yaml are listed here.
- https://github.com/goccy/go-yaml/wiki/Users
The source data is [here](https://github.com/goccy/go-yaml/network/dependents).
It is already being used in many repositories. Now it's your turn 😄
# Playground
The Playground visualizes how go-yaml processes YAML text. Use it to assist with your debugging or issue reporting.
https://goccy.github.io/go-yaml
# Installation
```sh
go get github.com/goccy/go-yaml
```
# Synopsis
## 1. Simple Encode/Decode
Has an interface like `go-yaml/yaml` using `reflect`
```go
var v struct {
A int
B string
}
v.A = 1
v.B = "hello"
bytes, err := yaml.Marshal(v)
if err != nil {
//...
}
fmt.Println(string(bytes)) // "a: 1\nb: hello\n"
```
```go
yml := `
%YAML 1.2
---
a: 1
b: c
`
var v struct {
A int
B string
}
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
//...
}
```
To control marshal/unmarshal behavior, you can use the `yaml` tag.
```go
yml := `---
foo: 1
bar: c
`
var v struct {
A int `yaml:"foo"`
B string `yaml:"bar"`
}
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
//...
}
```
For convenience, we also accept the `json` tag. Note that not all options from
the `json` tag will have significance when parsing YAML documents. If both
tags exist, `yaml` tag will take precedence.
```go
yml := `---
foo: 1
bar: c
`
var v struct {
A int `json:"foo"`
B string `json:"bar"`
}
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
//...
}
```
For custom marshal/unmarshaling, implement either `Bytes` or `Interface` variant of marshaler/unmarshaler. The difference is that while `BytesMarshaler`/`BytesUnmarshaler` behaves like [`encoding/json`](https://pkg.go.dev/encoding/json) and `InterfaceMarshaler`/`InterfaceUnmarshaler` behaves like [`gopkg.in/yaml.v2`](https://pkg.go.dev/gopkg.in/yaml.v2).
Semantically both are the same, but they differ in performance. Because indentation matters in YAML, you cannot simply accept a valid YAML fragment from a Marshaler, and expect it to work when it is attached to the parent container's serialized form. Therefore when we receive use the `BytesMarshaler`, which returns `[]byte`, we must decode it once to figure out how to make it work in the given context. If you use the `InterfaceMarshaler`, we can skip the decoding.
If you are repeatedly marshaling complex objects, the latter is always better
performance wise. But if you are, for example, just providing a choice between
a config file format that is read only once, the former is probably easier to
code.
## 2. Reference elements declared in another file
`testdata` directory contains `anchor.yml` file:
```shell
├── testdata
   └── anchor.yml
```
And `anchor.yml` is defined as follows:
```yaml
a: &a
b: 1
c: hello
```
Then, if `yaml.ReferenceDirs("testdata")` option is passed to `yaml.Decoder`,
`Decoder` tries to find the anchor definition from YAML files the under `testdata` directory.
```go
buf := bytes.NewBufferString("a: *a\n")
dec := yaml.NewDecoder(buf, yaml.ReferenceDirs("testdata"))
var v struct {
A struct {
B int
C string
}
}
if err := dec.Decode(&v); err != nil {
//...
}
fmt.Printf("%+v\n", v) // {A:{B:1 C:hello}}
```
## 3. Encode with `Anchor` and `Alias`
### 3.1. Explicitly declared `Anchor` name and `Alias` name
If you want to use `anchor`, you can define it as a struct tag.
If the value specified for an anchor is a pointer type and the same address as the pointer is found, the value is automatically set to alias.
If an explicit alias name is specified, an error is raised if its value is different from the value specified in the anchor.
```go
type T struct {
A int
B string
}
var v struct {
C *T `yaml:"c,anchor=x"`
D *T `yaml:"d,alias=x"`
}
v.C = &T{A: 1, B: "hello"}
v.D = v.C
bytes, err := yaml.Marshal(v)
if err != nil {
panic(err)
}
fmt.Println(string(bytes))
/*
c: &x
a: 1
b: hello
d: *x
*/
```
### 3.2. Implicitly declared `Anchor` and `Alias` names
If you do not explicitly declare the anchor name, the default behavior is to
use the equivalent of `strings.ToLower($FieldName)` as the name of the anchor.
If the value specified for an anchor is a pointer type and the same address as the pointer is found, the value is automatically set to alias.
```go
type T struct {
I int
S string
}
var v struct {
A *T `yaml:"a,anchor"`
B *T `yaml:"b,anchor"`
C *T `yaml:"c"`
D *T `yaml:"d"`
}
v.A = &T{I: 1, S: "hello"}
v.B = &T{I: 2, S: "world"}
v.C = v.A // C has same pointer address to A
v.D = v.B // D has same pointer address to B
bytes, err := yaml.Marshal(v)
if err != nil {
//...
}
fmt.Println(string(bytes))
/*
a: &a
i: 1
s: hello
b: &b
i: 2
s: world
c: *a
d: *b
*/
```
### 3.3 MergeKey and Alias
Merge key and alias ( `<<: *alias` ) can be used by embedding a structure with the `inline,alias` tag.
```go
type Person struct {
*Person `yaml:",omitempty,inline,alias"` // embed Person type for default value
Name string `yaml:",omitempty"`
Age int `yaml:",omitempty"`
}
defaultPerson := &Person{
Name: "John Smith",
Age: 20,
}
people := []*Person{
{
Person: defaultPerson, // assign default value
Name: "Ken", // override Name property
Age: 10, // override Age property
},
{
Person: defaultPerson, // assign default value only
},
}
var doc struct {
Default *Person `yaml:"default,anchor"`
People []*Person `yaml:"people"`
}
doc.Default = defaultPerson
doc.People = people
bytes, err := yaml.Marshal(doc)
if err != nil {
//...
}
fmt.Println(string(bytes))
/*
default: &default
name: John Smith
age: 20
people:
- <<: *default
name: Ken
age: 10
- <<: *default
*/
```
## 4. Pretty Formatted Errors
Error values produced during parsing have two extra features over regular
error values.
First, by default, they contain extra information on the location of the error
from the source YAML document, to make it easier to find the error location.
Second, the error messages can optionally be colorized.
If you would like to control exactly how the output looks like, consider
using `yaml.FormatError`, which accepts two boolean values to
control turning these features on or off.
<img src="https://user-images.githubusercontent.com/209884/67358124-587f0980-f59a-11e9-96fc-7205aab77695.png"></img>
## 5. Use YAMLPath
```go
yml := `
store:
book:
- author: john
price: 10
- author: ken
price: 12
bicycle:
color: red
price: 19.95
`
path, err := yaml.PathString("$.store.book[*].author")
if err != nil {
//...
}
var authors []string
if err := path.Read(strings.NewReader(yml), &authors); err != nil {
//...
}
fmt.Println(authors)
// [john ken]
```
### 5.1 Print customized error with YAML source code
```go
package main
import (
"fmt"
"github.com/goccy/go-yaml"
)
func main() {
yml := `
a: 1
b: "hello"
`
var v struct {
A int
B string
}
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
panic(err)
}
if v.A != 2 {
// output error with YAML source
path, err := yaml.PathString("$.a")
if err != nil {
panic(err)
}
source, err := path.AnnotateSource([]byte(yml), true)
if err != nil {
panic(err)
}
fmt.Printf("a value expected 2 but actual %d:\n%s\n", v.A, string(source))
}
}
```
output result is the following:
<img src="https://user-images.githubusercontent.com/209884/84148813-7aca8680-aa9a-11ea-8fc9-37dece2ebdac.png"></img>
# Tools
## ycat
print yaml file with color
<img width="713" alt="ycat" src="https://user-images.githubusercontent.com/209884/66986084-19b00600-f0f9-11e9-9f0e-1f91eb072fe0.png">
### Installation
```sh
git clone https://github.com/goccy/go-yaml.git
cd go-yaml/cmd/ycat && go install .
```
# For Developers
> [!NOTE]
> In this project, we manage such test code under the `testdata` directory to avoid adding dependencies on libraries that are only needed for testing to the top `go.mod` file. Therefore, if you want to add test cases that use 3rd party libraries, please add the test code to the `testdata` directory.
# Looking for Sponsors
I'm looking for sponsors this library. This library is being developed as a personal project in my spare time. If you want a quick response or problem resolution when using this library in your project, please register as a [sponsor](https://github.com/sponsors/goccy). I will cooperate as much as possible. Of course, this library is developed as an MIT license, so you can use it freely for free.
# License
MIT

2381
vendor/github.com/goccy/go-yaml/ast/ast.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

37
vendor/github.com/goccy/go-yaml/context.go generated vendored Normal file
View File

@@ -0,0 +1,37 @@
package yaml
import "context"
type (
ctxMergeKey struct{}
ctxAnchorKey struct{}
)
func withMerge(ctx context.Context) context.Context {
return context.WithValue(ctx, ctxMergeKey{}, true)
}
func isMerge(ctx context.Context) bool {
v, ok := ctx.Value(ctxMergeKey{}).(bool)
if !ok {
return false
}
return v
}
func withAnchor(ctx context.Context, name string) context.Context {
anchorMap := getAnchorMap(ctx)
if anchorMap == nil {
anchorMap = make(map[string]struct{})
}
anchorMap[name] = struct{}{}
return context.WithValue(ctx, ctxAnchorKey{}, anchorMap)
}
func getAnchorMap(ctx context.Context) map[string]struct{} {
v, ok := ctx.Value(ctxAnchorKey{}).(map[string]struct{})
if !ok {
return nil
}
return v
}

2037
vendor/github.com/goccy/go-yaml/decode.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

1074
vendor/github.com/goccy/go-yaml/encode.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

77
vendor/github.com/goccy/go-yaml/error.go generated vendored Normal file
View File

@@ -0,0 +1,77 @@
package yaml
import (
"fmt"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/internal/errors"
)
var (
ErrInvalidQuery = errors.New("invalid query")
ErrInvalidPath = errors.New("invalid path instance")
ErrInvalidPathString = errors.New("invalid path string")
ErrNotFoundNode = errors.New("node not found")
ErrUnknownCommentPositionType = errors.New("unknown comment position type")
ErrInvalidCommentMapValue = errors.New("invalid comment map value. it must be not nil value")
ErrDecodeRequiredPointerType = errors.New("required pointer type value")
ErrExceededMaxDepth = errors.New("exceeded max depth")
FormatErrorWithToken = errors.FormatError
)
type (
SyntaxError = errors.SyntaxError
TypeError = errors.TypeError
OverflowError = errors.OverflowError
DuplicateKeyError = errors.DuplicateKeyError
UnknownFieldError = errors.UnknownFieldError
UnexpectedNodeTypeError = errors.UnexpectedNodeTypeError
Error = errors.Error
)
func ErrUnsupportedHeadPositionType(node ast.Node) error {
return fmt.Errorf("unsupported comment head position for %s", node.Type())
}
func ErrUnsupportedLinePositionType(node ast.Node) error {
return fmt.Errorf("unsupported comment line position for %s", node.Type())
}
func ErrUnsupportedFootPositionType(node ast.Node) error {
return fmt.Errorf("unsupported comment foot position for %s", node.Type())
}
// IsInvalidQueryError whether err is ErrInvalidQuery or not.
func IsInvalidQueryError(err error) bool {
return errors.Is(err, ErrInvalidQuery)
}
// IsInvalidPathError whether err is ErrInvalidPath or not.
func IsInvalidPathError(err error) bool {
return errors.Is(err, ErrInvalidPath)
}
// IsInvalidPathStringError whether err is ErrInvalidPathString or not.
func IsInvalidPathStringError(err error) bool {
return errors.Is(err, ErrInvalidPathString)
}
// IsNotFoundNodeError whether err is ErrNotFoundNode or not.
func IsNotFoundNodeError(err error) bool {
return errors.Is(err, ErrNotFoundNode)
}
// IsInvalidTokenTypeError whether err is ast.ErrInvalidTokenType or not.
func IsInvalidTokenTypeError(err error) bool {
return errors.Is(err, ast.ErrInvalidTokenType)
}
// IsInvalidAnchorNameError whether err is ast.ErrInvalidAnchorName or not.
func IsInvalidAnchorNameError(err error) bool {
return errors.Is(err, ast.ErrInvalidAnchorName)
}
// IsInvalidAliasNameError whether err is ast.ErrInvalidAliasName or not.
func IsInvalidAliasNameError(err error) bool {
return errors.Is(err, ast.ErrInvalidAliasName)
}

View File

@@ -0,0 +1,246 @@
package errors
import (
"errors"
"fmt"
"reflect"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/printer"
"github.com/goccy/go-yaml/token"
)
var (
As = errors.As
Is = errors.Is
New = errors.New
)
const (
defaultFormatColor = false
defaultIncludeSource = true
)
type Error interface {
error
GetToken() *token.Token
GetMessage() string
FormatError(bool, bool) string
}
var (
_ Error = new(SyntaxError)
_ Error = new(TypeError)
_ Error = new(OverflowError)
_ Error = new(DuplicateKeyError)
_ Error = new(UnknownFieldError)
_ Error = new(UnexpectedNodeTypeError)
)
type SyntaxError struct {
Message string
Token *token.Token
}
type TypeError struct {
DstType reflect.Type
SrcType reflect.Type
StructFieldName *string
Token *token.Token
}
type OverflowError struct {
DstType reflect.Type
SrcNum string
Token *token.Token
}
type DuplicateKeyError struct {
Message string
Token *token.Token
}
type UnknownFieldError struct {
Message string
Token *token.Token
}
type UnexpectedNodeTypeError struct {
Actual ast.NodeType
Expected ast.NodeType
Token *token.Token
}
// ErrSyntax create syntax error instance with message and token
func ErrSyntax(msg string, tk *token.Token) *SyntaxError {
return &SyntaxError{
Message: msg,
Token: tk,
}
}
// ErrOverflow creates an overflow error instance with message and a token.
func ErrOverflow(dstType reflect.Type, num string, tk *token.Token) *OverflowError {
return &OverflowError{
DstType: dstType,
SrcNum: num,
Token: tk,
}
}
// ErrTypeMismatch cerates an type mismatch error instance with token.
func ErrTypeMismatch(dstType, srcType reflect.Type, token *token.Token) *TypeError {
return &TypeError{
DstType: dstType,
SrcType: srcType,
Token: token,
}
}
// ErrDuplicateKey creates an duplicate key error instance with token.
func ErrDuplicateKey(msg string, tk *token.Token) *DuplicateKeyError {
return &DuplicateKeyError{
Message: msg,
Token: tk,
}
}
// ErrUnknownField creates an unknown field error instance with token.
func ErrUnknownField(msg string, tk *token.Token) *UnknownFieldError {
return &UnknownFieldError{
Message: msg,
Token: tk,
}
}
func ErrUnexpectedNodeType(actual, expected ast.NodeType, tk *token.Token) *UnexpectedNodeTypeError {
return &UnexpectedNodeTypeError{
Actual: actual,
Expected: expected,
Token: tk,
}
}
func (e *SyntaxError) GetMessage() string {
return e.Message
}
func (e *SyntaxError) GetToken() *token.Token {
return e.Token
}
func (e *SyntaxError) Error() string {
return e.FormatError(defaultFormatColor, defaultIncludeSource)
}
func (e *SyntaxError) FormatError(colored, inclSource bool) string {
return FormatError(e.Message, e.Token, colored, inclSource)
}
func (e *OverflowError) GetMessage() string {
return e.msg()
}
func (e *OverflowError) GetToken() *token.Token {
return e.Token
}
func (e *OverflowError) Error() string {
return e.FormatError(defaultFormatColor, defaultIncludeSource)
}
func (e *OverflowError) FormatError(colored, inclSource bool) string {
return FormatError(e.msg(), e.Token, colored, inclSource)
}
func (e *OverflowError) msg() string {
return fmt.Sprintf("cannot unmarshal %s into Go value of type %s ( overflow )", e.SrcNum, e.DstType)
}
func (e *TypeError) msg() string {
if e.StructFieldName != nil {
return fmt.Sprintf("cannot unmarshal %s into Go struct field %s of type %s", e.SrcType, *e.StructFieldName, e.DstType)
}
return fmt.Sprintf("cannot unmarshal %s into Go value of type %s", e.SrcType, e.DstType)
}
func (e *TypeError) GetMessage() string {
return e.msg()
}
func (e *TypeError) GetToken() *token.Token {
return e.Token
}
func (e *TypeError) Error() string {
return e.FormatError(defaultFormatColor, defaultIncludeSource)
}
func (e *TypeError) FormatError(colored, inclSource bool) string {
return FormatError(e.msg(), e.Token, colored, inclSource)
}
func (e *DuplicateKeyError) GetMessage() string {
return e.Message
}
func (e *DuplicateKeyError) GetToken() *token.Token {
return e.Token
}
func (e *DuplicateKeyError) Error() string {
return e.FormatError(defaultFormatColor, defaultIncludeSource)
}
func (e *DuplicateKeyError) FormatError(colored, inclSource bool) string {
return FormatError(e.Message, e.Token, colored, inclSource)
}
func (e *UnknownFieldError) GetMessage() string {
return e.Message
}
func (e *UnknownFieldError) GetToken() *token.Token {
return e.Token
}
func (e *UnknownFieldError) Error() string {
return e.FormatError(defaultFormatColor, defaultIncludeSource)
}
func (e *UnknownFieldError) FormatError(colored, inclSource bool) string {
return FormatError(e.Message, e.Token, colored, inclSource)
}
func (e *UnexpectedNodeTypeError) GetMessage() string {
return e.msg()
}
func (e *UnexpectedNodeTypeError) GetToken() *token.Token {
return e.Token
}
func (e *UnexpectedNodeTypeError) Error() string {
return e.FormatError(defaultFormatColor, defaultIncludeSource)
}
func (e *UnexpectedNodeTypeError) FormatError(colored, inclSource bool) string {
return FormatError(e.msg(), e.Token, colored, inclSource)
}
func (e *UnexpectedNodeTypeError) msg() string {
return fmt.Sprintf("%s was used where %s is expected", e.Actual.YAMLName(), e.Expected.YAMLName())
}
func FormatError(errMsg string, token *token.Token, colored, inclSource bool) string {
var pp printer.Printer
if token == nil {
return pp.PrintErrorMessage(errMsg, colored)
}
pos := fmt.Sprintf("[%d:%d] ", token.Position.Line, token.Position.Column)
msg := pp.PrintErrorMessage(fmt.Sprintf("%s%s", pos, errMsg), colored)
if inclSource {
msg += "\n" + pp.PrintErrorToken(token, colored)
}
return msg
}

View File

@@ -0,0 +1,541 @@
package format
import (
"strings"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/token"
)
func FormatNodeWithResolvedAlias(n ast.Node, anchorNodeMap map[string]ast.Node) string {
tk := getFirstToken(n)
if tk == nil {
return ""
}
formatter := newFormatter(tk, hasComment(n))
formatter.anchorNodeMap = anchorNodeMap
return formatter.format(n)
}
func FormatNode(n ast.Node) string {
tk := getFirstToken(n)
if tk == nil {
return ""
}
return newFormatter(tk, hasComment(n)).format(n)
}
func FormatFile(file *ast.File) string {
if len(file.Docs) == 0 {
return ""
}
tk := getFirstToken(file.Docs[0])
if tk == nil {
return ""
}
return newFormatter(tk, hasCommentFile(file)).formatFile(file)
}
func hasCommentFile(f *ast.File) bool {
for _, doc := range f.Docs {
if hasComment(doc.Body) {
return true
}
}
return false
}
func hasComment(n ast.Node) bool {
if n == nil {
return false
}
switch nn := n.(type) {
case *ast.DocumentNode:
return hasComment(nn.Body)
case *ast.NullNode:
return nn.Comment != nil
case *ast.BoolNode:
return nn.Comment != nil
case *ast.IntegerNode:
return nn.Comment != nil
case *ast.FloatNode:
return nn.Comment != nil
case *ast.StringNode:
return nn.Comment != nil
case *ast.InfinityNode:
return nn.Comment != nil
case *ast.NanNode:
return nn.Comment != nil
case *ast.LiteralNode:
return nn.Comment != nil
case *ast.DirectiveNode:
if nn.Comment != nil {
return true
}
for _, value := range nn.Values {
if hasComment(value) {
return true
}
}
case *ast.TagNode:
if nn.Comment != nil {
return true
}
return hasComment(nn.Value)
case *ast.MappingNode:
if nn.Comment != nil || nn.FootComment != nil {
return true
}
for _, value := range nn.Values {
if value.Comment != nil || value.FootComment != nil {
return true
}
if hasComment(value.Key) {
return true
}
if hasComment(value.Value) {
return true
}
}
case *ast.MappingKeyNode:
return nn.Comment != nil
case *ast.MergeKeyNode:
return nn.Comment != nil
case *ast.SequenceNode:
if nn.Comment != nil || nn.FootComment != nil {
return true
}
for _, entry := range nn.Entries {
if entry.Comment != nil || entry.HeadComment != nil || entry.LineComment != nil {
return true
}
if hasComment(entry.Value) {
return true
}
}
case *ast.AnchorNode:
if nn.Comment != nil {
return true
}
if hasComment(nn.Name) || hasComment(nn.Value) {
return true
}
case *ast.AliasNode:
if nn.Comment != nil {
return true
}
if hasComment(nn.Value) {
return true
}
}
return false
}
func getFirstToken(n ast.Node) *token.Token {
if n == nil {
return nil
}
switch nn := n.(type) {
case *ast.DocumentNode:
if nn.Start != nil {
return nn.Start
}
return getFirstToken(nn.Body)
case *ast.NullNode:
return nn.Token
case *ast.BoolNode:
return nn.Token
case *ast.IntegerNode:
return nn.Token
case *ast.FloatNode:
return nn.Token
case *ast.StringNode:
return nn.Token
case *ast.InfinityNode:
return nn.Token
case *ast.NanNode:
return nn.Token
case *ast.LiteralNode:
return nn.Start
case *ast.DirectiveNode:
return nn.Start
case *ast.TagNode:
return nn.Start
case *ast.MappingNode:
if nn.IsFlowStyle {
return nn.Start
}
if len(nn.Values) == 0 {
return nn.Start
}
return getFirstToken(nn.Values[0].Key)
case *ast.MappingKeyNode:
return nn.Start
case *ast.MergeKeyNode:
return nn.Token
case *ast.SequenceNode:
return nn.Start
case *ast.AnchorNode:
return nn.Start
case *ast.AliasNode:
return nn.Start
}
return nil
}
type Formatter struct {
existsComment bool
tokenToOriginMap map[*token.Token]string
anchorNodeMap map[string]ast.Node
}
func newFormatter(tk *token.Token, existsComment bool) *Formatter {
tokenToOriginMap := make(map[*token.Token]string)
for tk.Prev != nil {
tk = tk.Prev
}
tokenToOriginMap[tk] = tk.Origin
var origin string
for tk.Next != nil {
tk = tk.Next
if tk.Type == token.CommentType {
origin += strings.Repeat("\n", strings.Count(normalizeNewLineChars(tk.Origin), "\n"))
continue
}
origin += tk.Origin
tokenToOriginMap[tk] = origin
origin = ""
}
return &Formatter{
existsComment: existsComment,
tokenToOriginMap: tokenToOriginMap,
}
}
func getIndentNumByFirstLineToken(tk *token.Token) int {
defaultIndent := tk.Position.Column - 1
// key: value
// ^
// next
if tk.Type == token.SequenceEntryType {
// If the current token is the sequence entry.
// the indent is calculated from the column value of the current token.
return defaultIndent
}
// key: value
// ^
// next
if tk.Next != nil && tk.Next.Type == token.MappingValueType {
// If the current token is the key in the mapping-value,
// the indent is calculated from the column value of the current token.
return defaultIndent
}
if tk.Prev == nil {
return defaultIndent
}
prev := tk.Prev
// key: value
// ^
// prev
if prev.Type == token.MappingValueType {
// If the current token is the value in the mapping-value,
// the indent is calculated from the column value of the key two steps back.
if prev.Prev == nil {
return defaultIndent
}
return prev.Prev.Position.Column - 1
}
// - value
// ^
// prev
if prev.Type == token.SequenceEntryType {
// If the value is not a mapping-value and the previous token was a sequence entry,
// the indent is calculated using the column value of the sequence entry token.
return prev.Position.Column - 1
}
return defaultIndent
}
func (f *Formatter) format(n ast.Node) string {
return f.trimSpacePrefix(
f.trimIndentSpace(
getIndentNumByFirstLineToken(getFirstToken(n)),
f.trimNewLineCharPrefix(f.formatNode(n)),
),
)
}
func (f *Formatter) formatFile(file *ast.File) string {
if len(file.Docs) == 0 {
return ""
}
var ret string
for _, doc := range file.Docs {
ret += f.formatDocument(doc)
}
return ret
}
func (f *Formatter) origin(tk *token.Token) string {
if tk == nil {
return ""
}
if f.existsComment {
return tk.Origin
}
return f.tokenToOriginMap[tk]
}
func (f *Formatter) formatDocument(n *ast.DocumentNode) string {
return f.origin(n.Start) + f.formatNode(n.Body) + f.origin(n.End)
}
func (f *Formatter) formatNull(n *ast.NullNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatString(n *ast.StringNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatInteger(n *ast.IntegerNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatFloat(n *ast.FloatNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatBool(n *ast.BoolNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatInfinity(n *ast.InfinityNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatNan(n *ast.NanNode) string {
return f.origin(n.Token) + f.formatCommentGroup(n.Comment)
}
func (f *Formatter) formatLiteral(n *ast.LiteralNode) string {
return f.origin(n.Start) + f.formatCommentGroup(n.Comment) + f.origin(n.Value.Token)
}
func (f *Formatter) formatMergeKey(n *ast.MergeKeyNode) string {
return f.origin(n.Token)
}
func (f *Formatter) formatMappingValue(n *ast.MappingValueNode) string {
return f.formatCommentGroup(n.Comment) +
f.origin(n.Key.GetToken()) + ":" + f.formatCommentGroup(n.Key.GetComment()) + f.formatNode(n.Value) +
f.formatCommentGroup(n.FootComment)
}
func (f *Formatter) formatDirective(n *ast.DirectiveNode) string {
ret := f.origin(n.Start) + f.formatNode(n.Name)
for _, val := range n.Values {
ret += f.formatNode(val)
}
return ret
}
func (f *Formatter) formatMapping(n *ast.MappingNode) string {
var ret string
if n.IsFlowStyle {
ret = f.origin(n.Start)
} else {
ret += f.formatCommentGroup(n.Comment)
}
for _, value := range n.Values {
if value.CollectEntry != nil {
ret += f.origin(value.CollectEntry)
}
ret += f.formatMappingValue(value)
}
if n.IsFlowStyle {
ret += f.origin(n.End)
ret += f.formatCommentGroup(n.Comment)
}
return ret
}
func (f *Formatter) formatTag(n *ast.TagNode) string {
return f.origin(n.Start) + f.formatNode(n.Value)
}
func (f *Formatter) formatMappingKey(n *ast.MappingKeyNode) string {
return f.origin(n.Start) + f.formatNode(n.Value)
}
func (f *Formatter) formatSequence(n *ast.SequenceNode) string {
var ret string
if n.IsFlowStyle {
ret = f.origin(n.Start)
} else {
// add head comment.
ret += f.formatCommentGroup(n.Comment)
}
for _, entry := range n.Entries {
ret += f.formatNode(entry)
}
if n.IsFlowStyle {
ret += f.origin(n.End)
ret += f.formatCommentGroup(n.Comment)
}
ret += f.formatCommentGroup(n.FootComment)
return ret
}
func (f *Formatter) formatSequenceEntry(n *ast.SequenceEntryNode) string {
return f.formatCommentGroup(n.HeadComment) + f.origin(n.Start) + f.formatCommentGroup(n.LineComment) + f.formatNode(n.Value)
}
func (f *Formatter) formatAnchor(n *ast.AnchorNode) string {
return f.origin(n.Start) + f.formatNode(n.Name) + f.formatNode(n.Value)
}
func (f *Formatter) formatAlias(n *ast.AliasNode) string {
if f.anchorNodeMap != nil {
anchorName := n.Value.GetToken().Value
node := f.anchorNodeMap[anchorName]
if node != nil {
formatted := f.formatNode(node)
// If formatted text contains newline characters, indentation needs to be considered.
if strings.Contains(formatted, "\n") {
// If the first character is not a newline, the first line should be output without indentation.
isIgnoredFirstLine := !strings.HasPrefix(formatted, "\n")
formatted = f.addIndentSpace(n.GetToken().Position.IndentNum, formatted, isIgnoredFirstLine)
}
return formatted
}
}
return f.origin(n.Start) + f.formatNode(n.Value)
}
func (f *Formatter) formatNode(n ast.Node) string {
switch nn := n.(type) {
case *ast.DocumentNode:
return f.formatDocument(nn)
case *ast.NullNode:
return f.formatNull(nn)
case *ast.BoolNode:
return f.formatBool(nn)
case *ast.IntegerNode:
return f.formatInteger(nn)
case *ast.FloatNode:
return f.formatFloat(nn)
case *ast.StringNode:
return f.formatString(nn)
case *ast.InfinityNode:
return f.formatInfinity(nn)
case *ast.NanNode:
return f.formatNan(nn)
case *ast.LiteralNode:
return f.formatLiteral(nn)
case *ast.DirectiveNode:
return f.formatDirective(nn)
case *ast.TagNode:
return f.formatTag(nn)
case *ast.MappingNode:
return f.formatMapping(nn)
case *ast.MappingKeyNode:
return f.formatMappingKey(nn)
case *ast.MappingValueNode:
return f.formatMappingValue(nn)
case *ast.MergeKeyNode:
return f.formatMergeKey(nn)
case *ast.SequenceNode:
return f.formatSequence(nn)
case *ast.SequenceEntryNode:
return f.formatSequenceEntry(nn)
case *ast.AnchorNode:
return f.formatAnchor(nn)
case *ast.AliasNode:
return f.formatAlias(nn)
}
return ""
}
func (f *Formatter) formatCommentGroup(g *ast.CommentGroupNode) string {
if g == nil {
return ""
}
var ret string
for _, cm := range g.Comments {
ret += f.formatComment(cm)
}
return ret
}
func (f *Formatter) formatComment(n *ast.CommentNode) string {
if n == nil {
return ""
}
return n.Token.Origin
}
// nolint: unused
func (f *Formatter) formatIndent(col int) string {
if col <= 1 {
return ""
}
return strings.Repeat(" ", col-1)
}
func (f *Formatter) trimNewLineCharPrefix(v string) string {
return strings.TrimLeftFunc(v, func(r rune) bool {
return r == '\n' || r == '\r'
})
}
func (f *Formatter) trimSpacePrefix(v string) string {
return strings.TrimLeftFunc(v, func(r rune) bool {
return r == ' '
})
}
func (f *Formatter) trimIndentSpace(trimIndentNum int, v string) string {
if trimIndentNum == 0 {
return v
}
lines := strings.Split(normalizeNewLineChars(v), "\n")
out := make([]string, 0, len(lines))
for _, line := range lines {
var cnt int
out = append(out, strings.TrimLeftFunc(line, func(r rune) bool {
cnt++
return r == ' ' && cnt <= trimIndentNum
}))
}
return strings.Join(out, "\n")
}
func (f *Formatter) addIndentSpace(indentNum int, v string, isIgnoredFirstLine bool) string {
if indentNum == 0 {
return v
}
indent := strings.Repeat(" ", indentNum)
lines := strings.Split(normalizeNewLineChars(v), "\n")
out := make([]string, 0, len(lines))
for idx, line := range lines {
if line == "" || (isIgnoredFirstLine && idx == 0) {
out = append(out, line)
continue
}
out = append(out, indent+line)
}
return strings.Join(out, "\n")
}
// normalizeNewLineChars normalize CRLF and CR to LF.
func normalizeNewLineChars(v string) string {
return strings.ReplaceAll(strings.ReplaceAll(v, "\r\n", "\n"), "\r", "\n")
}

23
vendor/github.com/goccy/go-yaml/lexer/lexer.go generated vendored Normal file
View File

@@ -0,0 +1,23 @@
package lexer
import (
"io"
"github.com/goccy/go-yaml/scanner"
"github.com/goccy/go-yaml/token"
)
// Tokenize split to token instances from string
func Tokenize(src string) token.Tokens {
var s scanner.Scanner
s.Init(src)
var tokens token.Tokens
for {
subTokens, err := s.Scan()
if err == io.EOF {
break
}
tokens.Add(subTokens...)
}
return tokens
}

352
vendor/github.com/goccy/go-yaml/option.go generated vendored Normal file
View File

@@ -0,0 +1,352 @@
package yaml
import (
"context"
"io"
"reflect"
"github.com/goccy/go-yaml/ast"
)
// DecodeOption functional option type for Decoder
type DecodeOption func(d *Decoder) error
// ReferenceReaders pass to Decoder that reference to anchor defined by passed readers
func ReferenceReaders(readers ...io.Reader) DecodeOption {
return func(d *Decoder) error {
d.referenceReaders = append(d.referenceReaders, readers...)
return nil
}
}
// ReferenceFiles pass to Decoder that reference to anchor defined by passed files
func ReferenceFiles(files ...string) DecodeOption {
return func(d *Decoder) error {
d.referenceFiles = files
return nil
}
}
// ReferenceDirs pass to Decoder that reference to anchor defined by files under the passed dirs
func ReferenceDirs(dirs ...string) DecodeOption {
return func(d *Decoder) error {
d.referenceDirs = dirs
return nil
}
}
// RecursiveDir search yaml file recursively from passed dirs by ReferenceDirs option
func RecursiveDir(isRecursive bool) DecodeOption {
return func(d *Decoder) error {
d.isRecursiveDir = isRecursive
return nil
}
}
// Validator set StructValidator instance to Decoder
func Validator(v StructValidator) DecodeOption {
return func(d *Decoder) error {
d.validator = v
return nil
}
}
// Strict enable DisallowUnknownField
func Strict() DecodeOption {
return func(d *Decoder) error {
d.disallowUnknownField = true
return nil
}
}
// DisallowUnknownField causes the Decoder to return an error when the destination
// is a struct and the input contains object keys which do not match any
// non-ignored, exported fields in the destination.
func DisallowUnknownField() DecodeOption {
return func(d *Decoder) error {
d.disallowUnknownField = true
return nil
}
}
// AllowFieldPrefixes, when paired with [DisallowUnknownField], allows fields
// with the specified prefixes to bypass the unknown field check.
func AllowFieldPrefixes(prefixes ...string) DecodeOption {
return func(d *Decoder) error {
d.allowedFieldPrefixes = append(d.allowedFieldPrefixes, prefixes...)
return nil
}
}
// AllowDuplicateMapKey ignore syntax error when mapping keys that are duplicates.
func AllowDuplicateMapKey() DecodeOption {
return func(d *Decoder) error {
d.allowDuplicateMapKey = true
return nil
}
}
// UseOrderedMap can be interpreted as a map,
// and uses MapSlice ( ordered map ) aggressively if there is no type specification
func UseOrderedMap() DecodeOption {
return func(d *Decoder) error {
d.useOrderedMap = true
return nil
}
}
// UseJSONUnmarshaler if neither `BytesUnmarshaler` nor `InterfaceUnmarshaler` is implemented
// and `UnmashalJSON([]byte)error` is implemented, convert the argument from `YAML` to `JSON` and then call it.
func UseJSONUnmarshaler() DecodeOption {
return func(d *Decoder) error {
d.useJSONUnmarshaler = true
return nil
}
}
// CustomUnmarshaler overrides any decoding process for the type specified in generics.
//
// NOTE: If RegisterCustomUnmarshaler and CustomUnmarshaler of DecodeOption are specified for the same type,
// the CustomUnmarshaler specified in DecodeOption takes precedence.
func CustomUnmarshaler[T any](unmarshaler func(*T, []byte) error) DecodeOption {
return func(d *Decoder) error {
var typ *T
d.customUnmarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}, b []byte) error {
return unmarshaler(v.(*T), b)
}
return nil
}
}
// CustomUnmarshalerContext overrides any decoding process for the type specified in generics.
// Similar to CustomUnmarshaler, but allows passing a context to the unmarshaler function.
func CustomUnmarshalerContext[T any](unmarshaler func(context.Context, *T, []byte) error) DecodeOption {
return func(d *Decoder) error {
var typ *T
d.customUnmarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}, b []byte) error {
return unmarshaler(ctx, v.(*T), b)
}
return nil
}
}
// EncodeOption functional option type for Encoder
type EncodeOption func(e *Encoder) error
// Indent change indent number
func Indent(spaces int) EncodeOption {
return func(e *Encoder) error {
e.indentNum = spaces
return nil
}
}
// IndentSequence causes sequence values to be indented the same value as Indent
func IndentSequence(indent bool) EncodeOption {
return func(e *Encoder) error {
e.indentSequence = indent
return nil
}
}
// UseSingleQuote determines if single or double quotes should be preferred for strings.
func UseSingleQuote(sq bool) EncodeOption {
return func(e *Encoder) error {
e.singleQuote = sq
return nil
}
}
// Flow encoding by flow style
func Flow(isFlowStyle bool) EncodeOption {
return func(e *Encoder) error {
e.isFlowStyle = isFlowStyle
return nil
}
}
// WithSmartAnchor when multiple map values share the same pointer,
// an anchor is automatically assigned to the first occurrence, and aliases are used for subsequent elements.
// The map key name is used as the anchor name by default.
// If key names conflict, a suffix is automatically added to avoid collisions.
// This is an experimental feature and cannot be used simultaneously with anchor tags.
func WithSmartAnchor() EncodeOption {
return func(e *Encoder) error {
e.enableSmartAnchor = true
return nil
}
}
// UseLiteralStyleIfMultiline causes encoding multiline strings with a literal syntax,
// no matter what characters they include
func UseLiteralStyleIfMultiline(useLiteralStyleIfMultiline bool) EncodeOption {
return func(e *Encoder) error {
e.useLiteralStyleIfMultiline = useLiteralStyleIfMultiline
return nil
}
}
// JSON encode in JSON format
func JSON() EncodeOption {
return func(e *Encoder) error {
e.isJSONStyle = true
e.isFlowStyle = true
return nil
}
}
// MarshalAnchor call back if encoder find an anchor during encoding
func MarshalAnchor(callback func(*ast.AnchorNode, interface{}) error) EncodeOption {
return func(e *Encoder) error {
e.anchorCallback = callback
return nil
}
}
// UseJSONMarshaler if neither `BytesMarshaler` nor `InterfaceMarshaler`
// nor `encoding.TextMarshaler` is implemented and `MarshalJSON()([]byte, error)` is implemented,
// call `MarshalJSON` to convert the returned `JSON` to `YAML` for processing.
func UseJSONMarshaler() EncodeOption {
return func(e *Encoder) error {
e.useJSONMarshaler = true
return nil
}
}
// CustomMarshaler overrides any encoding process for the type specified in generics.
//
// NOTE: If type T implements MarshalYAML for pointer receiver, the type specified in CustomMarshaler must be *T.
// If RegisterCustomMarshaler and CustomMarshaler of EncodeOption are specified for the same type,
// the CustomMarshaler specified in EncodeOption takes precedence.
func CustomMarshaler[T any](marshaler func(T) ([]byte, error)) EncodeOption {
return func(e *Encoder) error {
var typ T
e.customMarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}) ([]byte, error) {
return marshaler(v.(T))
}
return nil
}
}
// CustomMarshalerContext overrides any encoding process for the type specified in generics.
// Similar to CustomMarshaler, but allows passing a context to the marshaler function.
func CustomMarshalerContext[T any](marshaler func(context.Context, T) ([]byte, error)) EncodeOption {
return func(e *Encoder) error {
var typ T
e.customMarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}) ([]byte, error) {
return marshaler(ctx, v.(T))
}
return nil
}
}
// AutoInt automatically converts floating-point numbers to integers when the fractional part is zero.
// For example, a value of 1.0 will be encoded as 1.
func AutoInt() EncodeOption {
return func(e *Encoder) error {
e.autoInt = true
return nil
}
}
// OmitEmpty behaves in the same way as the interpretation of the omitempty tag in the encoding/json library.
// set on all the fields.
// In the current implementation, the omitempty tag is not implemented in the same way as encoding/json,
// so please specify this option if you expect the same behavior.
func OmitEmpty() EncodeOption {
return func(e *Encoder) error {
e.omitEmpty = true
return nil
}
}
// OmitZero forces the encoder to assume an `omitzero` struct tag is
// set on all the fields. See `Marshal` commentary for the `omitzero` tag logic.
func OmitZero() EncodeOption {
return func(e *Encoder) error {
e.omitZero = true
return nil
}
}
// CommentPosition type of the position for comment.
type CommentPosition int
const (
CommentHeadPosition CommentPosition = CommentPosition(iota)
CommentLinePosition
CommentFootPosition
)
func (p CommentPosition) String() string {
switch p {
case CommentHeadPosition:
return "Head"
case CommentLinePosition:
return "Line"
case CommentFootPosition:
return "Foot"
default:
return ""
}
}
// LineComment create a one-line comment for CommentMap.
func LineComment(text string) *Comment {
return &Comment{
Texts: []string{text},
Position: CommentLinePosition,
}
}
// HeadComment create a multiline comment for CommentMap.
func HeadComment(texts ...string) *Comment {
return &Comment{
Texts: texts,
Position: CommentHeadPosition,
}
}
// FootComment create a multiline comment for CommentMap.
func FootComment(texts ...string) *Comment {
return &Comment{
Texts: texts,
Position: CommentFootPosition,
}
}
// Comment raw data for comment.
type Comment struct {
Texts []string
Position CommentPosition
}
// CommentMap map of the position of the comment and the comment information.
type CommentMap map[string][]*Comment
// WithComment add a comment using the location and text information given in the CommentMap.
func WithComment(cm CommentMap) EncodeOption {
return func(e *Encoder) error {
commentMap := map[*Path][]*Comment{}
for k, v := range cm {
path, err := PathString(k)
if err != nil {
return err
}
commentMap[path] = v
}
e.commentMap = commentMap
return nil
}
}
// CommentToMap apply the position and content of comments in a YAML document to a CommentMap.
func CommentToMap(cm CommentMap) DecodeOption {
return func(d *Decoder) error {
if cm == nil {
return ErrInvalidCommentMapValue
}
d.toCommentMap = cm
return nil
}
}

28
vendor/github.com/goccy/go-yaml/parser/color.go generated vendored Normal file
View File

@@ -0,0 +1,28 @@
package parser
import "fmt"
const (
colorFgHiBlack int = iota + 90
colorFgHiRed
colorFgHiGreen
colorFgHiYellow
colorFgHiBlue
colorFgHiMagenta
colorFgHiCyan
)
var colorTable = []int{
colorFgHiRed,
colorFgHiGreen,
colorFgHiYellow,
colorFgHiBlue,
colorFgHiMagenta,
colorFgHiCyan,
}
func colorize(idx int, content string) string {
colorIdx := idx % len(colorTable)
color := colorTable[colorIdx]
return fmt.Sprintf("\x1b[1;%dm", color) + content + "\x1b[22;0m"
}

187
vendor/github.com/goccy/go-yaml/parser/context.go generated vendored Normal file
View File

@@ -0,0 +1,187 @@
package parser
import (
"fmt"
"strings"
"github.com/goccy/go-yaml/token"
)
// context context at parsing
type context struct {
tokenRef *tokenRef
path string
isFlow bool
}
type tokenRef struct {
tokens []*Token
size int
idx int
}
var pathSpecialChars = []string{
"$", "*", ".", "[", "]",
}
func containsPathSpecialChar(path string) bool {
for _, char := range pathSpecialChars {
if strings.Contains(path, char) {
return true
}
}
return false
}
func normalizePath(path string) string {
if containsPathSpecialChar(path) {
return fmt.Sprintf("'%s'", path)
}
return path
}
func (c *context) currentToken() *Token {
if c.tokenRef.idx >= c.tokenRef.size {
return nil
}
return c.tokenRef.tokens[c.tokenRef.idx]
}
func (c *context) isComment() bool {
return c.currentToken().Type() == token.CommentType
}
func (c *context) nextToken() *Token {
if c.tokenRef.idx+1 >= c.tokenRef.size {
return nil
}
return c.tokenRef.tokens[c.tokenRef.idx+1]
}
func (c *context) nextNotCommentToken() *Token {
for i := c.tokenRef.idx + 1; i < c.tokenRef.size; i++ {
tk := c.tokenRef.tokens[i]
if tk.Type() == token.CommentType {
continue
}
return tk
}
return nil
}
func (c *context) isTokenNotFound() bool {
return c.currentToken() == nil
}
func (c *context) withGroup(g *TokenGroup) *context {
ctx := *c
ctx.tokenRef = &tokenRef{
tokens: g.Tokens,
size: len(g.Tokens),
}
return &ctx
}
func (c *context) withChild(path string) *context {
ctx := *c
ctx.path = c.path + "." + normalizePath(path)
return &ctx
}
func (c *context) withIndex(idx uint) *context {
ctx := *c
ctx.path = c.path + "[" + fmt.Sprint(idx) + "]"
return &ctx
}
func (c *context) withFlow(isFlow bool) *context {
ctx := *c
ctx.isFlow = isFlow
return &ctx
}
func newContext() *context {
return &context{
path: "$",
}
}
func (c *context) goNext() {
ref := c.tokenRef
if ref.size <= ref.idx+1 {
ref.idx = ref.size
} else {
ref.idx++
}
}
func (c *context) next() bool {
return c.tokenRef.idx < c.tokenRef.size
}
func (c *context) insertNullToken(tk *Token) *Token {
nullToken := c.createImplicitNullToken(tk)
c.insertToken(nullToken)
c.goNext()
return nullToken
}
func (c *context) addNullValueToken(tk *Token) *Token {
nullToken := c.createImplicitNullToken(tk)
rawTk := nullToken.RawToken()
// add space for map or sequence value.
rawTk.Position.Column++
c.addToken(nullToken)
c.goNext()
return nullToken
}
func (c *context) createImplicitNullToken(base *Token) *Token {
pos := *(base.RawToken().Position)
pos.Column++
tk := token.New("null", " null", &pos)
tk.Type = token.ImplicitNullType
return &Token{Token: tk}
}
func (c *context) insertToken(tk *Token) {
ref := c.tokenRef
idx := ref.idx
if ref.size < idx {
return
}
if ref.size == idx {
curToken := ref.tokens[ref.size-1]
tk.RawToken().Next = curToken.RawToken()
curToken.RawToken().Prev = tk.RawToken()
ref.tokens = append(ref.tokens, tk)
ref.size = len(ref.tokens)
return
}
curToken := ref.tokens[idx]
tk.RawToken().Next = curToken.RawToken()
curToken.RawToken().Prev = tk.RawToken()
ref.tokens = append(ref.tokens[:idx+1], ref.tokens[idx:]...)
ref.tokens[idx] = tk
ref.size = len(ref.tokens)
}
func (c *context) addToken(tk *Token) {
ref := c.tokenRef
lastTk := ref.tokens[ref.size-1]
if lastTk.Group != nil {
lastTk = lastTk.Group.Last()
}
lastTk.RawToken().Next = tk.RawToken()
tk.RawToken().Prev = lastTk.RawToken()
ref.tokens = append(ref.tokens, tk)
ref.size = len(ref.tokens)
}

257
vendor/github.com/goccy/go-yaml/parser/node.go generated vendored Normal file
View File

@@ -0,0 +1,257 @@
package parser
import (
"fmt"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/internal/errors"
"github.com/goccy/go-yaml/token"
)
func newMappingNode(ctx *context, tk *Token, isFlow bool, values ...*ast.MappingValueNode) (*ast.MappingNode, error) {
node := ast.Mapping(tk.RawToken(), isFlow, values...)
node.SetPath(ctx.path)
return node, nil
}
func newMappingValueNode(ctx *context, colonTk, entryTk *Token, key ast.MapKeyNode, value ast.Node) (*ast.MappingValueNode, error) {
node := ast.MappingValue(colonTk.RawToken(), key, value)
node.SetPath(ctx.path)
node.CollectEntry = entryTk.RawToken()
if key.GetToken().Position.Line == value.GetToken().Position.Line {
// originally key was commented, but now that null value has been added, value must be commented.
if err := setLineComment(ctx, value, colonTk); err != nil {
return nil, err
}
// set line comment by colonTk or entryTk.
if err := setLineComment(ctx, value, entryTk); err != nil {
return nil, err
}
} else {
if err := setLineComment(ctx, key, colonTk); err != nil {
return nil, err
}
// set line comment by colonTk or entryTk.
if err := setLineComment(ctx, key, entryTk); err != nil {
return nil, err
}
}
return node, nil
}
func newMappingKeyNode(ctx *context, tk *Token) (*ast.MappingKeyNode, error) {
node := ast.MappingKey(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newAnchorNode(ctx *context, tk *Token) (*ast.AnchorNode, error) {
node := ast.Anchor(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newAliasNode(ctx *context, tk *Token) (*ast.AliasNode, error) {
node := ast.Alias(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newDirectiveNode(ctx *context, tk *Token) (*ast.DirectiveNode, error) {
node := ast.Directive(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newMergeKeyNode(ctx *context, tk *Token) (*ast.MergeKeyNode, error) {
node := ast.MergeKey(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newNullNode(ctx *context, tk *Token) (*ast.NullNode, error) {
node := ast.Null(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newBoolNode(ctx *context, tk *Token) (*ast.BoolNode, error) {
node := ast.Bool(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newIntegerNode(ctx *context, tk *Token) (*ast.IntegerNode, error) {
node := ast.Integer(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newFloatNode(ctx *context, tk *Token) (*ast.FloatNode, error) {
node := ast.Float(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newInfinityNode(ctx *context, tk *Token) (*ast.InfinityNode, error) {
node := ast.Infinity(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newNanNode(ctx *context, tk *Token) (*ast.NanNode, error) {
node := ast.Nan(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newStringNode(ctx *context, tk *Token) (*ast.StringNode, error) {
node := ast.String(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newLiteralNode(ctx *context, tk *Token) (*ast.LiteralNode, error) {
node := ast.Literal(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newTagNode(ctx *context, tk *Token) (*ast.TagNode, error) {
node := ast.Tag(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newSequenceNode(ctx *context, tk *Token, isFlow bool) (*ast.SequenceNode, error) {
node := ast.Sequence(tk.RawToken(), isFlow)
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}
func newTagDefaultScalarValueNode(ctx *context, tag *token.Token) (ast.ScalarNode, error) {
pos := *(tag.Position)
pos.Column++
var (
tk *Token
node ast.ScalarNode
)
switch token.ReservedTagKeyword(tag.Value) {
case token.IntegerTag:
tk = &Token{Token: token.New("0", "0", &pos)}
n, err := newIntegerNode(ctx, tk)
if err != nil {
return nil, err
}
node = n
case token.FloatTag:
tk = &Token{Token: token.New("0", "0", &pos)}
n, err := newFloatNode(ctx, tk)
if err != nil {
return nil, err
}
node = n
case token.StringTag, token.BinaryTag, token.TimestampTag:
tk = &Token{Token: token.New("", "", &pos)}
n, err := newStringNode(ctx, tk)
if err != nil {
return nil, err
}
node = n
case token.BooleanTag:
tk = &Token{Token: token.New("false", "false", &pos)}
n, err := newBoolNode(ctx, tk)
if err != nil {
return nil, err
}
node = n
case token.NullTag:
tk = &Token{Token: token.New("null", "null", &pos)}
n, err := newNullNode(ctx, tk)
if err != nil {
return nil, err
}
node = n
default:
return nil, errors.ErrSyntax(fmt.Sprintf("cannot assign default value for %q tag", tag.Value), tag)
}
ctx.insertToken(tk)
ctx.goNext()
return node, nil
}
func setLineComment(ctx *context, node ast.Node, tk *Token) error {
if tk == nil || tk.LineComment == nil {
return nil
}
comment := ast.CommentGroup([]*token.Token{tk.LineComment})
comment.SetPath(ctx.path)
if err := node.SetComment(comment); err != nil {
return err
}
return nil
}
func setHeadComment(cm *ast.CommentGroupNode, value ast.Node) error {
if cm == nil {
return nil
}
switch n := value.(type) {
case *ast.MappingNode:
if len(n.Values) != 0 && value.GetComment() == nil {
cm.SetPath(n.Values[0].GetPath())
return n.Values[0].SetComment(cm)
}
case *ast.MappingValueNode:
cm.SetPath(n.GetPath())
return n.SetComment(cm)
}
cm.SetPath(value.GetPath())
return value.SetComment(cm)
}

12
vendor/github.com/goccy/go-yaml/parser/option.go generated vendored Normal file
View File

@@ -0,0 +1,12 @@
package parser
// Option represents parser's option.
type Option func(p *parser)
// AllowDuplicateMapKey allow the use of keys with the same name in the same map,
// but by default, this is not permitted.
func AllowDuplicateMapKey() Option {
return func(p *parser) {
p.allowDuplicateMapKey = true
}
}

1330
vendor/github.com/goccy/go-yaml/parser/parser.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

746
vendor/github.com/goccy/go-yaml/parser/token.go generated vendored Normal file
View File

@@ -0,0 +1,746 @@
package parser
import (
"fmt"
"os"
"strings"
"github.com/goccy/go-yaml/internal/errors"
"github.com/goccy/go-yaml/token"
)
type TokenGroupType int
const (
TokenGroupNone TokenGroupType = iota
TokenGroupDirective
TokenGroupDirectiveName
TokenGroupDocument
TokenGroupDocumentBody
TokenGroupAnchor
TokenGroupAnchorName
TokenGroupAlias
TokenGroupLiteral
TokenGroupFolded
TokenGroupScalarTag
TokenGroupMapKey
TokenGroupMapKeyValue
)
func (t TokenGroupType) String() string {
switch t {
case TokenGroupNone:
return "none"
case TokenGroupDirective:
return "directive"
case TokenGroupDirectiveName:
return "directive_name"
case TokenGroupDocument:
return "document"
case TokenGroupDocumentBody:
return "document_body"
case TokenGroupAnchor:
return "anchor"
case TokenGroupAnchorName:
return "anchor_name"
case TokenGroupAlias:
return "alias"
case TokenGroupLiteral:
return "literal"
case TokenGroupFolded:
return "folded"
case TokenGroupScalarTag:
return "scalar_tag"
case TokenGroupMapKey:
return "map_key"
case TokenGroupMapKeyValue:
return "map_key_value"
}
return "none"
}
type Token struct {
Token *token.Token
Group *TokenGroup
LineComment *token.Token
}
func (t *Token) RawToken() *token.Token {
if t == nil {
return nil
}
if t.Token != nil {
return t.Token
}
return t.Group.RawToken()
}
func (t *Token) Type() token.Type {
if t == nil {
return 0
}
if t.Token != nil {
return t.Token.Type
}
return t.Group.TokenType()
}
func (t *Token) GroupType() TokenGroupType {
if t == nil {
return TokenGroupNone
}
if t.Token != nil {
return TokenGroupNone
}
return t.Group.Type
}
func (t *Token) Line() int {
if t == nil {
return 0
}
if t.Token != nil {
return t.Token.Position.Line
}
return t.Group.Line()
}
func (t *Token) Column() int {
if t == nil {
return 0
}
if t.Token != nil {
return t.Token.Position.Column
}
return t.Group.Column()
}
func (t *Token) SetGroupType(typ TokenGroupType) {
if t.Group == nil {
return
}
t.Group.Type = typ
}
func (t *Token) Dump() {
ctx := new(groupTokenRenderContext)
if t.Token != nil {
fmt.Fprint(os.Stdout, t.Token.Value)
return
}
t.Group.dump(ctx)
fmt.Fprintf(os.Stdout, "\n")
}
func (t *Token) dump(ctx *groupTokenRenderContext) {
if t.Token != nil {
fmt.Fprint(os.Stdout, t.Token.Value)
return
}
t.Group.dump(ctx)
}
type groupTokenRenderContext struct {
num int
}
type TokenGroup struct {
Type TokenGroupType
Tokens []*Token
}
func (g *TokenGroup) First() *Token {
if len(g.Tokens) == 0 {
return nil
}
return g.Tokens[0]
}
func (g *TokenGroup) Last() *Token {
if len(g.Tokens) == 0 {
return nil
}
return g.Tokens[len(g.Tokens)-1]
}
func (g *TokenGroup) dump(ctx *groupTokenRenderContext) {
num := ctx.num
fmt.Fprint(os.Stdout, colorize(num, "("))
ctx.num++
for _, tk := range g.Tokens {
tk.dump(ctx)
}
fmt.Fprint(os.Stdout, colorize(num, ")"))
}
func (g *TokenGroup) RawToken() *token.Token {
if len(g.Tokens) == 0 {
return nil
}
return g.Tokens[0].RawToken()
}
func (g *TokenGroup) Line() int {
if len(g.Tokens) == 0 {
return 0
}
return g.Tokens[0].Line()
}
func (g *TokenGroup) Column() int {
if len(g.Tokens) == 0 {
return 0
}
return g.Tokens[0].Column()
}
func (g *TokenGroup) TokenType() token.Type {
if len(g.Tokens) == 0 {
return 0
}
return g.Tokens[0].Type()
}
func CreateGroupedTokens(tokens token.Tokens) ([]*Token, error) {
var err error
tks := newTokens(tokens)
tks = createLineCommentTokenGroups(tks)
tks, err = createLiteralAndFoldedTokenGroups(tks)
if err != nil {
return nil, err
}
tks, err = createAnchorAndAliasTokenGroups(tks)
if err != nil {
return nil, err
}
tks, err = createScalarTagTokenGroups(tks)
if err != nil {
return nil, err
}
tks, err = createAnchorWithScalarTagTokenGroups(tks)
if err != nil {
return nil, err
}
tks, err = createMapKeyTokenGroups(tks)
if err != nil {
return nil, err
}
tks = createMapKeyValueTokenGroups(tks)
tks, err = createDirectiveTokenGroups(tks)
if err != nil {
return nil, err
}
tks, err = createDocumentTokens(tks)
if err != nil {
return nil, err
}
return tks, nil
}
func newTokens(tks token.Tokens) []*Token {
ret := make([]*Token, 0, len(tks))
for _, tk := range tks {
ret = append(ret, &Token{Token: tk})
}
return ret
}
func createLineCommentTokenGroups(tokens []*Token) []*Token {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.CommentType:
if i > 0 && tokens[i-1].Line() == tk.Line() {
tokens[i-1].LineComment = tk.RawToken()
} else {
ret = append(ret, tk)
}
default:
ret = append(ret, tk)
}
}
return ret
}
func createLiteralAndFoldedTokenGroups(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.LiteralType:
tks := []*Token{tk}
if i+1 < len(tokens) {
tks = append(tks, tokens[i+1])
}
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupLiteral,
Tokens: tks,
},
})
i++
case token.FoldedType:
tks := []*Token{tk}
if i+1 < len(tokens) {
tks = append(tks, tokens[i+1])
}
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupFolded,
Tokens: tks,
},
})
i++
default:
ret = append(ret, tk)
}
}
return ret, nil
}
func createAnchorAndAliasTokenGroups(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.AnchorType:
if i+1 >= len(tokens) {
return nil, errors.ErrSyntax("undefined anchor name", tk.RawToken())
}
if i+2 >= len(tokens) {
return nil, errors.ErrSyntax("undefined anchor value", tk.RawToken())
}
anchorName := &Token{
Group: &TokenGroup{
Type: TokenGroupAnchorName,
Tokens: []*Token{tk, tokens[i+1]},
},
}
valueTk := tokens[i+2]
if tk.Line() == valueTk.Line() && valueTk.Type() == token.SequenceEntryType {
return nil, errors.ErrSyntax("sequence entries are not allowed after anchor on the same line", valueTk.RawToken())
}
if tk.Line() == valueTk.Line() && isScalarType(valueTk) {
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupAnchor,
Tokens: []*Token{anchorName, valueTk},
},
})
i++
} else {
ret = append(ret, anchorName)
}
i++
case token.AliasType:
if i+1 == len(tokens) {
return nil, errors.ErrSyntax("undefined alias name", tk.RawToken())
}
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupAlias,
Tokens: []*Token{tk, tokens[i+1]},
},
})
i++
default:
ret = append(ret, tk)
}
}
return ret, nil
}
func createScalarTagTokenGroups(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
if tk.Type() != token.TagType {
ret = append(ret, tk)
continue
}
tag := tk.RawToken()
if strings.HasPrefix(tag.Value, "!!") {
// secondary tag.
switch token.ReservedTagKeyword(tag.Value) {
case token.IntegerTag, token.FloatTag, token.StringTag, token.BinaryTag, token.TimestampTag, token.BooleanTag, token.NullTag:
if len(tokens) <= i+1 {
ret = append(ret, tk)
continue
}
if tk.Line() != tokens[i+1].Line() {
ret = append(ret, tk)
continue
}
if tokens[i+1].GroupType() == TokenGroupAnchorName {
ret = append(ret, tk)
continue
}
if isScalarType(tokens[i+1]) {
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupScalarTag,
Tokens: []*Token{tk, tokens[i+1]},
},
})
i++
} else {
ret = append(ret, tk)
}
case token.MergeTag:
if len(tokens) <= i+1 {
ret = append(ret, tk)
continue
}
if tk.Line() != tokens[i+1].Line() {
ret = append(ret, tk)
continue
}
if tokens[i+1].GroupType() == TokenGroupAnchorName {
ret = append(ret, tk)
continue
}
if tokens[i+1].Type() != token.MergeKeyType {
return nil, errors.ErrSyntax("could not find merge key", tokens[i+1].RawToken())
}
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupScalarTag,
Tokens: []*Token{tk, tokens[i+1]},
},
})
i++
default:
ret = append(ret, tk)
}
} else {
if len(tokens) <= i+1 {
ret = append(ret, tk)
continue
}
if tk.Line() != tokens[i+1].Line() {
ret = append(ret, tk)
continue
}
if tokens[i+1].GroupType() == TokenGroupAnchorName {
ret = append(ret, tk)
continue
}
if isFlowType(tokens[i+1]) {
ret = append(ret, tk)
continue
}
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupScalarTag,
Tokens: []*Token{tk, tokens[i+1]},
},
})
i++
}
}
return ret, nil
}
func createAnchorWithScalarTagTokenGroups(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.GroupType() {
case TokenGroupAnchorName:
if i+1 >= len(tokens) {
return nil, errors.ErrSyntax("undefined anchor value", tk.RawToken())
}
valueTk := tokens[i+1]
if tk.Line() == valueTk.Line() && valueTk.GroupType() == TokenGroupScalarTag {
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupAnchor,
Tokens: []*Token{tk, tokens[i+1]},
},
})
i++
} else {
ret = append(ret, tk)
}
default:
ret = append(ret, tk)
}
}
return ret, nil
}
func createMapKeyTokenGroups(tokens []*Token) ([]*Token, error) {
tks, err := createMapKeyByMappingKey(tokens)
if err != nil {
return nil, err
}
return createMapKeyByMappingValue(tks)
}
func createMapKeyByMappingKey(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.MappingKeyType:
if i+1 >= len(tokens) {
return nil, errors.ErrSyntax("undefined map key", tk.RawToken())
}
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupMapKey,
Tokens: []*Token{tk, tokens[i+1]},
},
})
i++
default:
ret = append(ret, tk)
}
}
return ret, nil
}
func createMapKeyByMappingValue(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.MappingValueType:
if i == 0 {
return nil, errors.ErrSyntax("unexpected key name", tk.RawToken())
}
mapKeyTk := tokens[i-1]
if isNotMapKeyType(mapKeyTk) {
return nil, errors.ErrSyntax("found an invalid key for this map", tokens[i].RawToken())
}
newTk := &Token{Token: mapKeyTk.Token, Group: mapKeyTk.Group}
mapKeyTk.Token = nil
mapKeyTk.Group = &TokenGroup{
Type: TokenGroupMapKey,
Tokens: []*Token{newTk, tk},
}
default:
ret = append(ret, tk)
}
}
return ret, nil
}
func createMapKeyValueTokenGroups(tokens []*Token) []*Token {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.GroupType() {
case TokenGroupMapKey:
if len(tokens) <= i+1 {
ret = append(ret, tk)
continue
}
valueTk := tokens[i+1]
if tk.Line() != valueTk.Line() {
ret = append(ret, tk)
continue
}
if valueTk.GroupType() == TokenGroupAnchorName {
ret = append(ret, tk)
continue
}
if valueTk.Type() == token.TagType && valueTk.GroupType() != TokenGroupScalarTag {
ret = append(ret, tk)
continue
}
if isScalarType(valueTk) || valueTk.Type() == token.TagType {
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupMapKeyValue,
Tokens: []*Token{tk, valueTk},
},
})
i++
} else {
ret = append(ret, tk)
continue
}
default:
ret = append(ret, tk)
}
}
return ret
}
func createDirectiveTokenGroups(tokens []*Token) ([]*Token, error) {
ret := make([]*Token, 0, len(tokens))
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.DirectiveType:
if i+1 >= len(tokens) {
return nil, errors.ErrSyntax("undefined directive value", tk.RawToken())
}
directiveName := &Token{
Group: &TokenGroup{
Type: TokenGroupDirectiveName,
Tokens: []*Token{tk, tokens[i+1]},
},
}
i++
var valueTks []*Token
for j := i + 1; j < len(tokens); j++ {
if tokens[j].Line() != tk.Line() {
break
}
valueTks = append(valueTks, tokens[j])
i++
}
if i+1 >= len(tokens) || tokens[i+1].Type() != token.DocumentHeaderType {
return nil, errors.ErrSyntax("unexpected directive value. document not started", tk.RawToken())
}
if len(valueTks) != 0 {
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupDirective,
Tokens: append([]*Token{directiveName}, valueTks...),
},
})
} else {
ret = append(ret, directiveName)
}
default:
ret = append(ret, tk)
}
}
return ret, nil
}
func createDocumentTokens(tokens []*Token) ([]*Token, error) {
var ret []*Token
for i := 0; i < len(tokens); i++ {
tk := tokens[i]
switch tk.Type() {
case token.DocumentHeaderType:
if i != 0 {
ret = append(ret, &Token{
Group: &TokenGroup{Tokens: tokens[:i]},
})
}
if i+1 == len(tokens) {
// if current token is last token, add DocumentHeader only tokens to ret.
return append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupDocument,
Tokens: []*Token{tk},
},
}), nil
}
if tokens[i+1].Type() == token.DocumentHeaderType {
return append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupDocument,
Tokens: []*Token{tk},
},
}), nil
}
if tokens[i].Line() == tokens[i+1].Line() {
switch tokens[i+1].GroupType() {
case TokenGroupMapKey, TokenGroupMapKeyValue:
return nil, errors.ErrSyntax("value cannot be placed after document separator", tokens[i+1].RawToken())
}
switch tokens[i+1].Type() {
case token.SequenceEntryType:
return nil, errors.ErrSyntax("value cannot be placed after document separator", tokens[i+1].RawToken())
}
}
tks, err := createDocumentTokens(tokens[i+1:])
if err != nil {
return nil, err
}
if len(tks) != 0 {
tks[0].SetGroupType(TokenGroupDocument)
tks[0].Group.Tokens = append([]*Token{tk}, tks[0].Group.Tokens...)
return append(ret, tks...), nil
}
return append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupDocument,
Tokens: []*Token{tk},
},
}), nil
case token.DocumentEndType:
if i != 0 {
ret = append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupDocument,
Tokens: tokens[0 : i+1],
},
})
}
if i+1 == len(tokens) {
return ret, nil
}
if isScalarType(tokens[i+1]) {
return nil, errors.ErrSyntax("unexpected end content", tokens[i+1].RawToken())
}
tks, err := createDocumentTokens(tokens[i+1:])
if err != nil {
return nil, err
}
return append(ret, tks...), nil
}
}
return append(ret, &Token{
Group: &TokenGroup{
Type: TokenGroupDocument,
Tokens: tokens,
},
}), nil
}
func isScalarType(tk *Token) bool {
switch tk.GroupType() {
case TokenGroupMapKey, TokenGroupMapKeyValue:
return false
}
typ := tk.Type()
return typ == token.AnchorType ||
typ == token.AliasType ||
typ == token.LiteralType ||
typ == token.FoldedType ||
typ == token.NullType ||
typ == token.ImplicitNullType ||
typ == token.BoolType ||
typ == token.IntegerType ||
typ == token.BinaryIntegerType ||
typ == token.OctetIntegerType ||
typ == token.HexIntegerType ||
typ == token.FloatType ||
typ == token.InfinityType ||
typ == token.NanType ||
typ == token.StringType ||
typ == token.SingleQuoteType ||
typ == token.DoubleQuoteType
}
func isNotMapKeyType(tk *Token) bool {
typ := tk.Type()
return typ == token.DirectiveType ||
typ == token.DocumentHeaderType ||
typ == token.DocumentEndType ||
typ == token.CollectEntryType ||
typ == token.MappingStartType ||
typ == token.MappingValueType ||
typ == token.MappingEndType ||
typ == token.SequenceStartType ||
typ == token.SequenceEntryType ||
typ == token.SequenceEndType
}
func isFlowType(tk *Token) bool {
typ := tk.Type()
return typ == token.MappingStartType ||
typ == token.MappingEndType ||
typ == token.SequenceStartType ||
typ == token.SequenceEntryType
}

835
vendor/github.com/goccy/go-yaml/path.go generated vendored Normal file
View File

@@ -0,0 +1,835 @@
package yaml
import (
"bytes"
"fmt"
"io"
"strconv"
"strings"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/parser"
"github.com/goccy/go-yaml/printer"
)
// PathString create Path from string
//
// YAMLPath rule
// $ : the root object/element
// . : child operator
// .. : recursive descent
// [num] : object/element of array by number
// [*] : all objects/elements for array.
//
// If you want to use reserved characters such as `.` and `*` as a key name,
// enclose them in single quotation as follows ( $.foo.'bar.baz-*'.hoge ).
// If you want to use a single quote with reserved characters, escape it with `\` ( $.foo.'bar.baz\'s value'.hoge ).
func PathString(s string) (*Path, error) {
buf := []rune(s)
length := len(buf)
cursor := 0
builder := &PathBuilder{}
for cursor < length {
c := buf[cursor]
switch c {
case '$':
builder = builder.Root()
cursor++
case '.':
b, buf, c, err := parsePathDot(builder, buf, cursor)
if err != nil {
return nil, err
}
length = len(buf)
builder = b
cursor = c
case '[':
b, buf, c, err := parsePathIndex(builder, buf, cursor)
if err != nil {
return nil, err
}
length = len(buf)
builder = b
cursor = c
default:
return nil, fmt.Errorf("invalid path at %d: %w", cursor, ErrInvalidPathString)
}
}
return builder.Build(), nil
}
func parsePathRecursive(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
length := len(buf)
cursor += 2 // skip .. characters
start := cursor
for ; cursor < length; cursor++ {
c := buf[cursor]
switch c {
case '$':
return nil, nil, 0, fmt.Errorf("specified '$' after '..' character: %w", ErrInvalidPathString)
case '*':
return nil, nil, 0, fmt.Errorf("specified '*' after '..' character: %w", ErrInvalidPathString)
case '.', '[':
goto end
case ']':
return nil, nil, 0, fmt.Errorf("specified ']' after '..' character: %w", ErrInvalidPathString)
}
}
end:
if start == cursor {
return nil, nil, 0, fmt.Errorf("not found recursive selector: %w", ErrInvalidPathString)
}
return b.Recursive(string(buf[start:cursor])), buf, cursor, nil
}
func parsePathDot(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
if b.root == nil || b.node == nil {
return nil, nil, 0, fmt.Errorf("required '$' character at first: %w", ErrInvalidPathString)
}
length := len(buf)
if cursor+1 < length && buf[cursor+1] == '.' {
b, buf, c, err := parsePathRecursive(b, buf, cursor)
if err != nil {
return nil, nil, 0, err
}
return b, buf, c, nil
}
cursor++ // skip . character
start := cursor
// if started single quote, looking for end single quote char
if cursor < length && buf[cursor] == '\'' {
return parseQuotedKey(b, buf, cursor)
}
for ; cursor < length; cursor++ {
c := buf[cursor]
switch c {
case '$':
return nil, nil, 0, fmt.Errorf("specified '$' after '.' character: %w", ErrInvalidPathString)
case '*':
return nil, nil, 0, fmt.Errorf("specified '*' after '.' character: %w", ErrInvalidPathString)
case '.', '[':
goto end
case ']':
return nil, nil, 0, fmt.Errorf("specified ']' after '.' character: %w", ErrInvalidPathString)
}
}
end:
if start == cursor {
return nil, nil, 0, fmt.Errorf("could not find by empty key: %w", ErrInvalidPathString)
}
return b.child(string(buf[start:cursor])), buf, cursor, nil
}
func parseQuotedKey(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
if b.root == nil || b.node == nil {
return nil, nil, 0, fmt.Errorf("required '$' character at first: %w", ErrInvalidPathString)
}
cursor++ // skip single quote
start := cursor
length := len(buf)
var foundEndDelim bool
for ; cursor < length; cursor++ {
switch buf[cursor] {
case '\\':
buf = append(append([]rune{}, buf[:cursor]...), buf[cursor+1:]...)
length = len(buf)
case '\'':
foundEndDelim = true
goto end
}
}
end:
if !foundEndDelim {
return nil, nil, 0, fmt.Errorf("could not find end delimiter for key: %w", ErrInvalidPathString)
}
if start == cursor {
return nil, nil, 0, fmt.Errorf("could not find by empty key: %w", ErrInvalidPathString)
}
selector := buf[start:cursor]
cursor++
if cursor < length {
switch buf[cursor] {
case '$':
return nil, nil, 0, fmt.Errorf("specified '$' after '.' character: %w", ErrInvalidPathString)
case '*':
return nil, nil, 0, fmt.Errorf("specified '*' after '.' character: %w", ErrInvalidPathString)
case ']':
return nil, nil, 0, fmt.Errorf("specified ']' after '.' character: %w", ErrInvalidPathString)
}
}
return b.child(string(selector)), buf, cursor, nil
}
func parsePathIndex(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
if b.root == nil || b.node == nil {
return nil, nil, 0, fmt.Errorf("required '$' character at first: %w", ErrInvalidPathString)
}
length := len(buf)
cursor++ // skip '[' character
if length <= cursor {
return nil, nil, 0, fmt.Errorf("unexpected end of YAML Path: %w", ErrInvalidPathString)
}
c := buf[cursor]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*':
start := cursor
cursor++
for ; cursor < length; cursor++ {
c := buf[cursor]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
continue
}
break
}
if buf[cursor] != ']' {
return nil, nil, 0, fmt.Errorf("invalid character %s at %d: %w", string(buf[cursor]), cursor, ErrInvalidPathString)
}
numOrAll := string(buf[start:cursor])
if numOrAll == "*" {
return b.IndexAll(), buf, cursor + 1, nil
}
num, err := strconv.ParseInt(numOrAll, 10, 64)
if err != nil {
return nil, nil, 0, err
}
return b.Index(uint(num)), buf, cursor + 1, nil
}
return nil, nil, 0, fmt.Errorf("invalid character %q at %d: %w", c, cursor, ErrInvalidPathString)
}
// Path represent YAMLPath ( like a JSONPath ).
type Path struct {
node pathNode
}
// String path to text.
func (p *Path) String() string {
return p.node.String()
}
// Read decode from r and set extracted value by YAMLPath to v.
func (p *Path) Read(r io.Reader, v interface{}) error {
node, err := p.ReadNode(r)
if err != nil {
return err
}
if err := Unmarshal([]byte(node.String()), v); err != nil {
return err
}
return nil
}
// ReadNode create AST from r and extract node by YAMLPath.
func (p *Path) ReadNode(r io.Reader) (ast.Node, error) {
if p.node == nil {
return nil, ErrInvalidPath
}
var buf bytes.Buffer
if _, err := io.Copy(&buf, r); err != nil {
return nil, err
}
f, err := parser.ParseBytes(buf.Bytes(), 0)
if err != nil {
return nil, err
}
node, err := p.FilterFile(f)
if err != nil {
return nil, err
}
return node, nil
}
// Filter filter from target by YAMLPath and set it to v.
func (p *Path) Filter(target, v interface{}) error {
b, err := Marshal(target)
if err != nil {
return err
}
if err := p.Read(bytes.NewBuffer(b), v); err != nil {
return err
}
return nil
}
// FilterFile filter from ast.File by YAMLPath.
func (p *Path) FilterFile(f *ast.File) (ast.Node, error) {
for _, doc := range f.Docs {
// For simplicity, directives cannot be the target of operations
if doc.Body != nil && doc.Body.Type() == ast.DirectiveType {
continue
}
node, err := p.FilterNode(doc.Body)
if err != nil {
return nil, err
}
if node != nil {
return node, nil
}
}
return nil, fmt.Errorf("failed to find path ( %s ): %w", p.node, ErrNotFoundNode)
}
// FilterNode filter from node by YAMLPath.
func (p *Path) FilterNode(node ast.Node) (ast.Node, error) {
if node == nil {
return nil, nil
}
n, err := p.node.filter(node)
if err != nil {
return nil, err
}
return n, nil
}
// MergeFromReader merge YAML text into ast.File.
func (p *Path) MergeFromReader(dst *ast.File, src io.Reader) error {
var buf bytes.Buffer
if _, err := io.Copy(&buf, src); err != nil {
return err
}
file, err := parser.ParseBytes(buf.Bytes(), 0)
if err != nil {
return err
}
if err := p.MergeFromFile(dst, file); err != nil {
return err
}
return nil
}
// MergeFromFile merge ast.File into ast.File.
func (p *Path) MergeFromFile(dst *ast.File, src *ast.File) error {
base, err := p.FilterFile(dst)
if err != nil {
return err
}
for _, doc := range src.Docs {
if err := ast.Merge(base, doc); err != nil {
return err
}
}
return nil
}
// MergeFromNode merge ast.Node into ast.File.
func (p *Path) MergeFromNode(dst *ast.File, src ast.Node) error {
base, err := p.FilterFile(dst)
if err != nil {
return err
}
if err := ast.Merge(base, src); err != nil {
return err
}
return nil
}
// ReplaceWithReader replace ast.File with io.Reader.
func (p *Path) ReplaceWithReader(dst *ast.File, src io.Reader) error {
var buf bytes.Buffer
if _, err := io.Copy(&buf, src); err != nil {
return err
}
file, err := parser.ParseBytes(buf.Bytes(), 0)
if err != nil {
return err
}
if err := p.ReplaceWithFile(dst, file); err != nil {
return err
}
return nil
}
// ReplaceWithFile replace ast.File with ast.File.
func (p *Path) ReplaceWithFile(dst *ast.File, src *ast.File) error {
for _, doc := range src.Docs {
if err := p.ReplaceWithNode(dst, doc); err != nil {
return err
}
}
return nil
}
// ReplaceNode replace ast.File with ast.Node.
func (p *Path) ReplaceWithNode(dst *ast.File, node ast.Node) error {
for _, doc := range dst.Docs {
// For simplicity, directives cannot be the target of operations
if doc.Body != nil && doc.Body.Type() == ast.DirectiveType {
continue
}
if node.Type() == ast.DocumentType {
node = node.(*ast.DocumentNode).Body
}
if err := p.node.replace(doc.Body, node); err != nil {
return err
}
}
return nil
}
// AnnotateSource add annotation to passed source ( see section 5.1 in README.md ).
func (p *Path) AnnotateSource(source []byte, colored bool) ([]byte, error) {
file, err := parser.ParseBytes(source, 0)
if err != nil {
return nil, err
}
node, err := p.FilterFile(file)
if err != nil {
return nil, err
}
var pp printer.Printer
return []byte(pp.PrintErrorToken(node.GetToken(), colored)), nil
}
// PathBuilder represent builder for YAMLPath.
type PathBuilder struct {
root *rootNode
node pathNode
}
// Root add '$' to current path.
func (b *PathBuilder) Root() *PathBuilder {
root := newRootNode()
return &PathBuilder{root: root, node: root}
}
// IndexAll add '[*]' to current path.
func (b *PathBuilder) IndexAll() *PathBuilder {
b.node = b.node.chain(newIndexAllNode())
return b
}
// Recursive add '..selector' to current path.
func (b *PathBuilder) Recursive(selector string) *PathBuilder {
b.node = b.node.chain(newRecursiveNode(selector))
return b
}
func (b *PathBuilder) containsReservedPathCharacters(path string) bool {
if strings.Contains(path, ".") {
return true
}
if strings.Contains(path, "*") {
return true
}
return false
}
func (b *PathBuilder) enclosedSingleQuote(name string) bool {
return strings.HasPrefix(name, "'") && strings.HasSuffix(name, "'")
}
func (b *PathBuilder) normalizeSelectorName(name string) string {
if b.enclosedSingleQuote(name) {
// already escaped name
return name
}
if b.containsReservedPathCharacters(name) {
escapedName := strings.ReplaceAll(name, `'`, `\'`)
return "'" + escapedName + "'"
}
return name
}
func (b *PathBuilder) child(name string) *PathBuilder {
b.node = b.node.chain(newSelectorNode(name))
return b
}
// Child add '.name' to current path.
func (b *PathBuilder) Child(name string) *PathBuilder {
return b.child(b.normalizeSelectorName(name))
}
// Index add '[idx]' to current path.
func (b *PathBuilder) Index(idx uint) *PathBuilder {
b.node = b.node.chain(newIndexNode(idx))
return b
}
// Build build YAMLPath.
func (b *PathBuilder) Build() *Path {
return &Path{node: b.root}
}
type pathNode interface {
fmt.Stringer
chain(pathNode) pathNode
filter(ast.Node) (ast.Node, error)
replace(ast.Node, ast.Node) error
}
type basePathNode struct {
child pathNode
}
func (n *basePathNode) chain(node pathNode) pathNode {
n.child = node
return node
}
type rootNode struct {
*basePathNode
}
func newRootNode() *rootNode {
return &rootNode{basePathNode: &basePathNode{}}
}
func (n *rootNode) String() string {
s := "$"
if n.child != nil {
s += n.child.String()
}
return s
}
func (n *rootNode) filter(node ast.Node) (ast.Node, error) {
if n.child == nil {
return node, nil
}
filtered, err := n.child.filter(node)
if err != nil {
return nil, err
}
return filtered, nil
}
func (n *rootNode) replace(node ast.Node, target ast.Node) error {
if n.child == nil {
return nil
}
if err := n.child.replace(node, target); err != nil {
return err
}
return nil
}
type selectorNode struct {
*basePathNode
selector string
}
func newSelectorNode(selector string) *selectorNode {
return &selectorNode{
basePathNode: &basePathNode{},
selector: selector,
}
}
func (n *selectorNode) filter(node ast.Node) (ast.Node, error) {
selector := n.selector
if len(selector) > 1 && selector[0] == '\'' && selector[len(selector)-1] == '\'' {
selector = selector[1 : len(selector)-1]
}
switch node.Type() {
case ast.MappingType:
for _, value := range node.(*ast.MappingNode).Values {
key := value.Key.GetToken().Value
if len(key) > 0 {
switch key[0] {
case '"':
var err error
key, err = strconv.Unquote(key)
if err != nil {
return nil, err
}
case '\'':
if len(key) > 1 && key[len(key)-1] == '\'' {
key = key[1 : len(key)-1]
}
}
}
if key == selector {
if n.child == nil {
return value.Value, nil
}
filtered, err := n.child.filter(value.Value)
if err != nil {
return nil, err
}
return filtered, nil
}
}
case ast.MappingValueType:
value, _ := node.(*ast.MappingValueNode)
key := value.Key.GetToken().Value
if key == selector {
if n.child == nil {
return value.Value, nil
}
filtered, err := n.child.filter(value.Value)
if err != nil {
return nil, err
}
return filtered, nil
}
default:
return nil, fmt.Errorf("expected node type is map or map value. but got %s: %w", node.Type(), ErrInvalidQuery)
}
return nil, nil
}
func (n *selectorNode) replaceMapValue(value *ast.MappingValueNode, target ast.Node) error {
key := value.Key.GetToken().Value
if key != n.selector {
return nil
}
if n.child == nil {
if err := value.Replace(target); err != nil {
return err
}
} else {
if err := n.child.replace(value.Value, target); err != nil {
return err
}
}
return nil
}
func (n *selectorNode) replace(node ast.Node, target ast.Node) error {
switch node.Type() {
case ast.MappingType:
for _, value := range node.(*ast.MappingNode).Values {
if err := n.replaceMapValue(value, target); err != nil {
return err
}
}
case ast.MappingValueType:
value, _ := node.(*ast.MappingValueNode)
if err := n.replaceMapValue(value, target); err != nil {
return err
}
default:
return fmt.Errorf("expected node type is map or map value. but got %s: %w", node.Type(), ErrInvalidQuery)
}
return nil
}
func (n *selectorNode) String() string {
var builder PathBuilder
selector := builder.normalizeSelectorName(n.selector)
s := fmt.Sprintf(".%s", selector)
if n.child != nil {
s += n.child.String()
}
return s
}
type indexNode struct {
*basePathNode
selector uint
}
func newIndexNode(selector uint) *indexNode {
return &indexNode{
basePathNode: &basePathNode{},
selector: selector,
}
}
func (n *indexNode) filter(node ast.Node) (ast.Node, error) {
if node.Type() != ast.SequenceType {
return nil, fmt.Errorf("expected sequence type node. but got %s: %w", node.Type(), ErrInvalidQuery)
}
sequence, _ := node.(*ast.SequenceNode)
if n.selector >= uint(len(sequence.Values)) {
return nil, fmt.Errorf("expected index is %d. but got sequences has %d items: %w", n.selector, len(sequence.Values), ErrInvalidQuery)
}
value := sequence.Values[n.selector]
if n.child == nil {
return value, nil
}
filtered, err := n.child.filter(value)
if err != nil {
return nil, err
}
return filtered, nil
}
func (n *indexNode) replace(node ast.Node, target ast.Node) error {
if node.Type() != ast.SequenceType {
return fmt.Errorf("expected sequence type node. but got %s: %w", node.Type(), ErrInvalidQuery)
}
sequence, _ := node.(*ast.SequenceNode)
if n.selector >= uint(len(sequence.Values)) {
return fmt.Errorf("expected index is %d. but got sequences has %d items: %w", n.selector, len(sequence.Values), ErrInvalidQuery)
}
if n.child == nil {
if err := sequence.Replace(int(n.selector), target); err != nil {
return err
}
return nil
}
if err := n.child.replace(sequence.Values[n.selector], target); err != nil {
return err
}
return nil
}
func (n *indexNode) String() string {
s := fmt.Sprintf("[%d]", n.selector)
if n.child != nil {
s += n.child.String()
}
return s
}
type indexAllNode struct {
*basePathNode
}
func newIndexAllNode() *indexAllNode {
return &indexAllNode{
basePathNode: &basePathNode{},
}
}
func (n *indexAllNode) String() string {
s := "[*]"
if n.child != nil {
s += n.child.String()
}
return s
}
func (n *indexAllNode) filter(node ast.Node) (ast.Node, error) {
if node.Type() != ast.SequenceType {
return nil, fmt.Errorf("expected sequence type node. but got %s: %w", node.Type(), ErrInvalidQuery)
}
sequence, _ := node.(*ast.SequenceNode)
if n.child == nil {
return sequence, nil
}
out := *sequence
out.Values = []ast.Node{}
for _, value := range sequence.Values {
filtered, err := n.child.filter(value)
if err != nil {
return nil, err
}
out.Values = append(out.Values, filtered)
}
return &out, nil
}
func (n *indexAllNode) replace(node ast.Node, target ast.Node) error {
if node.Type() != ast.SequenceType {
return fmt.Errorf("expected sequence type node. but got %s: %w", node.Type(), ErrInvalidQuery)
}
sequence, _ := node.(*ast.SequenceNode)
if n.child == nil {
for idx := range sequence.Values {
if err := sequence.Replace(idx, target); err != nil {
return err
}
}
return nil
}
for _, value := range sequence.Values {
if err := n.child.replace(value, target); err != nil {
return err
}
}
return nil
}
type recursiveNode struct {
*basePathNode
selector string
}
func newRecursiveNode(selector string) *recursiveNode {
return &recursiveNode{
basePathNode: &basePathNode{},
selector: selector,
}
}
func (n *recursiveNode) String() string {
s := fmt.Sprintf("..%s", n.selector)
if n.child != nil {
s += n.child.String()
}
return s
}
func (n *recursiveNode) filterNode(node ast.Node) (*ast.SequenceNode, error) {
sequence := &ast.SequenceNode{BaseNode: &ast.BaseNode{}}
switch typedNode := node.(type) {
case *ast.MappingNode:
for _, value := range typedNode.Values {
seq, err := n.filterNode(value)
if err != nil {
return nil, err
}
sequence.Values = append(sequence.Values, seq.Values...)
}
case *ast.MappingValueNode:
key := typedNode.Key.GetToken().Value
if n.selector == key {
sequence.Values = append(sequence.Values, typedNode.Value)
}
seq, err := n.filterNode(typedNode.Value)
if err != nil {
return nil, err
}
sequence.Values = append(sequence.Values, seq.Values...)
case *ast.SequenceNode:
for _, value := range typedNode.Values {
seq, err := n.filterNode(value)
if err != nil {
return nil, err
}
sequence.Values = append(sequence.Values, seq.Values...)
}
}
return sequence, nil
}
func (n *recursiveNode) filter(node ast.Node) (ast.Node, error) {
sequence, err := n.filterNode(node)
if err != nil {
return nil, err
}
sequence.Start = node.GetToken()
return sequence, nil
}
func (n *recursiveNode) replaceNode(node ast.Node, target ast.Node) error {
switch typedNode := node.(type) {
case *ast.MappingNode:
for _, value := range typedNode.Values {
if err := n.replaceNode(value, target); err != nil {
return err
}
}
case *ast.MappingValueNode:
key := typedNode.Key.GetToken().Value
if n.selector == key {
if err := typedNode.Replace(target); err != nil {
return err
}
}
if err := n.replaceNode(typedNode.Value, target); err != nil {
return err
}
case *ast.SequenceNode:
for _, value := range typedNode.Values {
if err := n.replaceNode(value, target); err != nil {
return err
}
}
}
return nil
}
func (n *recursiveNode) replace(node ast.Node, target ast.Node) error {
if err := n.replaceNode(node, target); err != nil {
return err
}
return nil
}

83
vendor/github.com/goccy/go-yaml/printer/color.go generated vendored Normal file
View File

@@ -0,0 +1,83 @@
// This source inspired by https://github.com/fatih/color.
package printer
import (
"fmt"
"strings"
)
type ColorAttribute int
const (
ColorReset ColorAttribute = iota
ColorBold
ColorFaint
ColorItalic
ColorUnderline
ColorBlinkSlow
ColorBlinkRapid
ColorReverseVideo
ColorConcealed
ColorCrossedOut
)
const (
ColorFgHiBlack ColorAttribute = iota + 90
ColorFgHiRed
ColorFgHiGreen
ColorFgHiYellow
ColorFgHiBlue
ColorFgHiMagenta
ColorFgHiCyan
ColorFgHiWhite
)
const (
ColorResetBold ColorAttribute = iota + 22
ColorResetItalic
ColorResetUnderline
ColorResetBlinking
ColorResetReversed
ColorResetConcealed
ColorResetCrossedOut
)
const escape = "\x1b"
var colorResetMap = map[ColorAttribute]ColorAttribute{
ColorBold: ColorResetBold,
ColorFaint: ColorResetBold,
ColorItalic: ColorResetItalic,
ColorUnderline: ColorResetUnderline,
ColorBlinkSlow: ColorResetBlinking,
ColorBlinkRapid: ColorResetBlinking,
ColorReverseVideo: ColorResetReversed,
ColorConcealed: ColorResetConcealed,
ColorCrossedOut: ColorResetCrossedOut,
}
func format(attrs ...ColorAttribute) string {
format := make([]string, 0, len(attrs))
for _, attr := range attrs {
format = append(format, fmt.Sprint(attr))
}
return fmt.Sprintf("%s[%sm", escape, strings.Join(format, ";"))
}
func unformat(attrs ...ColorAttribute) string {
format := make([]string, len(attrs))
for _, attr := range attrs {
v := fmt.Sprint(ColorReset)
reset, exists := colorResetMap[attr]
if exists {
v = fmt.Sprint(reset)
}
format = append(format, v)
}
return fmt.Sprintf("%s[%sm", escape, strings.Join(format, ";"))
}
func colorize(msg string, attrs ...ColorAttribute) string {
return format(attrs...) + msg + unformat(attrs...)
}

353
vendor/github.com/goccy/go-yaml/printer/printer.go generated vendored Normal file
View File

@@ -0,0 +1,353 @@
package printer
import (
"fmt"
"math"
"strings"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/token"
)
// Property additional property set for each the token
type Property struct {
Prefix string
Suffix string
}
// PrintFunc returns property instance
type PrintFunc func() *Property
// Printer create text from token collection or ast
type Printer struct {
LineNumber bool
LineNumberFormat func(num int) string
MapKey PrintFunc
Anchor PrintFunc
Alias PrintFunc
Bool PrintFunc
String PrintFunc
Number PrintFunc
Comment PrintFunc
}
func defaultLineNumberFormat(num int) string {
return fmt.Sprintf("%2d | ", num)
}
func (p *Printer) property(tk *token.Token) *Property {
prop := &Property{}
switch tk.PreviousType() {
case token.AnchorType:
if p.Anchor != nil {
return p.Anchor()
}
return prop
case token.AliasType:
if p.Alias != nil {
return p.Alias()
}
return prop
}
switch tk.NextType() {
case token.MappingValueType:
if p.MapKey != nil {
return p.MapKey()
}
return prop
}
switch tk.Type {
case token.BoolType:
if p.Bool != nil {
return p.Bool()
}
return prop
case token.AnchorType:
if p.Anchor != nil {
return p.Anchor()
}
return prop
case token.AliasType:
if p.Anchor != nil {
return p.Alias()
}
return prop
case token.StringType, token.SingleQuoteType, token.DoubleQuoteType:
if p.String != nil {
return p.String()
}
return prop
case token.IntegerType, token.FloatType:
if p.Number != nil {
return p.Number()
}
return prop
case token.CommentType:
if p.Comment != nil {
return p.Comment()
}
return prop
default:
}
return prop
}
// PrintTokens create text from token collection
func (p *Printer) PrintTokens(tokens token.Tokens) string {
if len(tokens) == 0 {
return ""
}
if p.LineNumber {
if p.LineNumberFormat == nil {
p.LineNumberFormat = defaultLineNumberFormat
}
}
texts := []string{}
lineNumber := tokens[0].Position.Line
for _, tk := range tokens {
lines := strings.Split(tk.Origin, "\n")
prop := p.property(tk)
header := ""
if p.LineNumber {
header = p.LineNumberFormat(lineNumber)
}
if len(lines) == 1 {
line := prop.Prefix + lines[0] + prop.Suffix
if len(texts) == 0 {
texts = append(texts, header+line)
lineNumber++
} else {
text := texts[len(texts)-1]
texts[len(texts)-1] = text + line
}
} else {
for idx, src := range lines {
if p.LineNumber {
header = p.LineNumberFormat(lineNumber)
}
line := prop.Prefix + src + prop.Suffix
if idx == 0 {
if len(texts) == 0 {
texts = append(texts, header+line)
lineNumber++
} else {
text := texts[len(texts)-1]
texts[len(texts)-1] = text + line
}
} else {
texts = append(texts, fmt.Sprintf("%s%s", header, line))
lineNumber++
}
}
}
}
return strings.Join(texts, "\n")
}
// PrintNode create text from ast.Node
func (p *Printer) PrintNode(node ast.Node) []byte {
return []byte(fmt.Sprintf("%+v\n", node))
}
func (p *Printer) setDefaultColorSet() {
p.Bool = func() *Property {
return &Property{
Prefix: format(ColorFgHiMagenta),
Suffix: format(ColorReset),
}
}
p.Number = func() *Property {
return &Property{
Prefix: format(ColorFgHiMagenta),
Suffix: format(ColorReset),
}
}
p.MapKey = func() *Property {
return &Property{
Prefix: format(ColorFgHiCyan),
Suffix: format(ColorReset),
}
}
p.Anchor = func() *Property {
return &Property{
Prefix: format(ColorFgHiYellow),
Suffix: format(ColorReset),
}
}
p.Alias = func() *Property {
return &Property{
Prefix: format(ColorFgHiYellow),
Suffix: format(ColorReset),
}
}
p.String = func() *Property {
return &Property{
Prefix: format(ColorFgHiGreen),
Suffix: format(ColorReset),
}
}
p.Comment = func() *Property {
return &Property{
Prefix: format(ColorFgHiBlack),
Suffix: format(ColorReset),
}
}
}
func (p *Printer) PrintErrorMessage(msg string, isColored bool) string {
if isColored {
return fmt.Sprintf("%s%s%s",
format(ColorFgHiRed),
msg,
format(ColorReset),
)
}
return msg
}
func (p *Printer) removeLeftSideNewLineChar(src string) string {
return strings.TrimLeft(strings.TrimLeft(strings.TrimLeft(src, "\r"), "\n"), "\r\n")
}
func (p *Printer) removeRightSideNewLineChar(src string) string {
return strings.TrimRight(strings.TrimRight(strings.TrimRight(src, "\r"), "\n"), "\r\n")
}
func (p *Printer) removeRightSideWhiteSpaceChar(src string) string {
return p.removeRightSideNewLineChar(strings.TrimRight(src, " "))
}
func (p *Printer) newLineCount(s string) int {
src := []rune(s)
size := len(src)
cnt := 0
for i := 0; i < size; i++ {
c := src[i]
switch c {
case '\r':
if i+1 < size && src[i+1] == '\n' {
i++
}
cnt++
case '\n':
cnt++
}
}
return cnt
}
func (p *Printer) isNewLineLastChar(s string) bool {
for i := len(s) - 1; i > 0; i-- {
c := s[i]
switch c {
case ' ':
continue
case '\n', '\r':
return true
}
break
}
return false
}
func (p *Printer) printBeforeTokens(tk *token.Token, minLine, extLine int) token.Tokens {
for tk.Prev != nil {
if tk.Prev.Position.Line < minLine {
break
}
tk = tk.Prev
}
minTk := tk.Clone()
if minTk.Prev != nil {
// add white spaces to minTk by prev token
prev := minTk.Prev
whiteSpaceLen := len(prev.Origin) - len(strings.TrimRight(prev.Origin, " "))
minTk.Origin = strings.Repeat(" ", whiteSpaceLen) + minTk.Origin
}
minTk.Origin = p.removeLeftSideNewLineChar(minTk.Origin)
tokens := token.Tokens{minTk}
tk = minTk.Next
for tk != nil && tk.Position.Line <= extLine {
clonedTk := tk.Clone()
tokens.Add(clonedTk)
tk = clonedTk.Next
}
lastTk := tokens[len(tokens)-1]
trimmedOrigin := p.removeRightSideWhiteSpaceChar(lastTk.Origin)
suffix := lastTk.Origin[len(trimmedOrigin):]
lastTk.Origin = trimmedOrigin
if lastTk.Next != nil && len(suffix) > 1 {
next := lastTk.Next.Clone()
// add suffix to header of next token
if suffix[0] == '\n' || suffix[0] == '\r' {
suffix = suffix[1:]
}
next.Origin = suffix + next.Origin
lastTk.Next = next
}
return tokens
}
func (p *Printer) printAfterTokens(tk *token.Token, maxLine int) token.Tokens {
tokens := token.Tokens{}
if tk == nil {
return tokens
}
if tk.Position.Line > maxLine {
return tokens
}
minTk := tk.Clone()
minTk.Origin = p.removeLeftSideNewLineChar(minTk.Origin)
tokens.Add(minTk)
tk = minTk.Next
for tk != nil && tk.Position.Line <= maxLine {
clonedTk := tk.Clone()
tokens.Add(clonedTk)
tk = clonedTk.Next
}
return tokens
}
func (p *Printer) setupErrorTokenFormat(annotateLine int, isColored bool) {
prefix := func(annotateLine, num int) string {
if annotateLine == num {
return fmt.Sprintf("> %2d | ", num)
}
return fmt.Sprintf(" %2d | ", num)
}
p.LineNumber = true
p.LineNumberFormat = func(num int) string {
if isColored {
return colorize(prefix(annotateLine, num), ColorBold, ColorFgHiWhite)
}
return prefix(annotateLine, num)
}
if isColored {
p.setDefaultColorSet()
}
}
func (p *Printer) PrintErrorToken(tk *token.Token, isColored bool) string {
errToken := tk
curLine := tk.Position.Line
curExtLine := curLine + p.newLineCount(p.removeLeftSideNewLineChar(tk.Origin))
if p.isNewLineLastChar(tk.Origin) {
// if last character ( exclude white space ) is new line character, ignore it.
curExtLine--
}
minLine := int(math.Max(float64(curLine-3), 1))
maxLine := curExtLine + 3
p.setupErrorTokenFormat(curLine, isColored)
beforeTokens := p.printBeforeTokens(tk, minLine, curExtLine)
lastTk := beforeTokens[len(beforeTokens)-1]
afterTokens := p.printAfterTokens(lastTk.Next, maxLine)
beforeSource := p.PrintTokens(beforeTokens)
prefixSpaceNum := len(fmt.Sprintf(" %2d | ", curLine))
annotateLine := strings.Repeat(" ", prefixSpaceNum+errToken.Position.Column-1) + "^"
afterSource := p.PrintTokens(afterTokens)
return fmt.Sprintf("%s\n%s\n%s", beforeSource, annotateLine, afterSource)
}

452
vendor/github.com/goccy/go-yaml/scanner/context.go generated vendored Normal file
View File

@@ -0,0 +1,452 @@
package scanner
import (
"errors"
"strconv"
"strings"
"sync"
"github.com/goccy/go-yaml/token"
)
// Context context at scanning
type Context struct {
idx int
size int
notSpaceCharPos int
notSpaceOrgCharPos int
src []rune
buf []rune
obuf []rune
tokens token.Tokens
mstate *MultiLineState
}
type MultiLineState struct {
opt string
firstLineIndentColumn int
prevLineIndentColumn int
lineIndentColumn int
lastNotSpaceOnlyLineIndentColumn int
spaceOnlyIndentColumn int
foldedNewLine bool
isRawFolded bool
isLiteral bool
isFolded bool
}
var (
ctxPool = sync.Pool{
New: func() interface{} {
return createContext()
},
}
)
func createContext() *Context {
return &Context{
idx: 0,
tokens: token.Tokens{},
}
}
func newContext(src []rune) *Context {
ctx, _ := ctxPool.Get().(*Context)
ctx.reset(src)
return ctx
}
func (c *Context) release() {
ctxPool.Put(c)
}
func (c *Context) clear() {
c.resetBuffer()
c.mstate = nil
}
func (c *Context) reset(src []rune) {
c.idx = 0
c.size = len(src)
c.src = src
c.tokens = c.tokens[:0]
c.resetBuffer()
c.mstate = nil
}
func (c *Context) resetBuffer() {
c.buf = c.buf[:0]
c.obuf = c.obuf[:0]
c.notSpaceCharPos = 0
c.notSpaceOrgCharPos = 0
}
func (c *Context) breakMultiLine() {
c.mstate = nil
}
func (c *Context) getMultiLineState() *MultiLineState {
return c.mstate
}
func (c *Context) setLiteral(lastDelimColumn int, opt string) {
mstate := &MultiLineState{
isLiteral: true,
opt: opt,
}
indent := firstLineIndentColumnByOpt(opt)
if indent > 0 {
mstate.firstLineIndentColumn = lastDelimColumn + indent
}
c.mstate = mstate
}
func (c *Context) setFolded(lastDelimColumn int, opt string) {
mstate := &MultiLineState{
isFolded: true,
opt: opt,
}
indent := firstLineIndentColumnByOpt(opt)
if indent > 0 {
mstate.firstLineIndentColumn = lastDelimColumn + indent
}
c.mstate = mstate
}
func (c *Context) setRawFolded(column int) {
mstate := &MultiLineState{
isRawFolded: true,
}
mstate.updateIndentColumn(column)
c.mstate = mstate
}
func firstLineIndentColumnByOpt(opt string) int {
opt = strings.TrimPrefix(opt, "-")
opt = strings.TrimPrefix(opt, "+")
opt = strings.TrimSuffix(opt, "-")
opt = strings.TrimSuffix(opt, "+")
i, _ := strconv.ParseInt(opt, 10, 64)
return int(i)
}
func (s *MultiLineState) lastDelimColumn() int {
if s.firstLineIndentColumn == 0 {
return 0
}
return s.firstLineIndentColumn - 1
}
func (s *MultiLineState) updateIndentColumn(column int) {
if s.firstLineIndentColumn == 0 {
s.firstLineIndentColumn = column
}
if s.lineIndentColumn == 0 {
s.lineIndentColumn = column
}
}
func (s *MultiLineState) updateSpaceOnlyIndentColumn(column int) {
if s.firstLineIndentColumn != 0 {
return
}
s.spaceOnlyIndentColumn = column
}
func (s *MultiLineState) validateIndentAfterSpaceOnly(column int) error {
if s.firstLineIndentColumn != 0 {
return nil
}
if s.spaceOnlyIndentColumn > column {
return errors.New("invalid number of indent is specified after space only")
}
return nil
}
func (s *MultiLineState) validateIndentColumn() error {
if firstLineIndentColumnByOpt(s.opt) == 0 {
return nil
}
if s.firstLineIndentColumn > s.lineIndentColumn {
return errors.New("invalid number of indent is specified in the multi-line header")
}
return nil
}
func (s *MultiLineState) updateNewLineState() {
s.prevLineIndentColumn = s.lineIndentColumn
if s.lineIndentColumn != 0 {
s.lastNotSpaceOnlyLineIndentColumn = s.lineIndentColumn
}
s.foldedNewLine = true
s.lineIndentColumn = 0
}
func (s *MultiLineState) isIndentColumn(column int) bool {
if s.firstLineIndentColumn == 0 {
return column == 1
}
return s.firstLineIndentColumn > column
}
func (s *MultiLineState) addIndent(ctx *Context, column int) {
if s.firstLineIndentColumn == 0 {
return
}
// If the first line of the document has already been evaluated, the number is treated as the threshold, since the `firstLineIndentColumn` is a positive number.
if column < s.firstLineIndentColumn {
return
}
// `c.foldedNewLine` is a variable that is set to true for every newline.
if !s.isLiteral && s.foldedNewLine {
s.foldedNewLine = false
}
// Since addBuf ignore space character, add to the buffer directly.
ctx.buf = append(ctx.buf, ' ')
ctx.notSpaceCharPos = len(ctx.buf)
}
// updateNewLineInFolded if Folded or RawFolded context and the content on the current line starts at the same column as the previous line,
// treat the new-line-char as a space.
func (s *MultiLineState) updateNewLineInFolded(ctx *Context, column int) {
if s.isLiteral {
return
}
// Folded or RawFolded.
if !s.foldedNewLine {
return
}
var (
lastChar rune
prevLastChar rune
)
if len(ctx.buf) != 0 {
lastChar = ctx.buf[len(ctx.buf)-1]
}
if len(ctx.buf) > 1 {
prevLastChar = ctx.buf[len(ctx.buf)-2]
}
if s.lineIndentColumn == s.prevLineIndentColumn {
// ---
// >
// a
// b
if lastChar == '\n' {
ctx.buf[len(ctx.buf)-1] = ' '
}
} else if s.prevLineIndentColumn == 0 && s.lastNotSpaceOnlyLineIndentColumn == column {
// if previous line is indent-space and new-line-char only, prevLineIndentColumn is zero.
// In this case, last new-line-char is removed.
// ---
// >
// a
//
// b
if lastChar == '\n' && prevLastChar == '\n' {
ctx.buf = ctx.buf[:len(ctx.buf)-1]
ctx.notSpaceCharPos = len(ctx.buf)
}
}
s.foldedNewLine = false
}
func (s *MultiLineState) hasTrimAllEndNewlineOpt() bool {
return strings.HasPrefix(s.opt, "-") || strings.HasSuffix(s.opt, "-") || s.isRawFolded
}
func (s *MultiLineState) hasKeepAllEndNewlineOpt() bool {
return strings.HasPrefix(s.opt, "+") || strings.HasSuffix(s.opt, "+")
}
func (c *Context) addToken(tk *token.Token) {
if tk == nil {
return
}
c.tokens = append(c.tokens, tk)
}
func (c *Context) addBuf(r rune) {
if len(c.buf) == 0 && (r == ' ' || r == '\t') {
return
}
c.buf = append(c.buf, r)
if r != ' ' && r != '\t' {
c.notSpaceCharPos = len(c.buf)
}
}
func (c *Context) addBufWithTab(r rune) {
if len(c.buf) == 0 && r == ' ' {
return
}
c.buf = append(c.buf, r)
if r != ' ' {
c.notSpaceCharPos = len(c.buf)
}
}
func (c *Context) addOriginBuf(r rune) {
c.obuf = append(c.obuf, r)
if r != ' ' && r != '\t' {
c.notSpaceOrgCharPos = len(c.obuf)
}
}
func (c *Context) removeRightSpaceFromBuf() {
trimmedBuf := c.obuf[:c.notSpaceOrgCharPos]
buflen := len(trimmedBuf)
diff := len(c.obuf) - buflen
if diff > 0 {
c.obuf = c.obuf[:buflen]
c.buf = c.bufferedSrc()
}
}
func (c *Context) isEOS() bool {
return len(c.src)-1 <= c.idx
}
func (c *Context) isNextEOS() bool {
return len(c.src) <= c.idx+1
}
func (c *Context) next() bool {
return c.idx < c.size
}
func (c *Context) source(s, e int) string {
return string(c.src[s:e])
}
func (c *Context) previousChar() rune {
if c.idx > 0 {
return c.src[c.idx-1]
}
return rune(0)
}
func (c *Context) currentChar() rune {
if c.size > c.idx {
return c.src[c.idx]
}
return rune(0)
}
func (c *Context) nextChar() rune {
if c.size > c.idx+1 {
return c.src[c.idx+1]
}
return rune(0)
}
func (c *Context) repeatNum(r rune) int {
cnt := 0
for i := c.idx; i < c.size; i++ {
if c.src[i] == r {
cnt++
} else {
break
}
}
return cnt
}
func (c *Context) progress(num int) {
c.idx += num
}
func (c *Context) existsBuffer() bool {
return len(c.bufferedSrc()) != 0
}
func (c *Context) isMultiLine() bool {
return c.mstate != nil
}
func (c *Context) bufferedSrc() []rune {
src := c.buf[:c.notSpaceCharPos]
if c.isMultiLine() {
mstate := c.getMultiLineState()
// remove end '\n' character and trailing empty lines.
// https://yaml.org/spec/1.2.2/#8112-block-chomping-indicator
if mstate.hasTrimAllEndNewlineOpt() {
// If the '-' flag is specified, all trailing newline characters will be removed.
src = []rune(strings.TrimRight(string(src), "\n"))
} else if !mstate.hasKeepAllEndNewlineOpt() {
// Normally, all but one of the trailing newline characters are removed.
var newLineCharCount int
for i := len(src) - 1; i >= 0; i-- {
if src[i] == '\n' {
newLineCharCount++
continue
}
break
}
removedNewLineCharCount := newLineCharCount - 1
for removedNewLineCharCount > 0 {
src = []rune(strings.TrimSuffix(string(src), "\n"))
removedNewLineCharCount--
}
}
// If the text ends with a space character, remove all of them.
if mstate.hasTrimAllEndNewlineOpt() {
src = []rune(strings.TrimRight(string(src), " "))
}
if string(src) == "\n" {
// If the content consists only of a newline,
// it can be considered as the document ending without any specified value,
// so it is treated as an empty string.
src = []rune{}
}
if mstate.hasKeepAllEndNewlineOpt() && len(src) == 0 {
src = []rune{'\n'}
}
}
return src
}
func (c *Context) bufferedToken(pos *token.Position) *token.Token {
if c.idx == 0 {
return nil
}
source := c.bufferedSrc()
if len(source) == 0 {
c.buf = c.buf[:0] // clear value's buffer only.
return nil
}
var tk *token.Token
if c.isMultiLine() {
tk = token.String(string(source), string(c.obuf), pos)
} else {
tk = token.New(string(source), string(c.obuf), pos)
}
c.setTokenTypeByPrevTag(tk)
c.resetBuffer()
return tk
}
func (c *Context) setTokenTypeByPrevTag(tk *token.Token) {
lastTk := c.lastToken()
if lastTk == nil {
return
}
if lastTk.Type != token.TagType {
return
}
tag := token.ReservedTagKeyword(lastTk.Value)
if _, exists := token.ReservedTagKeywordMap[tag]; !exists {
tk.Type = token.StringType
}
}
func (c *Context) lastToken() *token.Token {
if len(c.tokens) != 0 {
return c.tokens[len(c.tokens)-1]
}
return nil
}

17
vendor/github.com/goccy/go-yaml/scanner/error.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
package scanner
import "github.com/goccy/go-yaml/token"
type InvalidTokenError struct {
Token *token.Token
}
func (e *InvalidTokenError) Error() string {
return e.Token.Error
}
func ErrInvalidToken(tk *token.Token) *InvalidTokenError {
return &InvalidTokenError{
Token: tk,
}
}

1536
vendor/github.com/goccy/go-yaml/scanner/scanner.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

113
vendor/github.com/goccy/go-yaml/stdlib_quote.go generated vendored Normal file
View File

@@ -0,0 +1,113 @@
// Copied and trimmed down from https://github.com/golang/go/blob/e3769299cd3484e018e0e2a6e1b95c2b18ce4f41/src/strconv/quote.go
// We want to use the standard library's private "quoteWith" function rather than write our own so that we get robust unicode support.
// Every private function called by quoteWith was copied.
// There are 2 modifications to simplify the code:
// 1. The unicode.IsPrint function was substituted for the custom implementation of IsPrint
// 2. All code paths reachable only when ASCIIonly or grphicOnly are set to true were removed.
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package yaml
import (
"unicode"
"unicode/utf8"
)
const (
lowerhex = "0123456789abcdef"
)
func quoteWith(s string, quote byte) string {
return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote))
}
func appendQuotedWith(buf []byte, s string, quote byte) []byte {
// Often called with big strings, so preallocate. If there's quoting,
// this is conservative but still helps a lot.
if cap(buf)-len(buf) < len(s) {
nBuf := make([]byte, len(buf), len(buf)+1+len(s)+1)
copy(nBuf, buf)
buf = nBuf
}
buf = append(buf, quote)
for width := 0; len(s) > 0; s = s[width:] {
r := rune(s[0])
width = 1
if r >= utf8.RuneSelf {
r, width = utf8.DecodeRuneInString(s)
}
if width == 1 && r == utf8.RuneError {
buf = append(buf, `\x`...)
buf = append(buf, lowerhex[s[0]>>4])
buf = append(buf, lowerhex[s[0]&0xF])
continue
}
buf = appendEscapedRune(buf, r, quote)
}
buf = append(buf, quote)
return buf
}
func appendEscapedRune(buf []byte, r rune, quote byte) []byte {
var runeTmp [utf8.UTFMax]byte
// goccy/go-yaml patch on top of the standard library's appendEscapedRune function.
//
// We use this to implement the YAML single-quoted string, where the only escape sequence is '', which represents a single quote.
// The below snippet from the standard library is for escaping e.g. \ with \\, which is not what we want for the single-quoted string.
//
// if r == rune(quote) || r == '\\' { // always backslashed
// buf = append(buf, '\\')
// buf = append(buf, byte(r))
// return buf
// }
if r == rune(quote) {
buf = append(buf, byte(r))
buf = append(buf, byte(r))
return buf
}
if unicode.IsPrint(r) {
n := utf8.EncodeRune(runeTmp[:], r)
buf = append(buf, runeTmp[:n]...)
return buf
}
switch r {
case '\a':
buf = append(buf, `\a`...)
case '\b':
buf = append(buf, `\b`...)
case '\f':
buf = append(buf, `\f`...)
case '\n':
buf = append(buf, `\n`...)
case '\r':
buf = append(buf, `\r`...)
case '\t':
buf = append(buf, `\t`...)
case '\v':
buf = append(buf, `\v`...)
default:
switch {
case r < ' ':
buf = append(buf, `\x`...)
buf = append(buf, lowerhex[byte(r)>>4])
buf = append(buf, lowerhex[byte(r)&0xF])
case r > utf8.MaxRune:
r = 0xFFFD
fallthrough
case r < 0x10000:
buf = append(buf, `\u`...)
for s := 12; s >= 0; s -= 4 {
buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
default:
buf = append(buf, `\U`...)
for s := 28; s >= 0; s -= 4 {
buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
}
}
return buf
}

128
vendor/github.com/goccy/go-yaml/struct.go generated vendored Normal file
View File

@@ -0,0 +1,128 @@
package yaml
import (
"fmt"
"reflect"
"strings"
)
const (
// StructTagName tag keyword for Marshal/Unmarshal
StructTagName = "yaml"
)
// StructField information for each the field in structure
type StructField struct {
FieldName string
RenderName string
AnchorName string
AliasName string
IsAutoAnchor bool
IsAutoAlias bool
IsOmitEmpty bool
IsOmitZero bool
IsFlow bool
IsInline bool
}
func getTag(field reflect.StructField) string {
// If struct tag `yaml` exist, use that. If no `yaml`
// exists, but `json` does, use that and try the best to
// adhere to its rules
tag := field.Tag.Get(StructTagName)
if tag == "" {
tag = field.Tag.Get(`json`)
}
return tag
}
func structField(field reflect.StructField) *StructField {
tag := getTag(field)
fieldName := strings.ToLower(field.Name)
options := strings.Split(tag, ",")
if len(options) > 0 {
if options[0] != "" {
fieldName = options[0]
}
}
sf := &StructField{
FieldName: field.Name,
RenderName: fieldName,
}
if len(options) > 1 {
for _, opt := range options[1:] {
switch {
case opt == "omitempty":
sf.IsOmitEmpty = true
case opt == "omitzero":
sf.IsOmitZero = true
case opt == "flow":
sf.IsFlow = true
case opt == "inline":
sf.IsInline = true
case strings.HasPrefix(opt, "anchor"):
anchor := strings.Split(opt, "=")
if len(anchor) > 1 {
sf.AnchorName = anchor[1]
} else {
sf.IsAutoAnchor = true
}
case strings.HasPrefix(opt, "alias"):
alias := strings.Split(opt, "=")
if len(alias) > 1 {
sf.AliasName = alias[1]
} else {
sf.IsAutoAlias = true
}
default:
}
}
}
return sf
}
func isIgnoredStructField(field reflect.StructField) bool {
if field.PkgPath != "" && !field.Anonymous {
// private field
return true
}
return getTag(field) == "-"
}
type StructFieldMap map[string]*StructField
func (m StructFieldMap) isIncludedRenderName(name string) bool {
for _, v := range m {
if !v.IsInline && v.RenderName == name {
return true
}
}
return false
}
func (m StructFieldMap) hasMergeProperty() bool {
for _, v := range m {
if v.IsOmitEmpty && v.IsInline && v.IsAutoAlias {
return true
}
}
return false
}
func structFieldMap(structType reflect.Type) (StructFieldMap, error) {
fieldMap := StructFieldMap{}
renderNameMap := map[string]struct{}{}
for i := 0; i < structType.NumField(); i++ {
field := structType.Field(i)
if isIgnoredStructField(field) {
continue
}
sf := structField(field)
if _, exists := renderNameMap[sf.RenderName]; exists {
return nil, fmt.Errorf("duplicated struct field name %s", sf.RenderName)
}
fieldMap[sf.FieldName] = sf
renderNameMap[sf.RenderName] = struct{}{}
}
return fieldMap, nil
}

1177
vendor/github.com/goccy/go-yaml/token/token.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

13
vendor/github.com/goccy/go-yaml/validate.go generated vendored Normal file
View File

@@ -0,0 +1,13 @@
package yaml
// StructValidator need to implement Struct method only
// ( see https://pkg.go.dev/github.com/go-playground/validator/v10#Validate.Struct )
type StructValidator interface {
Struct(interface{}) error
}
// FieldError need to implement StructField method only
// ( see https://pkg.go.dev/github.com/go-playground/validator/v10#FieldError )
type FieldError interface {
StructField() string
}

357
vendor/github.com/goccy/go-yaml/yaml.go generated vendored Normal file
View File

@@ -0,0 +1,357 @@
package yaml
import (
"bytes"
"context"
"io"
"reflect"
"sync"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/internal/errors"
)
// BytesMarshaler interface may be implemented by types to customize their
// behavior when being marshaled into a YAML document. The returned value
// is marshaled in place of the original value implementing Marshaler.
//
// If an error is returned by MarshalYAML, the marshaling procedure stops
// and returns with the provided error.
type BytesMarshaler interface {
MarshalYAML() ([]byte, error)
}
// BytesMarshalerContext interface use BytesMarshaler with context.Context.
type BytesMarshalerContext interface {
MarshalYAML(context.Context) ([]byte, error)
}
// InterfaceMarshaler interface has MarshalYAML compatible with github.com/go-yaml/yaml package.
type InterfaceMarshaler interface {
MarshalYAML() (interface{}, error)
}
// InterfaceMarshalerContext interface use InterfaceMarshaler with context.Context.
type InterfaceMarshalerContext interface {
MarshalYAML(context.Context) (interface{}, error)
}
// BytesUnmarshaler interface may be implemented by types to customize their
// behavior when being unmarshaled from a YAML document.
type BytesUnmarshaler interface {
UnmarshalYAML([]byte) error
}
// BytesUnmarshalerContext interface use BytesUnmarshaler with context.Context.
type BytesUnmarshalerContext interface {
UnmarshalYAML(context.Context, []byte) error
}
// InterfaceUnmarshaler interface has UnmarshalYAML compatible with github.com/go-yaml/yaml package.
type InterfaceUnmarshaler interface {
UnmarshalYAML(func(interface{}) error) error
}
// InterfaceUnmarshalerContext interface use InterfaceUnmarshaler with context.Context.
type InterfaceUnmarshalerContext interface {
UnmarshalYAML(context.Context, func(interface{}) error) error
}
// NodeUnmarshaler interface is similar to BytesUnmarshaler but provide related AST node instead of raw YAML source.
type NodeUnmarshaler interface {
UnmarshalYAML(ast.Node) error
}
// NodeUnmarshalerContext interface is similar to BytesUnmarshaler but provide related AST node instead of raw YAML source.
type NodeUnmarshalerContext interface {
UnmarshalYAML(context.Context, ast.Node) error
}
// MapItem is an item in a MapSlice.
type MapItem struct {
Key, Value interface{}
}
// MapSlice encodes and decodes as a YAML map.
// The order of keys is preserved when encoding and decoding.
type MapSlice []MapItem
// ToMap convert to map[interface{}]interface{}.
func (s MapSlice) ToMap() map[interface{}]interface{} {
v := map[interface{}]interface{}{}
for _, item := range s {
v[item.Key] = item.Value
}
return v
}
// Marshal serializes the value provided into a YAML document. The structure
// of the generated document will reflect the structure of the value itself.
// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
//
// Struct fields are only marshaled if they are exported (have an upper case
// first letter), and are marshaled using the field name lowercased as the
// default key. Custom keys may be defined via the "yaml" name in the field
// tag: the content preceding the first comma is used as the key, and the
// following comma-separated options are used to tweak the marshaling process.
// Conflicting names result in a runtime error.
//
// The field tag format accepted is:
//
// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
//
// The following flags are currently supported:
//
// omitempty Only include the field if it's not set to the zero
// value for the type or to empty slices or maps.
// Zero valued structs will be omitted if all their public
// fields are zero, unless they implement an IsZero
// method (see the IsZeroer interface type), in which
// case the field will be included if that method returns true.
// Note that this definition is slightly different from the Go's
// encoding/json 'omitempty' definition. It combines some elements
// of 'omitempty' and 'omitzero'. See https://github.com/goccy/go-yaml/issues/695.
//
// omitzero The omitzero tag behaves in the same way as the interpretation of the omitzero tag in the encoding/json library.
// 1) If the field type has an "IsZero() bool" method, that will be used to determine whether the value is zero.
// 2) Otherwise, the value is zero if it is the zero value for its type.
//
// flow Marshal using a flow style (useful for structs,
// sequences and maps).
//
// inline Inline the field, which must be a struct or a map,
// causing all of its fields or keys to be processed as if
// they were part of the outer struct. For maps, keys must
// not conflict with the yaml keys of other struct fields.
//
// anchor Marshal with anchor. If want to define anchor name explicitly, use anchor=name style.
// Otherwise, if used 'anchor' name only, used the field name lowercased as the anchor name
//
// alias Marshal with alias. If want to define alias name explicitly, use alias=name style.
// Otherwise, If omitted alias name and the field type is pointer type,
// assigned anchor name automatically from same pointer address.
//
// In addition, if the key is "-", the field is ignored.
//
// For example:
//
// type T struct {
// F int `yaml:"a,omitempty"`
// B int
// }
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
// yaml.Marshal(&T{F: 1}) // Returns "a: 1\nb: 0\n"
func Marshal(v interface{}) ([]byte, error) {
return MarshalWithOptions(v)
}
// MarshalWithOptions serializes the value provided into a YAML document with EncodeOptions.
func MarshalWithOptions(v interface{}, opts ...EncodeOption) ([]byte, error) {
return MarshalContext(context.Background(), v, opts...)
}
// MarshalContext serializes the value provided into a YAML document with context.Context and EncodeOptions.
func MarshalContext(ctx context.Context, v interface{}, opts ...EncodeOption) ([]byte, error) {
var buf bytes.Buffer
if err := NewEncoder(&buf, opts...).EncodeContext(ctx, v); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// ValueToNode convert from value to ast.Node.
func ValueToNode(v interface{}, opts ...EncodeOption) (ast.Node, error) {
var buf bytes.Buffer
node, err := NewEncoder(&buf, opts...).EncodeToNode(v)
if err != nil {
return nil, err
}
return node, nil
}
// Unmarshal decodes the first document found within the in byte slice
// and assigns decoded values into the out value.
//
// Struct fields are only unmarshalled if they are exported (have an
// upper case first letter), and are unmarshalled using the field name
// lowercased as the default key. Custom keys may be defined via the
// "yaml" name in the field tag: the content preceding the first comma
// is used as the key, and the following comma-separated options are
// used to tweak the marshaling process (see Marshal).
// Conflicting names result in a runtime error.
//
// For example:
//
// type T struct {
// F int `yaml:"a,omitempty"`
// B int
// }
// var t T
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
//
// See the documentation of Marshal for the format of tags and a list of
// supported tag options.
func Unmarshal(data []byte, v interface{}) error {
return UnmarshalWithOptions(data, v)
}
// UnmarshalWithOptions decodes with DecodeOptions the first document found within the in byte slice
// and assigns decoded values into the out value.
func UnmarshalWithOptions(data []byte, v interface{}, opts ...DecodeOption) error {
return UnmarshalContext(context.Background(), data, v, opts...)
}
// UnmarshalContext decodes with context.Context and DecodeOptions.
func UnmarshalContext(ctx context.Context, data []byte, v interface{}, opts ...DecodeOption) error {
dec := NewDecoder(bytes.NewBuffer(data), opts...)
if err := dec.DecodeContext(ctx, v); err != nil {
if err == io.EOF {
return nil
}
return err
}
return nil
}
// NodeToValue converts node to the value pointed to by v.
func NodeToValue(node ast.Node, v interface{}, opts ...DecodeOption) error {
var buf bytes.Buffer
if err := NewDecoder(&buf, opts...).DecodeFromNode(node, v); err != nil {
return err
}
return nil
}
// FormatError is a utility function that takes advantage of the metadata
// stored in the errors returned by this package's parser.
//
// If the second argument `colored` is true, the error message is colorized.
// If the third argument `inclSource` is true, the error message will
// contain snippets of the YAML source that was used.
func FormatError(e error, colored, inclSource bool) string {
var yamlErr Error
if errors.As(e, &yamlErr) {
return yamlErr.FormatError(colored, inclSource)
}
return e.Error()
}
// YAMLToJSON convert YAML bytes to JSON.
func YAMLToJSON(bytes []byte) ([]byte, error) {
var v interface{}
if err := UnmarshalWithOptions(bytes, &v, UseOrderedMap()); err != nil {
return nil, err
}
out, err := MarshalWithOptions(v, JSON())
if err != nil {
return nil, err
}
return out, nil
}
// JSONToYAML convert JSON bytes to YAML.
func JSONToYAML(bytes []byte) ([]byte, error) {
var v interface{}
if err := UnmarshalWithOptions(bytes, &v, UseOrderedMap()); err != nil {
return nil, err
}
out, err := Marshal(v)
if err != nil {
return nil, err
}
return out, nil
}
var (
globalCustomMarshalerMu sync.Mutex
globalCustomUnmarshalerMu sync.Mutex
globalCustomMarshalerMap = map[reflect.Type]func(context.Context, interface{}) ([]byte, error){}
globalCustomUnmarshalerMap = map[reflect.Type]func(context.Context, interface{}, []byte) error{}
)
// RegisterCustomMarshaler overrides any encoding process for the type specified in generics.
// If you want to switch the behavior for each encoder, use `CustomMarshaler` defined as EncodeOption.
//
// NOTE: If type T implements MarshalYAML for pointer receiver, the type specified in RegisterCustomMarshaler must be *T.
// If RegisterCustomMarshaler and CustomMarshaler of EncodeOption are specified for the same type,
// the CustomMarshaler specified in EncodeOption takes precedence.
func RegisterCustomMarshaler[T any](marshaler func(T) ([]byte, error)) {
globalCustomMarshalerMu.Lock()
defer globalCustomMarshalerMu.Unlock()
var typ T
globalCustomMarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}) ([]byte, error) {
return marshaler(v.(T))
}
}
// RegisterCustomMarshalerContext overrides any encoding process for the type specified in generics.
// Similar to RegisterCustomMarshalerContext, but allows passing a context to the unmarshaler function.
func RegisterCustomMarshalerContext[T any](marshaler func(context.Context, T) ([]byte, error)) {
globalCustomMarshalerMu.Lock()
defer globalCustomMarshalerMu.Unlock()
var typ T
globalCustomMarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}) ([]byte, error) {
return marshaler(ctx, v.(T))
}
}
// RegisterCustomUnmarshaler overrides any decoding process for the type specified in generics.
// If you want to switch the behavior for each decoder, use `CustomUnmarshaler` defined as DecodeOption.
//
// NOTE: If RegisterCustomUnmarshaler and CustomUnmarshaler of DecodeOption are specified for the same type,
// the CustomUnmarshaler specified in DecodeOption takes precedence.
func RegisterCustomUnmarshaler[T any](unmarshaler func(*T, []byte) error) {
globalCustomUnmarshalerMu.Lock()
defer globalCustomUnmarshalerMu.Unlock()
var typ *T
globalCustomUnmarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}, b []byte) error {
return unmarshaler(v.(*T), b)
}
}
// RegisterCustomUnmarshalerContext overrides any decoding process for the type specified in generics.
// Similar to RegisterCustomUnmarshalerContext, but allows passing a context to the unmarshaler function.
func RegisterCustomUnmarshalerContext[T any](unmarshaler func(context.Context, *T, []byte) error) {
globalCustomUnmarshalerMu.Lock()
defer globalCustomUnmarshalerMu.Unlock()
var typ *T
globalCustomUnmarshalerMap[reflect.TypeOf(typ)] = func(ctx context.Context, v interface{}, b []byte) error {
return unmarshaler(ctx, v.(*T), b)
}
}
// RawMessage is a raw encoded YAML value. It implements [BytesMarshaler] and
// [BytesUnmarshaler] and can be used to delay YAML decoding or precompute a YAML
// encoding.
// It also implements [json.Marshaler] and [json.Unmarshaler].
//
// This is similar to [json.RawMessage] in the stdlib.
type RawMessage []byte
func (m RawMessage) MarshalYAML() ([]byte, error) {
if m == nil {
return []byte("null"), nil
}
return m, nil
}
func (m *RawMessage) UnmarshalYAML(dt []byte) error {
if m == nil {
return errors.New("yaml.RawMessage: UnmarshalYAML on nil pointer")
}
*m = append((*m)[0:0], dt...)
return nil
}
func (m *RawMessage) UnmarshalJSON(b []byte) error {
return m.UnmarshalYAML(b)
}
func (m RawMessage) MarshalJSON() ([]byte, error) {
return YAMLToJSON(m)
}