chore: migrate to gitea
This commit is contained in:
31
vendor/github.com/goccy/go-yaml/.codecov.yml
generated
vendored
Normal file
31
vendor/github.com/goccy/go-yaml/.codecov.yml
generated
vendored
Normal 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
3
vendor/github.com/goccy/go-yaml/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
bin/
|
||||
.idea/
|
||||
cover.out
|
||||
65
vendor/github.com/goccy/go-yaml/.golangci.yml
generated
vendored
Normal file
65
vendor/github.com/goccy/go-yaml/.golangci.yml
generated
vendored
Normal 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
186
vendor/github.com/goccy/go-yaml/CHANGELOG.md
generated
vendored
Normal 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
21
vendor/github.com/goccy/go-yaml/LICENSE
generated
vendored
Normal 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
55
vendor/github.com/goccy/go-yaml/Makefile
generated
vendored
Normal 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
420
vendor/github.com/goccy/go-yaml/README.md
generated
vendored
Normal file
@@ -0,0 +1,420 @@
|
||||
# YAML support for the Go language
|
||||
|
||||
[](https://pkg.go.dev/github.com/goccy/go-yaml)
|
||||

|
||||
[](https://codecov.io/gh/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
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
37
vendor/github.com/goccy/go-yaml/context.go
generated
vendored
Normal 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
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
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
77
vendor/github.com/goccy/go-yaml/error.go
generated
vendored
Normal 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)
|
||||
}
|
||||
246
vendor/github.com/goccy/go-yaml/internal/errors/error.go
generated
vendored
Normal file
246
vendor/github.com/goccy/go-yaml/internal/errors/error.go
generated
vendored
Normal 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
|
||||
}
|
||||
541
vendor/github.com/goccy/go-yaml/internal/format/format.go
generated
vendored
Normal file
541
vendor/github.com/goccy/go-yaml/internal/format/format.go
generated
vendored
Normal 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
23
vendor/github.com/goccy/go-yaml/lexer/lexer.go
generated
vendored
Normal 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
352
vendor/github.com/goccy/go-yaml/option.go
generated
vendored
Normal 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
28
vendor/github.com/goccy/go-yaml/parser/color.go
generated
vendored
Normal 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
187
vendor/github.com/goccy/go-yaml/parser/context.go
generated
vendored
Normal 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
257
vendor/github.com/goccy/go-yaml/parser/node.go
generated
vendored
Normal 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
12
vendor/github.com/goccy/go-yaml/parser/option.go
generated
vendored
Normal 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
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
746
vendor/github.com/goccy/go-yaml/parser/token.go
generated
vendored
Normal 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
835
vendor/github.com/goccy/go-yaml/path.go
generated
vendored
Normal 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
83
vendor/github.com/goccy/go-yaml/printer/color.go
generated
vendored
Normal 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
353
vendor/github.com/goccy/go-yaml/printer/printer.go
generated
vendored
Normal 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
452
vendor/github.com/goccy/go-yaml/scanner/context.go
generated
vendored
Normal 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
17
vendor/github.com/goccy/go-yaml/scanner/error.go
generated
vendored
Normal 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
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
113
vendor/github.com/goccy/go-yaml/stdlib_quote.go
generated
vendored
Normal 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
128
vendor/github.com/goccy/go-yaml/struct.go
generated
vendored
Normal 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
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
13
vendor/github.com/goccy/go-yaml/validate.go
generated
vendored
Normal 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
357
vendor/github.com/goccy/go-yaml/yaml.go
generated
vendored
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user