Skip to content

Commit

Permalink
refactor: task lint
Browse files Browse the repository at this point in the history
  • Loading branch information
xbpk3t committed Dec 29, 2024
1 parent 9134f06 commit 0fd727d
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 176 deletions.
66 changes: 43 additions & 23 deletions pkg/parser/parser.go
Original file line number Diff line number Diff line change
@@ -1,52 +1,72 @@
package parser

import (
"os"
"bytes"
"errors"
"fmt"
"io"

"github.com/xbpk3t/docs-alfred/pkg/errcode"
"gopkg.in/yaml.v3"
)

// Parser YAML解析器
// Parser YAML配置解析器
type Parser[T any] struct {
data []byte
}

// NewParser 创建新的解析器
// NewParser 创建解析器
func NewParser[T any](data []byte) *Parser[T] {
return &Parser[T]{
data: data,
}
}

// ParseSingle 解析单个配置
// ParseSingle 解析单个YAML文档
func (p *Parser[T]) ParseSingle() (T, error) {
var result T
if err := yaml.Unmarshal(p.data, &result); err != nil {
return result, errcode.WithError(errcode.ErrParseConfig, err)
decoder := yaml.NewDecoder(bytes.NewReader(p.data))
if err := decoder.Decode(&result); err != nil {
return result, fmt.Errorf("解析配置失败: %w", err)
}
return result, nil
}

// ParseFlatten 解析并展平配置
func (p *Parser[T]) ParseFlatten() ([]T, error) {
var result []T
if err := yaml.Unmarshal(p.data, &result); err != nil {
return nil, errcode.WithError(errcode.ErrParseConfig, err)
// ParseMulti 解析多文档 YAML
func (p *Parser[T]) ParseMulti() ([]T, error) {
var results []T
decoder := yaml.NewDecoder(bytes.NewReader(p.data))

for {
var item T
err := decoder.Decode(&item)
if err == io.EOF {
break
}
if err != nil {
return nil, fmt.Errorf("解析配置失败: %w", err)
}
results = append(results, item)
}
return result, nil
return results, nil
}

// ParseFromFile 从文件解析
func (p *Parser[T]) ParseFromFile(file string) ([]T, error) {
data, err := os.ReadFile(file)
if err != nil {
return nil, errcode.WithError(errcode.ErrReadFile, err)
}
// ParseFlatten 解析多文档 YAML 并展开结果
// 适用于每个文档都是 slice 且需要合并的情况
func (p *Parser[T]) ParseFlatten() ([]T, error) {
var results []T
decoder := yaml.NewDecoder(bytes.NewReader(p.data))

var result []T
if err := yaml.Unmarshal(data, &result); err != nil {
return nil, errcode.WithError(errcode.ErrParseConfig, err)
for {
var item []T
err := decoder.Decode(&item)
if errors.Is(err, io.EOF) {
break
}
if err != nil {
return nil, fmt.Errorf("解析配置失败: %w", err)
}
results = append(results, item...)
}
return result, nil

return results, nil
}
4 changes: 2 additions & 2 deletions pkg/rss/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ type Feeds struct {
Feed string `yaml:"feed"`
}

// LoadConfig 加载配置文件
func LoadConfig(configFile string) (*Config, error) {
// NewConfig 加载配置文件
func NewConfig(configFile string) (*Config, error) {
data, err := os.ReadFile(configFile)
if err != nil {
return nil, errcode.WithError(errcode.ErrReadConfig, err)
Expand Down
144 changes: 74 additions & 70 deletions service/gh/merger.go
Original file line number Diff line number Diff line change
@@ -1,122 +1,126 @@
package gh

import (
"bytes"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"

"github.com/xbpk3t/docs-alfred/pkg/errcode"
"gopkg.in/yaml.v3"
)

// Merger 配置合并器
type Merger struct {
inputFiles []string
outputFile string
outputDir string
tagProvider func(string) string
type ConfigMerger struct {
options MergeOptions
}

// NewMerger 创建新的合并器
func NewMerger(inputFiles []string, outputFile, outputDir string, tagProvider func(string) string) *Merger {
return &Merger{
inputFiles: inputFiles,
outputFile: outputFile,
outputDir: outputDir,
tagProvider: tagProvider,
}
func NewConfigMerger(opts MergeOptions) *ConfigMerger {
return &ConfigMerger{options: opts}
}

// Merge 执行合并
func (m *Merger) Merge() error {
// Merge
func (m *ConfigMerger) Merge() error {
if err := m.validateInput(); err != nil {
return errcode.WithError(errcode.ErrValidateInput, err)
return fmt.Errorf("验证输入失败: %w", err)
}

result, err := m.mergeConfigs()
config, err := m.mergeConfigs()
if err != nil {
return errcode.WithError(errcode.ErrMergeConfig, err)
return fmt.Errorf("合并配置失败: %w", err)
}

return m.writeResult(result)
return m.writeResult(config)
}

// validateInput 验证输入
func (m *Merger) validateInput() error {
if len(m.inputFiles) == 0 {
return errcode.ErrInvalidInput
func (m *ConfigMerger) validateInput() error {
if m.options.FolderPath == "" {
return fmt.Errorf("文件夹路径不能为空")
}
if len(m.options.FileNames) == 0 {
return fmt.Errorf("文件列表不能为空")
}
if m.options.OutputPath == "" {
return fmt.Errorf("输出路径不能为空")
}
return nil
}

// mergeConfigs 合并配置
func (m *Merger) mergeConfigs() (interface{}, error) {
var result interface{}
for _, file := range m.inputFiles {
config, err := m.processFile(file)
// mergeConfigs
func (m *ConfigMerger) mergeConfigs() (ConfigRepos, error) {
var mergedConfig ConfigRepos

for _, fileName := range m.options.FileNames {
config, err := m.processFile(fileName)
if err != nil {
return nil, errcode.WithError(errcode.ErrFileProcess, err)
return nil, fmt.Errorf("处理文件 %s 失败: %w", fileName, err)
}
result = m.merge(result, config)
mergedConfig = append(mergedConfig, config...)
}
return result, nil

return mergedConfig, nil
}

// processFile 处理单个文件
func (m *Merger) processFile(fileName string) (interface{}, error) {
data, err := os.ReadFile(fileName)
func (m *ConfigMerger) processFile(fileName string) (ConfigRepos, error) {
content, err := m.readFile(fileName)
if err != nil {
return nil, errcode.WithError(errcode.ErrReadFile, err)
return nil, err
}

var config interface{}
if err := yaml.Unmarshal(data, &config); err != nil {
return nil, errcode.WithError(errcode.ErrParseYAML, err)
}

if m.tagProvider != nil {
if err := m.setTag(config, m.tagProvider(fileName)); err != nil {
return nil, errcode.WithError(errcode.ErrSetTag, err)
}
}
tag := strings.TrimSuffix(fileName, ".yml")
rc := NewConfigRepos(content)
// rc, err := parser.NewParser[ConfigRepos](content).ParseFlatten()
// if err != nil {
// return nil, fmt.Errorf("解析YAML失败: %w", err)
// }

return config, nil
return rc.WithTag(tag), nil
}

// writeResult 写入结果
func (m *Merger) writeResult(result interface{}) error {
if m.outputDir != "" {
if err := os.MkdirAll(m.outputDir, 0755); err != nil {
return errcode.WithError(errcode.ErrCreateDir, err)
}
func (m *ConfigMerger) readFile(fileName string) ([]byte, error) {
filePath := filepath.Join(m.options.FolderPath, fileName)
content, err := os.ReadFile(filePath)
if err != nil {
return nil, fmt.Errorf("读取文件失败: %w", err)
}
return content, nil
}

file, err := os.Create(filepath.Join(m.outputDir, m.outputFile))
func (m *ConfigMerger) writeResult(config ConfigRepos) error {
file, err := os.Create(m.options.OutputPath)
if err != nil {
return errcode.WithError(errcode.ErrCreateFile, err)
return fmt.Errorf("创建输出文件失败: %w", err)
}
defer file.Close()

encoder := yaml.NewEncoder(file)
defer encoder.Close()

if err := encoder.Encode(result); err != nil {
return errcode.WithError(errcode.ErrEncodeYAML, err)
if err := encoder.Encode(config); err != nil {
return fmt.Errorf("编码YAML失败: %w", err)
}

return nil
}

// merge 合并两个配置
func (m *Merger) merge(a, b interface{}) interface{} {
if a == nil {
return b
}
// 实现合并逻辑
return b
}
func NewConfigRepos(f []byte) ConfigRepos {
var ghs ConfigRepos

d := yaml.NewDecoder(bytes.NewReader(f))
for {
// create new spec here
spec := new(ConfigRepos)
// pass a reference to spec reference
if err := d.Decode(&spec); err != nil {
// break the loop in case of EOF
if errors.Is(err, io.EOF) {
break
}
panic(err)
}

// setTag 设置标签
func (m *Merger) setTag(config interface{}, tag string) error {
// 实现设置标签逻辑
return nil
ghs = append(ghs, *spec...)
}
return ghs
}
81 changes: 0 additions & 81 deletions service/works/works_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,91 +4,10 @@ import (
"os"
"testing"

"github.com/xbpk3t/docs-alfred/pkg/parser"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestParseConfig(t *testing.T) {
tests := []struct {
name string
input string
want Docs
wantErr bool
}{
{
name: "基础配置解析",
input: `
- type: "类型1"
tag: "标签1"
qs:
- q: "问题1"
x: "答案1"
- q: "问题2"
x: "答案2"
u: "http://example.com"`,
want: Docs{
{
Type: "类型1",
Tag: "标签1",
Qs: []QA{
{Question: "问题1", Answer: "答案1"},
{Question: "问题2", Answer: "答案2", URL: "http://example.com"},
},
},
},
wantErr: false,
},
{
name: "带子问题和图片的配置",
input: `
- type: "类型2"
tag: "标签2"
qs:
- q: "主问题"
x: "主答案"
s: ["子问题1", "子问题2"]
p: ["image1.jpg", "image2.jpg"]`,
want: Docs{
{
Type: "类型2",
Tag: "标签2",
Qs: []QA{
{
Question: "主问题",
Answer: "主答案",
SubQuestions: []string{"子问题1", "子问题2"},
Pictures: []string{"image1.jpg", "image2.jpg"},
},
},
},
},
wantErr: false,
},
{
name: "无效的YAML",
input: `invalid: yaml: [`,
want: nil,
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parser.NewParser[Docs]([]byte(tt.input)).ParseMulti()
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
for _, docs := range got {
assert.Equal(t, tt.want, docs)
}
})
}
}

func TestQA_Render(t *testing.T) {
tests := []struct {
name string
Expand Down

0 comments on commit 0fd727d

Please sign in to comment.