all repos

anpi @ 5b7a2874c5409cda15f2140b72607647da2fd06e

yaml to anki importer
5 files changed, 117 insertions(+), 6 deletions(-)
implement parser
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2025-04-29 22:40:12 +0300
Parent: 5b11d15
M go.mod
···
        2
        2
         

      
        3
        3
         go 1.24.2

      
        4
        4
         

      
        5
        
        -require (

      
        6
        
        -	golang.org/x/sync v0.13.0

      
        7
        
        -	gopkg.in/yaml.v3 v3.0.1

      
        8
        
        -)

      
        
        5
        +require gopkg.in/yaml.v3 v3.0.1

      
M go.sum
···
        1
        
        -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=

      
        2
        
        -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=

      
        3
        1
         gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

      
        4
        2
         gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

      
        5
        3
         gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

      
M main.go
···
        1
        1
         package main

      
        2
        2
         

      
        3
        3
         import (

      
        
        4
        +	"fmt"

      
        4
        5
         	"log/slog"

      
        
        6
        +	"os"

      
        5
        7
         

      
        6
        8
         	"github.com/olexsmir/anpi/anki"

      
        
        9
        +	"github.com/olexsmir/anpi/parser"

      
        7
        10
         )

      
        8
        11
         

      
        9
        12
         func main() {

      ···
        17
        20
         

      
        18
        21
         	fieldsErr, err := anki.GetModelFieldNames("chicked jokey")

      
        19
        22
         	slog.Info("test non-existent type", "fields", fieldsErr, "err", err)

      
        
        23
        +

      
        
        24
        +	f, _ := os.ReadFile("test.yml")

      
        
        25
        +	data, err := parser.Parse(f)

      
        
        26
        +	slog.Info("parsing data", "err", err)

      
        
        27
        +

      
        
        28
        +	for _, deck := range data {

      
        
        29
        +		fmt.Printf("\nDeck: %s\n", deck.Deck)

      
        
        30
        +		fmt.Printf("Type: %s\n", deck.Type)

      
        
        31
        +		fmt.Printf("Global Tags: %v\n", deck.Tags)

      
        
        32
        +		fmt.Println("Fields mapping:")

      
        
        33
        +		for internalName, anki := range deck.Fields {

      
        
        34
        +			fmt.Printf("  %s -> %s\n", internalName, anki)

      
        
        35
        +		}

      
        
        36
        +

      
        
        37
        +		fmt.Println("Notes:")

      
        
        38
        +		for _, note := range deck.Notes {

      
        
        39
        +			fmt.Println("  Note fields:")

      
        
        40
        +			for internalName, value := range note.Fields {

      
        
        41
        +				fmt.Printf("    %s: %s\n", internalName, value)

      
        
        42
        +			}

      
        
        43
        +			if len(note.Tags) > 0 {

      
        
        44
        +				fmt.Printf("    Local Tags: %v\n", note.Tags)

      
        
        45
        +			}

      
        
        46
        +		}

      
        
        47
        +	}

      
        20
        48
         }

      
A parser/parser.go
···
        
        1
        +package parser

      
        
        2
        +

      
        
        3
        +import (

      
        
        4
        +	"fmt"

      
        
        5
        +

      
        
        6
        +	"gopkg.in/yaml.v3"

      
        
        7
        +)

      
        
        8
        +

      
        
        9
        +type DeckImport struct {

      
        
        10
        +	Deck   string            `yaml:"deck"`

      
        
        11
        +	Type   string            `yaml:"type"`

      
        
        12
        +	Tags   []string          `yaml:"tags"`

      
        
        13
        +	Fields map[string]string `yaml:"fields"`

      
        
        14
        +	Notes  []Note            `yaml:"notes"`

      
        
        15
        +}

      
        
        16
        +

      
        
        17
        +type Note struct {

      
        
        18
        +	Fields map[string]string

      
        
        19
        +	Tags   []string

      
        
        20
        +}

      
        
        21
        +

      
        
        22
        +func (n *Note) UnmarshalYAML(value *yaml.Node) error {

      
        
        23
        +	var raw map[string]any

      
        
        24
        +	if err := value.Decode(&raw); err != nil {

      
        
        25
        +		return err

      
        
        26
        +	}

      
        
        27
        +

      
        
        28
        +	n.Fields = make(map[string]string)

      
        
        29
        +	for k, v := range raw {

      
        
        30
        +		if k == "tags" {

      
        
        31
        +			if tags, ok := v.([]string); ok {

      
        
        32
        +				n.Tags = append(n.Tags, tags...)

      
        
        33
        +			}

      
        
        34
        +		}

      
        
        35
        +

      
        
        36
        +		if str, ok := v.(string); ok {

      
        
        37
        +			n.Fields[k] = str

      
        
        38
        +		}

      
        
        39
        +	}

      
        
        40
        +

      
        
        41
        +	return nil

      
        
        42
        +}

      
        
        43
        +

      
        
        44
        +func (d *DeckImport) Validate() error {

      
        
        45
        +	return nil

      
        
        46
        +}

      
        
        47
        +

      
        
        48
        +func Parse(inp []byte) ([]DeckImport, error) {

      
        
        49
        +	var listRes []DeckImport

      
        
        50
        +	if err := yaml.Unmarshal(inp, &listRes); err == nil {

      
        
        51
        +		return listRes, nil

      
        
        52
        +	}

      
        
        53
        +

      
        
        54
        +	var single DeckImport

      
        
        55
        +	if err := yaml.Unmarshal(inp, &single); err == nil {

      
        
        56
        +		return []DeckImport{single}, nil

      
        
        57
        +	}

      
        
        58
        +

      
        
        59
        +	return nil, fmt.Errorf("invalid file format")

      
        
        60
        +}

      
A test.yml
···
        
        1
        +---

      
        
        2
        +- deck: English

      
        
        3
        +  type: Basic

      
        
        4
        +  fields:

      
        
        5
        +    front: Front

      
        
        6
        +    back: Back

      
        
        7
        +    extra: Extra

      
        
        8
        +  notes:

      
        
        9
        +    - front: The question? asdf asdf

      
        
        10
        +      back: The answer

      
        
        11
        +      extra: Some extra stuff, maybe an explanation

      
        
        12
        +    - front: Some more questions?

      
        
        13
        +      back: Even some more answers

      
        
        14
        +      tags: [english::strange, dck]

      
        
        15
        +- deck: toki pona

      
        
        16
        +  type: Vocab sentence

      
        
        17
        +  fields:

      
        
        18
        +    front: Sentence

      
        
        19
        +    trans: Translatation

      
        
        20
        +    extra: Extra

      
        
        21
        +  notes:

      
        
        22
        +    - front: sina pona ala pona?

      
        
        23
        +      trans: o kokosila ala!

      
        
        24
        +    - front: "how to poop?"

      
        
        25
        +      trans: sina sona ala sone e ni

      
        
        26
        +      extra: jaki. ni li jaki.

      
        
        27
        +      tags: [tokipona:grammar]

      
        
        28
        +---