Convert panics to errors for public interface

This commit is contained in:
Niklas Fasching 2018-12-14 16:24:53 +01:00
parent f28f400d7e
commit 04df30a7b5
5 changed files with 52 additions and 15 deletions

11
main.go
View file

@ -25,19 +25,22 @@ func main() {
if err != nil {
log.Fatal(err)
}
r, out := bytes.NewReader(bs), ""
r, out, err := bytes.NewReader(bs), "", nil
switch strings.ToLower(os.Args[2]) {
case "org":
out = org.NewDocument().Parse(r).Write(org.NewOrgWriter()).String()
out, err = org.NewDocument().Parse(r).Write(org.NewOrgWriter())
case "html":
out = org.NewDocument().Parse(r).Write(org.NewHTMLWriter()).String()
out, err = org.NewDocument().Parse(r).Write(org.NewHTMLWriter())
case "html-chroma":
writer := org.NewHTMLWriter()
writer.HighlightCodeBlock = highlightCodeBlock
out = org.NewDocument().Parse(r).Write(writer).String()
out, err = org.NewDocument().Parse(r).Write(writer)
default:
log.Fatal("Unsupported output format")
}
if err != nil {
log.Fatal(err)
}
log.Print(out)
}

View file

@ -9,6 +9,7 @@ import (
)
type Document struct {
Path string
tokens []token
Nodes []Node
Footnotes *Footnotes
@ -17,6 +18,7 @@ type Document struct {
AutoLink bool
BufferSettings map[string]string
DefaultSettings map[string]string
Error error
}
type Writer interface {
@ -77,24 +79,45 @@ func NewDocument() *Document {
}
}
func (d *Document) Write(w Writer) Writer {
if d.Nodes == nil {
panic("cannot Write() empty document: you must call Parse() first")
func (d *Document) Write(w Writer) (out string, err error) {
defer func() {
if recovered := recover(); recovered != nil {
err = fmt.Errorf("could not write output: %s", recovered)
}
}()
if d.Error != nil {
return "", d.Error
} else if d.Nodes == nil {
return "", fmt.Errorf("could not write output: parse was not called")
}
w.before(d)
w.writeNodes(d.Nodes...)
w.after(d)
return w
return w.String(), err
}
func (d *Document) Parse(input io.Reader) *Document {
defer func() {
if err := recover(); err != nil {
d.Error = fmt.Errorf("could not parse input: %s", err)
}
}()
if d.tokens != nil {
d.Error = fmt.Errorf("parse was called multiple times")
}
d.tokenize(input)
_, nodes := d.parseMany(0, func(d *Document, i int) bool { return !(i < len(d.tokens)) })
d.Nodes = nodes
return d
}
func (d *Document) FrontMatter(input io.Reader, f func(string, string) interface{}) map[string]interface{} {
func (d *Document) FrontMatter(input io.Reader, f func(string, string) interface{}) (_ map[string]interface{}, err error) {
defer func() {
d.tokens = nil
if recovered := recover(); recovered != nil {
err = fmt.Errorf("could not parse input: %s", recovered)
}
}()
d.tokenize(input)
d.parseMany(0, func(d *Document, i int) bool {
if !(i < len(d.tokens)) {
@ -107,7 +130,7 @@ func (d *Document) FrontMatter(input io.Reader, f func(string, string) interface
for k, v := range d.BufferSettings {
frontMatter[k] = f(k, v)
}
return frontMatter
return frontMatter, err
}
func (d *Document) tokenize(input io.Reader) {
@ -117,7 +140,7 @@ func (d *Document) tokenize(input io.Reader) {
d.tokens = append(d.tokens, tokenize(scanner.Text()))
}
if err := scanner.Err(); err != nil {
panic(err)
d.Error = fmt.Errorf("could not tokenize input: %s", err)
}
}

View file

@ -64,7 +64,11 @@ var frontMatterTests = []frontMatterTest{
func TestParseFrontMatter(t *testing.T) {
for _, test := range frontMatterTests {
actual := NewDocument().FrontMatter(strings.NewReader(test.input), test.handler)
actual, err := NewDocument().FrontMatter(strings.NewReader(test.input), test.handler)
if err != nil {
t.Errorf("%s\n got error: %s", test.name, err)
continue
}
if !reflect.DeepEqual(test.expected, actual) {
t.Errorf("%s\n got: %#v\nexpected: %#v\n%s'", test.name, actual, test.expected, test.input)
}

View file

@ -8,9 +8,12 @@ import (
func TestHTMLWriter(t *testing.T) {
for _, path := range orgTestFiles() {
reader, writer := strings.NewReader(fileString(path)), NewHTMLWriter()
actual := NewDocument().Parse(reader).Write(writer).String()
actual, err := NewDocument().Parse(reader).Write(writer)
if err != nil {
t.Errorf("%s\n got error: %s", path, err)
continue
}
expected := fileString(path[:len(path)-len(".org")] + ".html")
if expected != actual {
t.Errorf("%s:\n%s'", path, diff(actual, expected))
} else {

View file

@ -14,7 +14,11 @@ func TestOrgWriter(t *testing.T) {
for _, path := range orgTestFiles() {
expected := fileString(path)
reader, writer := strings.NewReader(expected), NewOrgWriter()
actual := NewDocument().Parse(reader).Write(writer).String()
actual, err := NewDocument().Parse(reader).Write(writer)
if err != nil {
t.Errorf("%s\n got error: %s", path, err)
continue
}
if actual != expected {
t.Errorf("%s:\n%s'", path, diff(actual, expected))
} else {