parent
dd2bf81ff8
commit
5a887cd08f
1
go.mod
1
go.mod
|
@ -9,6 +9,7 @@ require (
|
||||||
github.com/google/go-cmp v0.5.5 // indirect
|
github.com/google/go-cmp v0.5.5 // indirect
|
||||||
github.com/haunt98/clock v0.1.0
|
github.com/haunt98/clock v0.1.0
|
||||||
github.com/haunt98/color v0.1.0
|
github.com/haunt98/color v0.1.0
|
||||||
|
github.com/haunt98/markdown-go v0.1.0
|
||||||
github.com/kevinburke/ssh_config v1.1.0 // indirect
|
github.com/kevinburke/ssh_config v1.1.0 // indirect
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -39,6 +39,8 @@ github.com/haunt98/clock v0.1.0 h1:iRaGSoQ21Z+gD9J4mVoYqL4liAg5eGwPkkPGknmfV6A=
|
||||||
github.com/haunt98/clock v0.1.0/go.mod h1:Sq2/R7IgMjxnqgCF3f69ROb8ZeF9PO0YaQW1p3wXGiE=
|
github.com/haunt98/clock v0.1.0/go.mod h1:Sq2/R7IgMjxnqgCF3f69ROb8ZeF9PO0YaQW1p3wXGiE=
|
||||||
github.com/haunt98/color v0.1.0 h1:qfP5oNI3aoUC8T+bH/JNVAg79ljyhTGpgfqSKWhkiQQ=
|
github.com/haunt98/color v0.1.0 h1:qfP5oNI3aoUC8T+bH/JNVAg79ljyhTGpgfqSKWhkiQQ=
|
||||||
github.com/haunt98/color v0.1.0/go.mod h1:V4BPVUSuiOItuVZHRHUTkpxO7OYQiP0DSgIWMpC/2qs=
|
github.com/haunt98/color v0.1.0/go.mod h1:V4BPVUSuiOItuVZHRHUTkpxO7OYQiP0DSgIWMpC/2qs=
|
||||||
|
github.com/haunt98/markdown-go v0.1.0 h1:Yg98g9F8NtLfZwFOlBtJRu1VWhDbJbPC8LjLgD70WSc=
|
||||||
|
github.com/haunt98/markdown-go v0.1.0/go.mod h1:E18hIq5n6hy+aQ+U6o+MuMJdZoq7/5n50FG+JsjuFIs=
|
||||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
|
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/haunt98/changeloguru/internal/convention"
|
"github.com/haunt98/changeloguru/internal/convention"
|
||||||
"github.com/haunt98/changeloguru/internal/markdown"
|
|
||||||
"github.com/haunt98/clock"
|
"github.com/haunt98/clock"
|
||||||
|
"github.com/haunt98/markdown-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/haunt98/changeloguru/internal/convention"
|
"github.com/haunt98/changeloguru/internal/convention"
|
||||||
"github.com/haunt98/changeloguru/internal/markdown"
|
"github.com/haunt98/markdown-go"
|
||||||
"github.com/sebdah/goldie/v2"
|
"github.com/sebdah/goldie/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"github.com/haunt98/changeloguru/internal/changelog"
|
"github.com/haunt98/changeloguru/internal/changelog"
|
||||||
"github.com/haunt98/changeloguru/internal/convention"
|
"github.com/haunt98/changeloguru/internal/convention"
|
||||||
"github.com/haunt98/changeloguru/internal/git"
|
"github.com/haunt98/changeloguru/internal/git"
|
||||||
"github.com/haunt98/changeloguru/internal/markdown"
|
"github.com/haunt98/markdown-go"
|
||||||
"github.com/pkg/diff"
|
"github.com/pkg/diff"
|
||||||
"github.com/pkg/diff/write"
|
"github.com/pkg/diff/write"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
package markdown
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// GenerateText return single string which represents all markdown nodes
|
|
||||||
func GenerateText(bases []Node) string {
|
|
||||||
lines := make([]string, len(bases))
|
|
||||||
for i, base := range bases {
|
|
||||||
lines[i] = base.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
result := strings.Join(lines, string(NewlineToken)+string(NewlineToken))
|
|
||||||
// Fix no newline at end of file
|
|
||||||
result += string(NewlineToken)
|
|
||||||
return result
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package markdown
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGenerate(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
bases []Node
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "normal",
|
|
||||||
bases: []Node{
|
|
||||||
header{
|
|
||||||
level: 1,
|
|
||||||
text: "header",
|
|
||||||
},
|
|
||||||
listItem{
|
|
||||||
text: "item 1",
|
|
||||||
},
|
|
||||||
listItem{
|
|
||||||
text: "item 2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
want: "# header\n\n- item 1\n\n- item 2\n",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
got := GenerateText(tc.bases)
|
|
||||||
assert.Equal(t, tc.want, got)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
package markdown
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// https://guides.github.com/features/mastering-markdown/
|
|
||||||
|
|
||||||
const (
|
|
||||||
headerToken = '#'
|
|
||||||
defaultListToken = '-'
|
|
||||||
alternativeListToken = '*'
|
|
||||||
|
|
||||||
spaceToken = ' '
|
|
||||||
NewlineToken = '\n'
|
|
||||||
)
|
|
||||||
|
|
||||||
// Node is single markdown syntax representation
|
|
||||||
// Example: header, list, ...
|
|
||||||
type Node interface {
|
|
||||||
String() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type header struct {
|
|
||||||
level int
|
|
||||||
text string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHeader(level int, text string) Node {
|
|
||||||
return header{
|
|
||||||
level: level,
|
|
||||||
text: text,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h header) String() 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 NewListItem(text string) Node {
|
|
||||||
return listItem{
|
|
||||||
text: text,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i listItem) String() string {
|
|
||||||
text := strings.TrimSpace(i.text)
|
|
||||||
|
|
||||||
return string(defaultListToken) + string(spaceToken) + text
|
|
||||||
}
|
|
||||||
|
|
||||||
func Equal(base1, base2 Node) bool {
|
|
||||||
return base1.String() == base2.String()
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
package markdown
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHeaderString(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.String()
|
|
||||||
assert.Equal(t, tc.want, got)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestListItemString(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.String()
|
|
||||||
assert.Equal(t, tc.want, got)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
package markdown
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultBaseLen = 10
|
|
||||||
)
|
|
||||||
|
|
||||||
// Parse return all markdown nodes from lines
|
|
||||||
func Parse(lines []string) []Node {
|
|
||||||
if len(lines) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
bases := make([]Node, 0, defaultBaseLen)
|
|
||||||
|
|
||||||
for _, line := range lines {
|
|
||||||
line = strings.TrimSpace(line)
|
|
||||||
|
|
||||||
if line == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(line, string(headerToken)) {
|
|
||||||
bases = append(bases, parseHeader(line))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(line, string(defaultListToken)) ||
|
|
||||||
strings.HasPrefix(line, string(alternativeListToken)) {
|
|
||||||
bases = append(bases, parseListItem(line))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,117 +0,0 @@
|
||||||
package markdown
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
lines []string
|
|
||||||
want []Node
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "level 1",
|
|
||||||
lines: []string{
|
|
||||||
"# abc",
|
|
||||||
"- xyz",
|
|
||||||
},
|
|
||||||
want: []Node{
|
|
||||||
header{
|
|
||||||
level: 1,
|
|
||||||
text: "abc",
|
|
||||||
},
|
|
||||||
listItem{
|
|
||||||
text: "xyz",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "level 3 with alternative",
|
|
||||||
lines: []string{
|
|
||||||
"### xyz",
|
|
||||||
"* abc",
|
|
||||||
},
|
|
||||||
want: []Node{
|
|
||||||
header{
|
|
||||||
level: 3,
|
|
||||||
text: "xyz",
|
|
||||||
},
|
|
||||||
listItem{
|
|
||||||
text: "abc",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
got := Parse(tc.lines)
|
|
||||||
assert.Equal(t, tc.want, got)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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