aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/yuin/goldmark-meta/meta.go
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2024-10-25 00:47:47 +0200
committerMitja Felicijan <mitja.felicijan@gmail.com>2024-10-25 00:47:47 +0200
commitc6cc0108ca7738023b45e0eeac0fa2390532dd93 (patch)
tree36890e6cd3091bbab8efbe686cc56f467f645bfd /vendor/github.com/yuin/goldmark-meta/meta.go
parent0130404a1dc663d4aa68d780c9bcb23a4243e68d (diff)
downloadjbmafp-c6cc0108ca7738023b45e0eeac0fa2390532dd93.tar.gz
Added vendor lock on depsHEADmaster
Diffstat (limited to 'vendor/github.com/yuin/goldmark-meta/meta.go')
-rw-r--r--vendor/github.com/yuin/goldmark-meta/meta.go320
1 files changed, 320 insertions, 0 deletions
diff --git a/vendor/github.com/yuin/goldmark-meta/meta.go b/vendor/github.com/yuin/goldmark-meta/meta.go
new file mode 100644
index 0000000..f6c93f1
--- /dev/null
+++ b/vendor/github.com/yuin/goldmark-meta/meta.go
@@ -0,0 +1,320 @@
1// package meta is a extension for the goldmark(http://github.com/yuin/goldmark).
2//
3// This extension parses YAML metadata blocks and store metadata to a
4// parser.Context.
5package meta
6
7import (
8 "bytes"
9 "fmt"
10
11 "github.com/yuin/goldmark"
12 gast "github.com/yuin/goldmark/ast"
13 east "github.com/yuin/goldmark/extension/ast"
14 "github.com/yuin/goldmark/parser"
15 "github.com/yuin/goldmark/text"
16 "github.com/yuin/goldmark/util"
17
18 "gopkg.in/yaml.v2"
19)
20
21type data struct {
22 Map map[string]interface{}
23 Items yaml.MapSlice
24 Error error
25 Node gast.Node
26}
27
28var contextKey = parser.NewContextKey()
29
30// Option interface sets options for this extension.
31type Option interface {
32 metaOption()
33}
34
35// Get returns a YAML metadata.
36func Get(pc parser.Context) map[string]interface{} {
37 v := pc.Get(contextKey)
38 if v == nil {
39 return nil
40 }
41 d := v.(*data)
42 return d.Map
43}
44
45// TryGet tries to get a YAML metadata.
46// If there are YAML parsing errors, then nil and error are returned
47func TryGet(pc parser.Context) (map[string]interface{}, error) {
48 dtmp := pc.Get(contextKey)
49 if dtmp == nil {
50 return nil, nil
51 }
52 d := dtmp.(*data)
53 if d.Error != nil {
54 return nil, d.Error
55 }
56 return d.Map, nil
57}
58
59// GetItems returns a YAML metadata.
60// GetItems preserves defined key order.
61func GetItems(pc parser.Context) yaml.MapSlice {
62 v := pc.Get(contextKey)
63 if v == nil {
64 return nil
65 }
66 d := v.(*data)
67 return d.Items
68}
69
70// TryGetItems returns a YAML metadata.
71// TryGetItems preserves defined key order.
72// If there are YAML parsing errors, then nil and erro are returned.
73func TryGetItems(pc parser.Context) (yaml.MapSlice, error) {
74 dtmp := pc.Get(contextKey)
75 if dtmp == nil {
76 return nil, nil
77 }
78 d := dtmp.(*data)
79 if d.Error != nil {
80 return nil, d.Error
81 }
82 return d.Items, nil
83}
84
85type metaParser struct {
86}
87
88var defaultParser = &metaParser{}
89
90// NewParser returns a BlockParser that can parse YAML metadata blocks.
91func NewParser() parser.BlockParser {
92 return defaultParser
93}
94
95func isSeparator(line []byte) bool {
96 line = util.TrimRightSpace(util.TrimLeftSpace(line))
97 for i := 0; i < len(line); i++ {
98 if line[i] != '-' {
99 return false
100 }
101 }
102 return true
103}
104
105func (b *metaParser) Trigger() []byte {
106 return []byte{'-'}
107}
108
109func (b *metaParser) Open(parent gast.Node, reader text.Reader, pc parser.Context) (gast.Node, parser.State) {
110 linenum, _ := reader.Position()
111 if linenum != 0 {
112 return nil, parser.NoChildren
113 }
114 line, _ := reader.PeekLine()
115 if isSeparator(line) {
116 return gast.NewTextBlock(), parser.NoChildren
117 }
118 return nil, parser.NoChildren
119}
120
121func (b *metaParser) Continue(node gast.Node, reader text.Reader, pc parser.Context) parser.State {
122 line, segment := reader.PeekLine()
123 if isSeparator(line) && !util.IsBlank(line) {
124 reader.Advance(segment.Len())
125 return parser.Close
126 }
127 node.Lines().Append(segment)
128 return parser.Continue | parser.NoChildren
129}
130
131func (b *metaParser) Close(node gast.Node, reader text.Reader, pc parser.Context) {
132 lines := node.Lines()
133 var buf bytes.Buffer
134 for i := 0; i < lines.Len(); i++ {
135 segment := lines.At(i)
136 buf.Write(segment.Value(reader.Source()))
137 }
138 d := &data{}
139 d.Node = node
140 meta := map[string]interface{}{}
141 if err := yaml.Unmarshal(buf.Bytes(), &meta); err != nil {
142 d.Error = err
143 } else {
144 d.Map = meta
145 }
146
147 metaMapSlice := yaml.MapSlice{}
148 if err := yaml.Unmarshal(buf.Bytes(), &metaMapSlice); err != nil {
149 d.Error = err
150 } else {
151 d.Items = metaMapSlice
152 }
153
154 pc.Set(contextKey, d)
155
156 if d.Error == nil {
157 node.Parent().RemoveChild(node.Parent(), node)
158 }
159}
160
161func (b *metaParser) CanInterruptParagraph() bool {
162 return false
163}
164
165func (b *metaParser) CanAcceptIndentedLine() bool {
166 return false
167}
168
169type astTransformer struct {
170 transformerConfig
171}
172
173type transformerConfig struct {
174 // Renders metadata as an html table.
175 Table bool
176
177 // Stores metadata in ast.Document.Meta().
178 StoresInDocument bool
179}
180
181type transformerOption interface {
182 Option
183
184 // SetMetaOption sets options for the metadata parser.
185 SetMetaOption(*transformerConfig)
186}
187
188var _ transformerOption = &withTable{}
189
190type withTable struct {
191 value bool
192}
193
194func (o *withTable) metaOption() {}
195
196func (o *withTable) SetMetaOption(m *transformerConfig) {
197 m.Table = o.value
198}
199
200// WithTable is a functional option that renders a YAML metadata as a table.
201func WithTable() Option {
202 return &withTable{
203 value: true,
204 }
205}
206
207var _ transformerOption = &withStoresInDocument{}
208
209type withStoresInDocument struct {
210 value bool
211}
212
213func (o *withStoresInDocument) metaOption() {}
214
215func (o *withStoresInDocument) SetMetaOption(c *transformerConfig) {
216 c.StoresInDocument = o.value
217}
218
219// WithStoresInDocument is a functional option that parser will store YAML meta in ast.Document.Meta().
220func WithStoresInDocument() Option {
221 return &withStoresInDocument{
222 value: true,
223 }
224}
225
226func newTransformer(opts ...transformerOption) parser.ASTTransformer {
227 p := &astTransformer{
228 transformerConfig: transformerConfig{
229 Table: false,
230 StoresInDocument: false,
231 },
232 }
233 for _, o := range opts {
234 o.SetMetaOption(&p.transformerConfig)
235 }
236 return p
237}
238
239func (a *astTransformer) Transform(node *gast.Document, reader text.Reader, pc parser.Context) {
240 dtmp := pc.Get(contextKey)
241 if dtmp == nil {
242 return
243 }
244 d := dtmp.(*data)
245 if d.Error != nil {
246 msg := gast.NewString([]byte(fmt.Sprintf("<!-- %s -->", d.Error)))
247 msg.SetCode(true)
248 d.Node.AppendChild(d.Node, msg)
249 return
250 }
251
252 if a.Table {
253 meta := GetItems(pc)
254 if meta == nil {
255 return
256 }
257 table := east.NewTable()
258 alignments := []east.Alignment{}
259 for range meta {
260 alignments = append(alignments, east.AlignNone)
261 }
262 row := east.NewTableRow(alignments)
263 for _, item := range meta {
264 cell := east.NewTableCell()
265 cell.AppendChild(cell, gast.NewString([]byte(fmt.Sprintf("%v", item.Key))))
266 row.AppendChild(row, cell)
267 }
268 table.AppendChild(table, east.NewTableHeader(row))
269
270 row = east.NewTableRow(alignments)
271 for _, item := range meta {
272 cell := east.NewTableCell()
273 cell.AppendChild(cell, gast.NewString([]byte(fmt.Sprintf("%v", item.Value))))
274 row.AppendChild(row, cell)
275 }
276 table.AppendChild(table, row)
277 node.InsertBefore(node, node.FirstChild(), table)
278 }
279
280 if a.StoresInDocument {
281 for k, v := range d.Map {
282 node.AddMeta(k, v)
283 }
284 }
285}
286
287type meta struct {
288 options []Option
289}
290
291// Meta is a extension for the goldmark.
292var Meta = &meta{}
293
294// New returns a new Meta extension.
295func New(opts ...Option) goldmark.Extender {
296 e := &meta{
297 options: opts,
298 }
299 return e
300}
301
302// Extend implements goldmark.Extender.
303func (e *meta) Extend(m goldmark.Markdown) {
304 topts := []transformerOption{}
305 for _, opt := range e.options {
306 if topt, ok := opt.(transformerOption); ok {
307 topts = append(topts, topt)
308 }
309 }
310 m.Parser().AddOptions(
311 parser.WithBlockParsers(
312 util.Prioritized(NewParser(), 0),
313 ),
314 )
315 m.Parser().AddOptions(
316 parser.WithASTTransformers(
317 util.Prioritized(newTransformer(topts...), 0),
318 ),
319 )
320}