feat: refactor some shit
This commit is contained in:
98
parser/blocks/blocks.go
Normal file
98
parser/blocks/blocks.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TemplateType represents whether a template is short, long, or invalid.
|
||||
type TemplateType int
|
||||
|
||||
const (
|
||||
InvalidTemplate TemplateType = iota
|
||||
ShortTemplate
|
||||
LongTemplate
|
||||
)
|
||||
|
||||
// DetectTemplateType checks if the template is short or long.
|
||||
func DetectTemplateType(tmpl string) TemplateType {
|
||||
trimmed := strings.TrimSpace(tmpl)
|
||||
|
||||
// Short type: starts with "{" and ends with "}" on a single line,
|
||||
// and contains "|" or "," inside for inline definition
|
||||
// Matchs for example { name | text,required }
|
||||
if strings.HasPrefix(trimmed, "{") &&
|
||||
strings.HasSuffix(trimmed, "}") &&
|
||||
!strings.Contains(trimmed, "\n") {
|
||||
return ShortTemplate
|
||||
}
|
||||
|
||||
// Long type: multiline and contains keys like "path:" or "codec:" inside
|
||||
// Matches for example:
|
||||
// {
|
||||
// path: name
|
||||
// codec: text
|
||||
// required: true
|
||||
// }
|
||||
if strings.Contains(trimmed, "\n") &&
|
||||
(strings.Contains(trimmed, "path:") || strings.Contains(trimmed, "codec:")) {
|
||||
return LongTemplate
|
||||
}
|
||||
|
||||
return InvalidTemplate
|
||||
}
|
||||
|
||||
// CodecType represents the type of codec used to encode/render a value
|
||||
type CodecType string
|
||||
|
||||
const (
|
||||
CodecText CodecType = "text"
|
||||
CodecNumber CodecType = "number"
|
||||
CodecYaml CodecType = "yaml"
|
||||
CodecList CodecType = "list"
|
||||
)
|
||||
|
||||
func parseCodecType(input string) (CodecType, error) {
|
||||
switch input {
|
||||
case "number":
|
||||
return CodecNumber, nil
|
||||
case "yaml":
|
||||
return CodecYaml, nil
|
||||
case "list":
|
||||
return CodecList, nil
|
||||
case "text":
|
||||
return CodecText, nil
|
||||
}
|
||||
return CodecText, fmt.Errorf("unknown codec: '%s'", input)
|
||||
}
|
||||
|
||||
type BlockType string
|
||||
|
||||
const (
|
||||
DataBlock BlockType = "data" // content between lines "{" and "}"
|
||||
MatchingBlock BlockType = "matching" // everything outside data blocks
|
||||
)
|
||||
|
||||
type TemplateBlock struct {
|
||||
Type BlockType
|
||||
Path string
|
||||
Codec CodecType
|
||||
Required bool
|
||||
content string
|
||||
}
|
||||
|
||||
func (b TemplateBlock) GetContent() string {
|
||||
return b.content
|
||||
}
|
||||
|
||||
func (p *TemplateBlock) Parse(input string) (key string, value any, err error) {
|
||||
switch p.Codec {
|
||||
case CodecText:
|
||||
return p.Path, input, nil
|
||||
case CodecYaml:
|
||||
return p.ParseYamlBlock(input)
|
||||
case CodecList:
|
||||
return p.ParseListBlock(input)
|
||||
}
|
||||
return p.Path, "", nil
|
||||
}
|
10
parser/blocks/list_block.go
Normal file
10
parser/blocks/list_block.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package blocks
|
||||
|
||||
import "fmt"
|
||||
|
||||
func (b TemplateBlock) ParseListBlock(input string) (key string, value any, error error) {
|
||||
|
||||
fmt.Printf("Parsing List: '%q'", input)
|
||||
|
||||
return "", nil, nil
|
||||
}
|
118
parser/blocks/template.go
Normal file
118
parser/blocks/template.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"go.yaml.in/yaml/v4"
|
||||
)
|
||||
|
||||
func cleanTemplate(input string) string {
|
||||
s := strings.TrimSpace(input)
|
||||
s = strings.TrimPrefix(s, "{")
|
||||
s = strings.TrimSuffix(s, "}")
|
||||
return s
|
||||
}
|
||||
|
||||
func parseShortTemplate(input string) (TemplateBlock, error) {
|
||||
|
||||
var split = strings.Split(cleanTemplate(input), "|")
|
||||
if len(split) < 1 {
|
||||
return TemplateBlock{}, fmt.Errorf("Invalid Short Template")
|
||||
}
|
||||
|
||||
block := TemplateBlock{
|
||||
Type: DataBlock,
|
||||
Path: strings.TrimSpace(split[0]),
|
||||
Codec: CodecText,
|
||||
content: input,
|
||||
}
|
||||
|
||||
if len(split) > 1 {
|
||||
var optionSplit = strings.Split(split[1], ",")
|
||||
for _, option := range optionSplit {
|
||||
switch strings.TrimSpace(option) {
|
||||
case "required":
|
||||
block.Required = true
|
||||
case "number":
|
||||
block.Codec = CodecNumber
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return block, nil
|
||||
}
|
||||
|
||||
type yamlBlock struct {
|
||||
Path string `yaml:"path"`
|
||||
Codec string `yaml:"codec"`
|
||||
Required bool `yaml:"required,omitempty"`
|
||||
Fields []yamlField `yaml:"fields"`
|
||||
Item *struct {
|
||||
Template string `yaml:"template,omitempty"`
|
||||
} `yaml:"item,omitempty"`
|
||||
Template string `yaml:"template,omitempty"`
|
||||
}
|
||||
|
||||
type yamlField struct {
|
||||
Path string `yaml:"path"`
|
||||
Value any `yaml:"value,omitempty"`
|
||||
Codec string `yaml:"codec"`
|
||||
Required bool `yaml:"required"`
|
||||
}
|
||||
|
||||
func parseYamlTemplate(input string) (block TemplateBlock, err error) {
|
||||
|
||||
var blk yamlBlock
|
||||
|
||||
cleaned := cleanTemplate(input)
|
||||
|
||||
dec := yaml.NewDecoder(strings.NewReader(cleaned))
|
||||
dec.KnownFields(true)
|
||||
|
||||
if err := dec.Decode(&blk); err != nil {
|
||||
fmt.Printf("Failed to parse:\n---\n%s\n---\n", cleaned)
|
||||
return block, err
|
||||
}
|
||||
|
||||
if blk.Path == "" {
|
||||
return block, fmt.Errorf("missing top-level 'path'")
|
||||
}
|
||||
|
||||
codec, err := parseCodecType(blk.Codec)
|
||||
if err != nil {
|
||||
return block, fmt.Errorf("failed to parse codec: %w", err)
|
||||
}
|
||||
|
||||
return TemplateBlock{
|
||||
Type: DataBlock,
|
||||
Path: blk.Path,
|
||||
Codec: codec,
|
||||
content: input,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func ParseTemplateBlock(template string, blockType BlockType) (block TemplateBlock, err error) {
|
||||
|
||||
if blockType == MatchingBlock {
|
||||
return TemplateBlock{
|
||||
Type: MatchingBlock,
|
||||
content: template,
|
||||
}, nil
|
||||
}
|
||||
|
||||
block.Type = DataBlock
|
||||
block.content = template
|
||||
|
||||
templateType := DetectTemplateType(template)
|
||||
if templateType == InvalidTemplate {
|
||||
return block, fmt.Errorf("Invalid Template")
|
||||
}
|
||||
|
||||
if templateType == ShortTemplate {
|
||||
return parseShortTemplate(template)
|
||||
}
|
||||
|
||||
return parseYamlTemplate(template)
|
||||
}
|
18
parser/blocks/yaml_block.go
Normal file
18
parser/blocks/yaml_block.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go.yaml.in/yaml/v4"
|
||||
)
|
||||
|
||||
func (b TemplateBlock) ParseYamlBlock(input string) (key string, value any, error error) {
|
||||
|
||||
res := make(map[string]any)
|
||||
err := yaml.Unmarshal([]byte(input), &res)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to parse yaml: %w", err)
|
||||
}
|
||||
|
||||
return "", nil, nil
|
||||
}
|
Reference in New Issue
Block a user