summaryrefslogtreecommitdiff
path: root/internal/draft
diff refs
from: back
to: back
| flip
diff options
context:
space:
mode:
Diffstat (limited to 'internal/draft')
-rw-r--r--internal/draft/parser.go179
-rw-r--r--internal/draft/parser_test.go83
2 files changed, 0 insertions, 262 deletions
diff --git a/internal/draft/parser.go b/internal/draft/parser.go
deleted file mode 100644
index 2761c87..0000000
--- a/internal/draft/parser.go
+++ /dev/null
@@ -1,179 +0,0 @@
-package draft
-
-import (
- "regexp"
- "strings"
-
- "github.com/SayaAndy/saya-today-article-metadata-add/internal/frontmatter"
-)
-
-// layoutTokenRe matches gallery layout hints like "2x", "3x" that are
-// meaningful only to the sayauz renderer and must be dropped elsewhere.
-var layoutTokenRe = regexp.MustCompile(`^\d+x$`)
-
-type BlockKind int
-
-const (
- TextBlock BlockKind = iota
- GalleryBlock
-)
-
-// Block is one ordered piece of a section: either a run of markdown text or a
-// gallery. Exactly one of Text / Gallery is meaningful depending on Kind.
-type Block struct {
- Kind BlockKind
- Text string
- Gallery *Gallery
-}
-
-type Gallery struct {
- Timezone string
- KeyPrefix string
- Photos []Photo
-}
-
-type Photo struct {
- Key string // KeyPrefix + filename, e.g. "Sevsk/20241008-093833.jpg"
- Caption string
-}
-
-// Section is the content between two "..." separator lines, split into ordered
-// text and gallery blocks.
-type Section struct {
- Index int
- Blocks []Block
-}
-
-type Document struct {
- SourcePath string
- Codename string
- Metadata *frontmatter.Metadata
- RawContent []byte
- Body string
- Sections []Section
-}
-
-// ParseDraft parses a draft file: frontmatter metadata, the markdown body, and
-// the body split into sections (on "..." lines) of ordered text/gallery blocks.
-func ParseDraft(sourcePath, codename string, content []byte) (*Document, error) {
- metadata, body, err := frontmatter.ParseFrontmatter(content)
- if err != nil {
- return nil, err
- }
-
- doc := &Document{
- SourcePath: sourcePath,
- Codename: codename,
- Metadata: metadata,
- RawContent: content,
- Body: string(body),
- }
- doc.Sections = splitSections(doc.Body)
-
- return doc, nil
-}
-
-func splitSections(body string) []Section {
- lines := strings.Split(body, "\n")
-
- var sections []Section
- var chunk []string
-
- flush := func() {
- blocks := parseBlocks(chunk)
- chunk = nil
- if len(blocks) == 0 {
- return
- }
- sections = append(sections, Section{Index: len(sections), Blocks: blocks})
- }
-
- for _, line := range lines {
- if strings.TrimSpace(line) == "..." {
- flush()
- continue
- }
- chunk = append(chunk, line)
- }
- flush()
-
- return sections
-}
-
-func parseBlocks(lines []string) []Block {
- var blocks []Block
- var text []string
-
- flushText := func() {
- joined := strings.TrimSpace(strings.Join(text, "\n"))
- text = nil
- if joined != "" {
- blocks = append(blocks, Block{Kind: TextBlock, Text: joined})
- }
- }
-
- for i := 0; i < len(lines); i++ {
- trimmed := strings.TrimSpace(lines[i])
- if strings.HasPrefix(trimmed, "{Gallery:") {
- flushText()
- gallery, next := parseGallery(lines, i)
- if gallery != nil {
- blocks = append(blocks, Block{Kind: GalleryBlock, Gallery: gallery})
- }
- i = next
- continue
- }
- text = append(text, lines[i])
- }
- flushText()
-
- return blocks
-}
-
-// parseGallery reads a {Gallery:...} block starting at lines[start] and returns
-// the parsed gallery plus the index of the closing {/Gallery} line (or the last
-// consumed line if unterminated).
-func parseGallery(lines []string, start int) (*Gallery, int) {
- header := strings.TrimSpace(lines[start])
- header = strings.TrimPrefix(header, "{Gallery:")
- header = strings.TrimSuffix(header, "}")
- tz, keyPrefix, _ := strings.Cut(header, ":")
-
- gallery := &Gallery{Timezone: tz, KeyPrefix: keyPrefix}
-
- i := start + 1
- for ; i < len(lines); i++ {
- trimmed := strings.TrimSpace(lines[i])
- if trimmed == "{/Gallery}" {
- break
- }
- if trimmed == "" {
- continue
- }
- gallery.Photos = append(gallery.Photos, parsePhoto(keyPrefix, trimmed))
- }
-
- return gallery, i
-}
-
-func parsePhoto(keyPrefix, line string) Photo {
- parts := strings.Split(line, "|")
- for i := range parts {
- parts[i] = strings.TrimSpace(parts[i])
- }
-
- filename := parts[0]
-
- var captionParts []string
- for _, p := range parts[1:] {
- if p == "" || layoutTokenRe.MatchString(p) {
- continue
- }
- captionParts = append(captionParts, p)
- }
-
- return Photo{
- Key: keyPrefix + filename,
- Caption: strings.Join(captionParts, " "),
- }
-}
diff --git a/internal/draft/parser_test.go b/internal/draft/parser_test.go
deleted file mode 100644
index c6d454d..0000000
--- a/internal/draft/parser_test.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package draft
-
-import (
- "os"
- "strings"
- "testing"
-)
-
-func TestParseDraftSevsk(t *testing.T) {
- raw, err := os.ReadFile("../../.draft/sevsk.md.draft")
- if err != nil {
- t.Fatal(err)
- }
-
- doc, err := ParseDraft("../../.draft/sevsk.md.draft", "sevsk", raw)
- if err != nil {
- t.Fatal(err)
- }
- if doc.Metadata == nil || doc.Metadata.Title == "" {
- t.Fatal("expected frontmatter metadata")
- }
-
- var galleries int
- for _, section := range doc.Sections {
- for _, block := range section.Blocks {
- if block.Kind != GalleryBlock {
- continue
- }
- galleries++
- for _, p := range block.Gallery.Photos {
- if !strings.HasPrefix(p.Key, "Sevsk/20241008-") {
- t.Errorf("unexpected photo key %q", p.Key)
- }
- if strings.Contains(p.Caption, "2x") {
- t.Errorf("layout token leaked into caption %q", p.Caption)
- }
- }
- }
- }
- if galleries == 0 {
- t.Fatal("expected at least one gallery")
- }
-
- // First gallery: 4 photos, captions on photos 1 and 3, none on 2; photo 4 had "2x |" => empty caption.
- first := firstGallery(doc)
- if first == nil || len(first.Photos) != 4 {
- t.Fatalf("first gallery: want 4 photos, got %v", first)
- }
- if first.Timezone != "Europe/Moscow" {
- t.Errorf("first gallery tz = %q", first.Timezone)
- }
- if first.Photos[0].Caption != "Никольская церковь. Действующая" {
- t.Errorf("photo[0] caption = %q", first.Photos[0].Caption)
- }
- if first.Photos[1].Caption != "" {
- t.Errorf("photo[1] caption = %q, want empty", first.Photos[1].Caption)
- }
- if first.Photos[3].Caption != "" {
- t.Errorf("photo[3] caption = %q, want empty (only 2x token)", first.Photos[3].Caption)
- }
- if first.Photos[3].Key != "Sevsk/20241008-094036.jpg" {
- t.Errorf("photo[3] key = %q", first.Photos[3].Key)
- }
-}
-
-func firstGallery(doc *Document) *Gallery {
- for _, section := range doc.Sections {
- for _, block := range section.Blocks {
- if block.Kind == GalleryBlock {
- return block.Gallery
- }
- }
- }
- return nil
-}
-
-func TestSplitSectionsSeparator(t *testing.T) {
- body := "intro\n...\nmiddle\n...\nend"
- sections := splitSections(body)
- if len(sections) != 3 {
- t.Fatalf("want 3 sections, got %d", len(sections))
- }
-}