Documentation ¶
Overview ¶
Package frostedmd converts Markdown files to structured data and HTML.
The structured data is extracted from a Meta Block if present: a code block at the beginning (or, optionally, the end) of the file. At the beginning of the file, the Meta Block may optionally be preceded by a single heading.
# Sample Doc # Meta: AmIYaml: true Tags: [foo, bar, baz, baloney] There you are.
Parsing and rendering are handled by the excellent Blackfriday package: https://godoc.org/github.com/russross/blackfriday
YAML processing is handled with the nearly canonical YAML package from Canonical: https://godoc.org/gopkg.in/yaml.v2
The Meta Block position can be reversed globally by setting MetaBlockAtEnd to true, or at the Parser level. In reversed order the meta code block must be the last element in the Markdown source.
If the Meta contains no Title (nor "title" nor "TITLE") then the first heading is used, if and only if that heading was not preceded by any other block besides the Meta Block.
Supported languages for the meta block are JSON and YAML (the default); additional languages as well as custom parsers are planned for the future.
If an appropriate meta block is found it will be excluded from the rendered HTML content.
Example ¶
package main import ( "fmt" "github.com/biztos/frostedmd" ) func main() { // NOTE: due to a godoc bug, the following text may not appear correctly. // The "# Meta" line and the "Tags" line are both indented (four spaces). // https://github.com/golang/go/issues/18446 // The easiest way to get things done: input := `# My Markdown # Meta: Tags: ["fee","fi","foe"] Obscurantism threatens clean data. ` res, err := frostedmd.MarkdownCommon([]byte(input)) if err != nil { panic(err) } mm := res.Meta fmt.Println("Title:", mm["Title"]) fmt.Println("Tags:", mm["Tags"]) fmt.Println("HTML:", string(res.Content)) }
Output: Title: My Markdown Tags: [fee fi foe] HTML: <h1>My Markdown</h1> <p>Obscurantism threatens clean data.</p>
Index ¶
Examples ¶
Constants ¶
const ( CMD_OPTIONS_ERROR = 1 CMD_FILE_ERROR = 2 CMD_PARSE_ERROR = 3 CMD_SERIALIZATION_ERROR = 4 CMD_OTHER_ERROR = 99 )
const BlackFridayCommonExtensions = 0 |
blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
blackfriday.EXTENSION_TABLES |
blackfriday.EXTENSION_FENCED_CODE |
blackfriday.EXTENSION_AUTOLINK |
blackfriday.EXTENSION_STRIKETHROUGH |
blackfriday.EXTENSION_SPACE_HEADERS |
blackfriday.EXTENSION_HEADER_IDS |
blackfriday.EXTENSION_BACKSLASH_LINE_BREAK |
blackfriday.EXTENSION_DEFINITION_LISTS
BlackFridayCommonExtensions defines the "Common" set of Blackfriday extensions, which are highly recommended for the productive use of Markdown.
const BlackFridayCommonHTMLFlags = 0 |
blackfriday.HTML_USE_XHTML |
blackfriday.HTML_USE_SMARTYPANTS |
blackfriday.HTML_SMARTYPANTS_FRACTIONS |
blackfriday.HTML_SMARTYPANTS_DASHES |
blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
BlackFridayCommonHTMLFlags defines the "Common" set of Blackfriday HTML flags; also highly recommended.
Variables ¶
var CmdUsage = `` /* 832-byte string literal not displayed */
Standard DocOpt specification covering all known options. Additional explanatory text is up to the caller of NewCmd.
var DefaultExitFunction = os.Exit
Exit function; override for testing main()
var MetaBlockAtEnd = false
MetaBlockAtEnd defines whether the block of data is expected at the end of the Markdown file, or (the default) at the beginning.
Functions ¶
func LicenseFullText ¶
func LicenseFullText() string
LicenseFullText returns the full license text for Frosted Markdown and all known included licenses, to the best of the author's knowledge.
func RendererTestCoverageShim ¶
func RendererTestCoverageShim() int
RendererTestCoverageShim is, as its name hopefully implies, a function that minimally exercises some hard (impossible?) to reach code in our internal renderer. Removing the code is not really an option, since it is necessary for the blackfriday.Renderer interface; however it has not yet proven reachable from within document parsing. This function is the lesser of two evils. The greater evil would be to expose the entire rendering subsystem just to make it testable; or (worse) live with less than 100% test coverage.
Types ¶
type Cmd ¶
type Cmd struct { Name string Version string Usage string Options *CmdOptions Result *ParseResult // In order to make testing realistically possible in the command context // we make these standard things overrideable: Exit func(int) Stdin io.Reader Stdout io.Writer Stderr io.Writer }
Cmd defines a command-line program or its equivalent.
func NewCmd ¶
NewCmd returns a new Cmd for the given name, version and DocOpt usage specification. The Exit property is set to the DefaultExitFunction, allowing a global override for testing.
func (*Cmd) Fail ¶
Fail fails with a useful message based on err; if err is a CmdError and has an exit code set, that is used, otherwise the "other" code is used: CMD_OTHER_ERROR.
func (*Cmd) ParseFile ¶
ParseFile parses a single file contained in the Options, according to the other options therein, and returning any error. Note that a useful result *may* be returned together with an error. If the Options.File is the empty string, input is read from the command's Stdin (os.Stdin by default).
func (*Cmd) PrintResult ¶
PrintResult prints the Result according to the Options, with output going to c.Stdout. Any error returned should be considered fatal. If Result is nil, nothing is printed; this is normal if the Test option is set.
func (*Cmd) Run ¶
Run calls the methods used for a standard command run in order: SetOptions, ParseFile, and finally PrintResult. The first error encountered is returned, to (normally) be passed to Fail. Note that in the interest of simplicity, docopt is allowed to exit directly from within SetOptions.
func (*Cmd) SetOptions ¶
SetOptions sets the Options struct according to the Usage. If a --license boolean option is found, the LicenseFullText is printed and the program exits with success. The --help and --version (-h and -v) options are handled similarly by docopt, and it will also fail directly to os.Exit on any option errors.
type CmdError ¶
type CmdError struct { Err error // The source error. File string // The file to include in the error message. Code int // The exit code, if Force is not set. Silent bool // If true, do not print the error. Force bool // If true, do not exit. }
CmdError defines an error in the command-running context.
type CmdOptions ¶
type CmdOptions struct { File string Format string Indent bool NoBase64 bool ContentOnly bool MetaOnly bool PlainMarkdown bool Force bool Silent bool Test bool }
CmdOptions describes the options available to the command. The standard fmd command exposes all of them.
type CmdYamlRes ¶
CmdYamlRes is a shim to handle output serialization to YAML.
type ParseResult ¶
type ParseResult struct { Meta map[string]interface{} `json:"meta"` Content []byte `json:"content"` }
ParseResult defines the result of a Parse operation.
func MarkdownBasic ¶
func MarkdownBasic(input []byte) (*ParseResult, error)
MarkdownBasic converts Markdown input using the same options as blackfriday.MarkdownBasic. This is simply a convenience method for:
NewBasic().Parse(input)
func MarkdownCommon ¶
func MarkdownCommon(input []byte) (*ParseResult, error)
MarkdownCommon converts Markdown input using the same options as blackfriday.MarkdownCommon. This is simply a convenience method for:
New().Parse(input)
type Parser ¶
type Parser struct { MetaAtEnd bool MarkdownExtensions int // uses blackfriday EXTENSION_* constants HTMLFlags int // uses blackfridy HTML_* constants }
Parser defines a parser-renderer used for converting source data to HTML and metadata.
func New ¶
func New() *Parser
New returns a new Parser with the common flags and extensions enabled.
Example ¶
package main import ( "fmt" "github.com/biztos/frostedmd" ) func main() { input := `# Lots of Data Here we have a full dataset, which (for instance) a template engine will turn into something cool and dynamic. Thus we put it at the end so we can read our nice summary using the *head* command. { "datasets": { "numbers": [11,22,33,44,55,66], "letters": ["a","B","ß","í"] } } ` parser := frostedmd.New() parser.MetaAtEnd = true res, err := parser.Parse([]byte(input)) if err != nil { panic(err) } mm := res.Meta fmt.Println("Title:", mm["Title"]) fmt.Println("HTML:", string(res.Content)) // Order within a map is random in Go, so let's make it explicit. fmt.Println("Data sets:") if ds, ok := mm["datasets"].(map[string]interface{}); ok { fmt.Println(" numbers:", ds["numbers"]) fmt.Println(" letters:", ds["letters"]) } else { fmt.Printf("NOT A MAP: %T\n", mm["datasets"]) } }
Output: Title: Lots of Data HTML: <h1>Lots of Data</h1> <p>Here we have a full dataset, which (for instance) a template engine will turn into something cool and dynamic. Thus we put it at the end so we can read our nice summary using the <em>head</em> command.</p> Data sets: numbers: [11 22 33 44 55 66] letters: [a B ß í]
func NewBasic ¶
func NewBasic() *Parser
NewBasic returns a new Parser without the common flags and extensions.
func (*Parser) Parse ¶
func (p *Parser) Parse(input []byte) (*ParseResult, error)
Parse converts Markdown input into a meta map and HTML content fragment. If an error is encountered while parsing the meta block, the rendered content is still returned. Thus the caller may choose to handle meta errors without interrupting flow.