feat: add markdown parser
parent
426f5ea5fe
commit
080796c15c
3
go.mod
3
go.mod
|
@ -11,10 +11,13 @@ require (
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/sebdah/goldie/v2 v2.5.3
|
github.com/sebdah/goldie/v2 v2.5.3
|
||||||
|
github.com/stretchr/testify v1.6.1
|
||||||
github.com/urfave/cli/v2 v2.3.0
|
github.com/urfave/cli/v2 v2.3.0
|
||||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9 // indirect
|
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9 // indirect
|
||||||
golang.org/x/mod v0.3.0
|
golang.org/x/mod v0.3.0
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
|
||||||
)
|
)
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -72,11 +72,14 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5I
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||||
|
@ -136,3 +139,8 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package markdown
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
//https://guides.github.com/features/mastering-markdown/
|
||||||
|
|
||||||
|
const (
|
||||||
|
headerToken = '#'
|
||||||
|
defaultListToken = '-'
|
||||||
|
alternativeListToken = '*'
|
||||||
|
spaceToken = ' '
|
||||||
|
newlineToken = '\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
// Base is single markdown syntax representation
|
||||||
|
// Example: header, list, ...
|
||||||
|
type Base interface {
|
||||||
|
ToString() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type header struct {
|
||||||
|
level int
|
||||||
|
text string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *header) ToString() string {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
for i := 0; i < h.level; i++ {
|
||||||
|
builder.WriteString(string(headerToken))
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(string(spaceToken))
|
||||||
|
|
||||||
|
text := strings.TrimSpace(h.text)
|
||||||
|
builder.WriteString(text)
|
||||||
|
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
type listItem struct {
|
||||||
|
text string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *listItem) ToString() string {
|
||||||
|
text := strings.TrimSpace(i.text)
|
||||||
|
|
||||||
|
return string(defaultListToken) + string(spaceToken) + text
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package markdown
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/haunt98/changeloguru/pkg/comparision"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHeaderToString(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
header header
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "level 1",
|
||||||
|
header: header{
|
||||||
|
level: 1,
|
||||||
|
text: "abc",
|
||||||
|
},
|
||||||
|
want: "# abc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "level 3",
|
||||||
|
header: header{
|
||||||
|
level: 3,
|
||||||
|
text: "xyz",
|
||||||
|
},
|
||||||
|
want: "### xyz",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
got := tc.header.ToString()
|
||||||
|
comparision.Diff(t, tc.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListItemToString(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
listItem listItem
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "normal",
|
||||||
|
listItem: listItem{
|
||||||
|
text: "abc",
|
||||||
|
},
|
||||||
|
want: "- abc",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
got := tc.listItem.ToString()
|
||||||
|
comparision.Diff(t, tc.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package markdown
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultBaseLen = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
func Parse(lines []string) []Base {
|
||||||
|
bases := make([]Base, 0, defaultBaseLen)
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(line, string(headerToken)) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bases
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHeader(line string) header {
|
||||||
|
level := 0
|
||||||
|
|
||||||
|
for _, c := range line {
|
||||||
|
if c != headerToken {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
level++
|
||||||
|
}
|
||||||
|
|
||||||
|
line = strings.TrimLeft(line, string(headerToken))
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
|
return header{
|
||||||
|
level: level,
|
||||||
|
text: line,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseListItem(line string) listItem {
|
||||||
|
line = strings.TrimLeft(line, string(defaultListToken))
|
||||||
|
line = strings.TrimLeft(line, string(alternativeListToken))
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
|
return listItem{
|
||||||
|
text: line,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package markdown
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseHeader(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
line string
|
||||||
|
want header
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "level 1",
|
||||||
|
line: "# abc",
|
||||||
|
want: header{
|
||||||
|
level: 1,
|
||||||
|
text: "abc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "level 3",
|
||||||
|
line: "### xyz",
|
||||||
|
want: header{
|
||||||
|
level: 3,
|
||||||
|
text: "xyz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
got := parseHeader(tc.line)
|
||||||
|
assert.Equal(t, tc.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseListItem(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
line string
|
||||||
|
want listItem
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "normal",
|
||||||
|
line: "- abc",
|
||||||
|
want: listItem{
|
||||||
|
text: "abc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "alternative",
|
||||||
|
line: "* xyz",
|
||||||
|
want: listItem{
|
||||||
|
text: "xyz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
got := parseListItem(tc.line)
|
||||||
|
assert.Equal(t, tc.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue