commit e03b0d49f716e556026620fc9e5035e3b2770d4e
parent 395e3be2c1fa6dd5b85c4f91f3d4c645ea6724ad
Author: yuin <yuin@inforno.net>
Date: Sat, 12 Feb 2022 19:42:33 +0900
Add WithStoresInDocument option
Diffstat:
M | README.md | | | 35 | +++++++++++++++++++++++++++++++++++ |
M | go.mod | | | 4 | ++-- |
M | go.sum | | | 8 | ++------ |
M | meta.go | | | 162 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------- |
M | meta_test.go | | | 43 | +++++++++++++++++++++++++++++++++++++++++++ |
5 files changed, 199 insertions(+), 53 deletions(-)
diff --git a/README.md b/README.md
@@ -88,6 +88,41 @@ Tags:
}
```
+Or `WithStoresInDocument` option:
+
+```go
+import (
+ "bytes"
+ "fmt"
+ "github.com/yuin/goldmark"
+ "github.com/yuin/goldmark/extension"
+ "github.com/yuin/goldmark/parser"
+ "github.com/yuin/goldmark-meta"
+)
+
+func main() {
+ markdown := goldmark.New(
+ goldmark.WithExtensions(
+ meta.New(
+ meta.WithStoresInDocument(),
+ ),
+ ),
+ )
+ source := `---
+Title: goldmark-meta
+Summary: Add YAML metadata to the document
+Tags:
+ - markdown
+ - goldmark
+---
+`
+
+ document := markdown.Parser().Parse(text.NewReader([]byte(source)))
+ metaData := document.OwnerDocument().Meta()
+ title := metaData["Title"]
+ fmt.Print(title)
+```
+
### Render the metadata as a table
You need to add `extension.TableHTMLRenderer` or the `Table` extension to
diff --git a/go.mod b/go.mod
@@ -1,8 +1,8 @@
module github.com/yuin/goldmark-meta
-go 1.15
+go 1.17
require (
- github.com/yuin/goldmark v1.2.1
+ github.com/yuin/goldmark v1.4.6
gopkg.in/yaml.v2 v2.3.0
)
diff --git a/go.sum b/go.sum
@@ -1,10 +1,6 @@
-github.com/yuin/goldmark v1.1.7 h1:XiwWADvxJeIM1JbXqthrEhDc19hTMui+o+QaY1hGXlk=
-github.com/yuin/goldmark v1.1.7/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.4.6 h1:EQ1OkiNq/eMbQxs/2O/A8VDIHERXGH14s19ednd4XIw=
+github.com/yuin/goldmark v1.4.6/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/meta.go b/meta.go
@@ -27,6 +27,11 @@ type data struct {
var contextKey = parser.NewContextKey()
+// Option interface sets options for this extension.
+type Option interface {
+ metaOption()
+}
+
// Get returns a YAML metadata.
func Get(pc parser.Context) map[string]interface{} {
v := pc.Get(contextKey)
@@ -80,11 +85,11 @@ func TryGetItems(pc parser.Context) (yaml.MapSlice, error) {
type metaParser struct {
}
-var defaultMetaParser = &metaParser{}
+var defaultParser = &metaParser{}
// NewParser returns a BlockParser that can parse YAML metadata blocks.
func NewParser() parser.BlockParser {
- return defaultMetaParser
+ return defaultParser
}
func isSeparator(line []byte) bool {
@@ -162,9 +167,74 @@ func (b *metaParser) CanAcceptIndentedLine() bool {
}
type astTransformer struct {
+ transformerConfig
+}
+
+type transformerConfig struct {
+ // Renders metadata as an html table.
+ Table bool
+
+ // Stores metadata in ast.Document.Meta().
+ StoresInDocument bool
+}
+
+type transformerOption interface {
+ Option
+
+ // SetMetaOption sets options for the metadata parser.
+ SetMetaOption(*transformerConfig)
+}
+
+var _ transformerOption = &withTable{}
+
+type withTable struct {
+ value bool
+}
+
+func (o *withTable) metaOption() {}
+
+func (o *withTable) SetMetaOption(m *transformerConfig) {
+ m.Table = o.value
+}
+
+// WithTable is a functional option that renders a YAML metadata as a table.
+func WithTable() Option {
+ return &withTable{
+ value: true,
+ }
+}
+
+var _ transformerOption = &withStoresInDocument{}
+
+type withStoresInDocument struct {
+ value bool
+}
+
+func (o *withStoresInDocument) metaOption() {}
+
+func (o *withStoresInDocument) SetMetaOption(c *transformerConfig) {
+ c.StoresInDocument = o.value
}
-var defaultASTTransformer = &astTransformer{}
+// WithStoresInDocument is a functional option that parser will store YAML meta in ast.Document.Meta().
+func WithStoresInDocument() Option {
+ return &withStoresInDocument{
+ value: true,
+ }
+}
+
+func newTransformer(opts ...transformerOption) parser.ASTTransformer {
+ p := &astTransformer{
+ transformerConfig: transformerConfig{
+ Table: false,
+ StoresInDocument: false,
+ },
+ }
+ for _, o := range opts {
+ o.SetMetaOption(&p.transformerConfig)
+ }
+ return p
+}
func (a *astTransformer) Transform(node *gast.Document, reader text.Reader, pc parser.Context) {
dtmp := pc.Get(contextKey)
@@ -179,45 +249,43 @@ func (a *astTransformer) Transform(node *gast.Document, reader text.Reader, pc p
return
}
- meta := GetItems(pc)
- if meta == nil {
- return
- }
- table := east.NewTable()
- alignments := []east.Alignment{}
- for range meta {
- alignments = append(alignments, east.AlignNone)
- }
- row := east.NewTableRow(alignments)
- for _, item := range meta {
- cell := east.NewTableCell()
- cell.AppendChild(cell, gast.NewString([]byte(fmt.Sprintf("%v", item.Key))))
- row.AppendChild(row, cell)
- }
- table.AppendChild(table, east.NewTableHeader(row))
+ if a.Table {
+ meta := GetItems(pc)
+ if meta == nil {
+ return
+ }
+ table := east.NewTable()
+ alignments := []east.Alignment{}
+ for range meta {
+ alignments = append(alignments, east.AlignNone)
+ }
+ row := east.NewTableRow(alignments)
+ for _, item := range meta {
+ cell := east.NewTableCell()
+ cell.AppendChild(cell, gast.NewString([]byte(fmt.Sprintf("%v", item.Key))))
+ row.AppendChild(row, cell)
+ }
+ table.AppendChild(table, east.NewTableHeader(row))
- row = east.NewTableRow(alignments)
- for _, item := range meta {
- cell := east.NewTableCell()
- cell.AppendChild(cell, gast.NewString([]byte(fmt.Sprintf("%v", item.Value))))
- row.AppendChild(row, cell)
+ row = east.NewTableRow(alignments)
+ for _, item := range meta {
+ cell := east.NewTableCell()
+ cell.AppendChild(cell, gast.NewString([]byte(fmt.Sprintf("%v", item.Value))))
+ row.AppendChild(row, cell)
+ }
+ table.AppendChild(table, row)
+ node.InsertBefore(node, node.FirstChild(), table)
}
- table.AppendChild(table, row)
- node.InsertBefore(node, node.FirstChild(), table)
-}
-// Option is a functional option type for this extension.
-type Option func(*meta)
-
-// WithTable is a functional option that renders a YAML metadata as a table.
-func WithTable() Option {
- return func(m *meta) {
- m.Table = true
+ if a.StoresInDocument {
+ for k, v := range d.Map {
+ node.AddMeta(k, v)
+ }
}
}
type meta struct {
- Table bool
+ options []Option
}
// Meta is a extension for the goldmark.
@@ -225,24 +293,28 @@ var Meta = &meta{}
// New returns a new Meta extension.
func New(opts ...Option) goldmark.Extender {
- e := &meta{}
- for _, opt := range opts {
- opt(e)
+ e := &meta{
+ options: opts,
}
return e
}
+// Extend implements goldmark.Extender.
func (e *meta) Extend(m goldmark.Markdown) {
+ topts := []transformerOption{}
+ for _, opt := range e.options {
+ if topt, ok := opt.(transformerOption); ok {
+ topts = append(topts, topt)
+ }
+ }
m.Parser().AddOptions(
parser.WithBlockParsers(
util.Prioritized(NewParser(), 0),
),
)
- if e.Table {
- m.Parser().AddOptions(
- parser.WithASTTransformers(
- util.Prioritized(defaultASTTransformer, 0),
- ),
- )
- }
+ m.Parser().AddOptions(
+ parser.WithASTTransformers(
+ util.Prioritized(newTransformer(topts...), 0),
+ ),
+ )
}
diff --git a/meta_test.go b/meta_test.go
@@ -8,6 +8,7 @@ import (
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
+ "github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
@@ -203,3 +204,45 @@ Tags:
t.Error("invalid table output")
}
}
+
+func TestMetaStoreInDocument(t *testing.T) {
+ markdown := goldmark.New(
+ goldmark.WithExtensions(
+ New(
+ WithStoresInDocument(),
+ ),
+ ),
+ )
+ source := `---
+Title: goldmark-meta
+Summary: Add YAML metadata to the document
+Tags:
+ - markdown
+ - goldmark
+---
+`
+
+ document := markdown.Parser().Parse(text.NewReader([]byte(source)))
+ metaData := document.OwnerDocument().Meta()
+ title := metaData["Title"]
+ s, ok := title.(string)
+ if !ok {
+ t.Error("Title not found in meta data or is not a string")
+ }
+ if s != "goldmark-meta" {
+ t.Errorf("Title must be %s, but got %v", "goldmark-meta", s)
+ }
+ tags, ok := metaData["Tags"].([]interface{})
+ if !ok {
+ t.Error("Tags not found in meta data or is not a slice")
+ }
+ if len(tags) != 2 {
+ t.Error("Tags must be a slice that has 2 elements")
+ }
+ if tags[0] != "markdown" {
+ t.Errorf("Tag#1 must be 'markdown', but got %s", tags[0])
+ }
+ if tags[1] != "goldmark" {
+ t.Errorf("Tag#2 must be 'goldmark', but got %s", tags[1])
+ }
+}