mirror of
https://github.com/yuin/goldmark
synced 2025-03-04 23:04:52 +00:00
Add parser.ParseContext
This commit is contained in:
parent
77aabc8f8e
commit
a8a4629dd9
3 changed files with 40 additions and 22 deletions
|
|
@ -108,7 +108,7 @@ Summary:
|
|||
Security
|
||||
--------------------
|
||||
By default, goldmark does not render raw HTMLs and potentially dangerous urls.
|
||||
If you need to gain more control about untrusted contents, it is recommended to
|
||||
If you need to gain more control over untrusted contents, it is recommended to
|
||||
use HTML sanitizer such as [bluemonday](https://github.com/microcosm-cc/bluemonday).
|
||||
|
||||
Benchmark
|
||||
|
|
|
|||
12
markdown.go
12
markdown.go
|
|
@ -27,8 +27,8 @@ var defaultMarkdown = New()
|
|||
|
||||
// Convert interprets a UTF-8 bytes source in Markdown and
|
||||
// write rendered contents to a writer w.
|
||||
func Convert(source []byte, w io.Writer) error {
|
||||
return defaultMarkdown.Convert(source, w)
|
||||
func Convert(source []byte, w io.Writer, opts ...parser.ParseOption) error {
|
||||
return defaultMarkdown.Convert(source, w, opts...)
|
||||
}
|
||||
|
||||
// A Markdown interface offers functions to convert Markdown text to
|
||||
|
|
@ -36,7 +36,7 @@ func Convert(source []byte, w io.Writer) error {
|
|||
type Markdown interface {
|
||||
// Convert interprets a UTF-8 bytes source in Markdown and write rendered
|
||||
// contents to a writer w.
|
||||
Convert(source []byte, writer io.Writer) error
|
||||
Convert(source []byte, writer io.Writer, opts ...parser.ParseOption) error
|
||||
|
||||
// Parser returns a Parser that will be used for conversion.
|
||||
Parser() parser.Parser
|
||||
|
|
@ -115,10 +115,10 @@ func New(options ...Option) Markdown {
|
|||
return md
|
||||
}
|
||||
|
||||
func (m *markdown) Convert(source []byte, writer io.Writer) error {
|
||||
func (m *markdown) Convert(source []byte, writer io.Writer, opts ...parser.ParseOption) error {
|
||||
reader := text.NewReader(source)
|
||||
doc, _ := m.parser.Parse(reader)
|
||||
return m.renderer.Render(writer, reader.Source(), doc)
|
||||
doc := m.parser.Parse(reader, opts...)
|
||||
return m.renderer.Render(writer, source, doc)
|
||||
}
|
||||
|
||||
func (m *markdown) Parser() parser.Parser {
|
||||
|
|
|
|||
|
|
@ -62,11 +62,12 @@ func (c *ContextKey) New() ContextKey {
|
|||
return ContextKey(atomic.AddInt32((*int32)(c), 1))
|
||||
}
|
||||
|
||||
var contextKey ContextKey
|
||||
// ContextKeyMax is a maximum value of the ContextKey.
|
||||
var ContextKeyMax ContextKey
|
||||
|
||||
// NewContextKey return a new ContextKey value.
|
||||
func NewContextKey() ContextKey {
|
||||
return contextKey.New()
|
||||
return ContextKeyMax.New()
|
||||
}
|
||||
|
||||
// A Context interface holds a information that are necessary to parse
|
||||
|
|
@ -131,13 +132,6 @@ type Context interface {
|
|||
SetLastOpenedBlock(Block)
|
||||
}
|
||||
|
||||
// A Result interface holds a result of parsing Markdown text.
|
||||
type Result interface {
|
||||
// Reference returns (a reference, true) if a reference associated with
|
||||
// given label exists, otherwise (nil, false).
|
||||
Reference(label string) (Reference, bool)
|
||||
}
|
||||
|
||||
type parseContext struct {
|
||||
store []interface{}
|
||||
source []byte
|
||||
|
|
@ -149,9 +143,10 @@ type parseContext struct {
|
|||
lastOpenedBlock Block
|
||||
}
|
||||
|
||||
func newContext(source []byte) Context {
|
||||
// NewContext returns a new Context.
|
||||
func NewContext(source []byte) Context {
|
||||
return &parseContext{
|
||||
store: make([]interface{}, contextKey+1),
|
||||
store: make([]interface{}, ContextKeyMax+1),
|
||||
source: source,
|
||||
refs: map[string]Reference{},
|
||||
blockOffset: 0,
|
||||
|
|
@ -339,7 +334,7 @@ type OptionName string
|
|||
// A Parser interface parses Markdown text into AST nodes.
|
||||
type Parser interface {
|
||||
// Parse parses given Markdown text into AST nodes.
|
||||
Parse(reader text.Reader) (ast.Node, Result)
|
||||
Parse(reader text.Reader, opts ...ParseOption) ast.Node
|
||||
|
||||
// AddOption adds given option to thie parser.
|
||||
AddOption(Option)
|
||||
|
|
@ -652,7 +647,23 @@ func (p *parser) addASTTransformer(v util.PrioritizedValue, options map[OptionNa
|
|||
p.astTransformers = append(p.astTransformers, at)
|
||||
}
|
||||
|
||||
func (p *parser) Parse(reader text.Reader) (ast.Node, Result) {
|
||||
// A ParseConfig struct is a data structure that holds configuration of the Parser.Parse.
|
||||
type ParseConfig struct {
|
||||
Context Context
|
||||
}
|
||||
|
||||
// A ParseOption is a functional option type for the Parser.Parse.
|
||||
type ParseOption func(c *ParseConfig)
|
||||
|
||||
// WithContext is a functional option that allow you to override
|
||||
// a default context.
|
||||
func WithContext(context Context) ParseOption {
|
||||
return func(c *ParseConfig) {
|
||||
c.Context = context
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) Parse(reader text.Reader, opts ...ParseOption) ast.Node {
|
||||
p.initSync.Do(func() {
|
||||
p.config.BlockParsers.Sort()
|
||||
for _, v := range p.config.BlockParsers {
|
||||
|
|
@ -672,8 +683,15 @@ func (p *parser) Parse(reader text.Reader) (ast.Node, Result) {
|
|||
}
|
||||
p.config = nil
|
||||
})
|
||||
c := &ParseConfig{}
|
||||
for _, opt := range opts {
|
||||
opt(c)
|
||||
}
|
||||
if c.Context == nil {
|
||||
c.Context = NewContext(reader.Source())
|
||||
}
|
||||
pc := c.Context
|
||||
root := ast.NewDocument()
|
||||
pc := newContext(reader.Source())
|
||||
p.parseBlocks(root, reader, pc)
|
||||
blockReader := text.NewBlockReader(reader.Source(), nil)
|
||||
p.walkBlock(root, func(node ast.Node) {
|
||||
|
|
@ -683,7 +701,7 @@ func (p *parser) Parse(reader text.Reader) (ast.Node, Result) {
|
|||
at.Transform(root, pc)
|
||||
}
|
||||
//root.Dump(reader.Source(), 0)
|
||||
return root, pc
|
||||
return root
|
||||
}
|
||||
|
||||
func (p *parser) transformParagraph(node *ast.Paragraph, pc Context) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue