aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnhgelus Morhtuuzh <william@herges.fr>2025-10-02 13:21:37 +0200
committerAnhgelus Morhtuuzh <william@herges.fr>2025-10-02 13:21:37 +0200
commit72eed1cfa1f5067a7ca581c53bb40e9e0fb047cc (patch)
tree5a4e8b69c4e2705222baf1e1c8e0ffcfadfb3c98
parentcdb0a541554aa4a16fc71b6425225e8c603c83b8 (diff)
fix(markdown): bad list parsing
-rw-r--r--.gitignore158
-rw-r--r--mardown/ast_external.go76
-rw-r--r--mardown/ast_external_test.go18
-rw-r--r--mardown/ast_list.go4
-rw-r--r--mardown/ast_paragraph.go3
-rw-r--r--mardown/ast_quote.go2
-rw-r--r--mardown/ast_test.go8
7 files changed, 247 insertions, 22 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..284ed34
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,158 @@
+### Node template
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+web_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional stylelint cache
+.stylelintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variable files
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+out
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and not Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# vuepress v2.x temp and cache directory
+.temp
+
+# Docusaurus cache and generated files
+.docusaurus
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+# yarn v2
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
+### Go template
+# If you prefer the allow list template instead of the deny list, see community template:
+# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
+#
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
+
+# Go workspace file
+go.work
+go.work.sum
+
+# env file
+
+.idea
diff --git a/mardown/ast_external.go b/mardown/ast_external.go
index 87fb880..78f12c8 100644
--- a/mardown/ast_external.go
+++ b/mardown/ast_external.go
@@ -25,7 +25,7 @@ func (a *astLink) Eval() (template.HTML, error) {
type astImage struct {
alt block
src block
- source *astParagraph
+ source []*astParagraph
}
func (a *astImage) Eval() (template.HTML, error) {
@@ -40,11 +40,16 @@ func (a *astImage) Eval() (template.HTML, error) {
if a.source == nil {
return template.HTML(fmt.Sprintf(`<figure><img alt="%s" src="%s"></figure>`, alt, src)), nil
}
- source, err := a.source.Eval()
- if err != nil {
- return "", err
+ var s template.HTML
+ for _, c := range a.source {
+ ct, err := c.Eval()
+ if err != nil {
+ return "", err
+ }
+ s += ct + " "
}
- return template.HTML(fmt.Sprintf(`<figure><img alt="%s" src="%s"><figcaption>%s</figcaption></figure>`, alt, src, source)), nil
+ s = s[:len(s)-1]
+ return template.HTML(fmt.Sprintf(`<figure><img alt="%s" src="%s"><figcaption>%s</figcaption></figure>`, alt, src, s)), nil
}
func external(lxs *lexers) (block, error) {
@@ -69,7 +74,7 @@ func external(lxs *lexers) (block, error) {
func link(lxs *lexers) (block, error) {
lk := new(astLink)
start := lxs.current
- content, href, _, ok := parseExternal(lxs, 1)
+ content, href, _, ok := parseExternal(lxs, false)
if !ok {
return reset(lxs, start), nil
}
@@ -81,34 +86,60 @@ func link(lxs *lexers) (block, error) {
func image(lxs *lexers) (block, error) {
img := new(astImage)
start := lxs.current
- alt, src, _, ok := parseExternal(lxs, 2)
+ alt, src, source, ok := parseExternal(lxs, true)
if !ok {
return reset(lxs, start), nil
}
img.alt = astLiteral(alt)
img.src = astLiteral(src)
- //img.source = astLiteral(source)
+ img.source = source
return img, nil
}
-func parseExternal(lxs *lexers, maxBreak int) (string, string, string, bool) {
+func parseExternal(lxs *lexers, withSource bool) (string, string, []*astParagraph, bool) {
next := false
var s string
var first string
var end string
+ var ps []*astParagraph
n := 0
- for lxs.Next() && n < maxBreak {
+ fn := func() bool {
+ p, err := paragraph(lxs, true)
+ if err != nil {
+ return false
+ }
+ ps = append(ps, p)
+ n = 0
+ return true
+ }
+ for lxs.Next() && n < 2 {
switch lxs.Current().Type {
case lexerBreak:
- n++
+ if !withSource {
+ return "", "", nil, false
+ }
+ n += len(lxs.Current().Value)
+ if first != "" && end != "" {
+ if !lxs.Next() {
+ return first, end, ps, true
+ }
+ ok := fn()
+ if !ok {
+ return "", "", nil, false
+ }
+ lxs.Before() // because we must parse lexerBreak
+ }
case lexerExternal:
+ if first != "" && end != "" {
+ return "", "", nil, false
+ }
if n > 0 && (first == "" || end == "") {
- return "", "", "", false
+ return "", "", nil, false
}
n = 0
if !next {
if lxs.Current().Value != "](" || !lxs.Next() {
- return "", "", "", false
+ return "", "", nil, false
}
lxs.Before() // because we called Next
first = s
@@ -116,23 +147,30 @@ func parseExternal(lxs *lexers, maxBreak int) (string, string, string, bool) {
next = true
} else {
if lxs.Current().Value != ")" {
- return "", "", "", false
+ return "", "", nil, false
}
- if maxBreak == 1 {
- return first, s, "", true
+ if !withSource {
+ return first, s, nil, true
}
end = s
s = ""
+ if lxs.Next() && lxs.Current().Type != lexerBreak {
+ return "", "", nil, false
+ }
+ lxs.Before() // because we called Next
}
default:
+ if ps != nil {
+ return "", "", nil, false
+ }
n = 0
s += lxs.Current().Value
}
}
- if maxBreak == 1 {
- return "", "", "", false
+ if !withSource {
+ return "", "", nil, false
}
- return first, end, s, true
+ return first, end, ps, true
}
func reset(lxs *lexers, start int) block {
diff --git a/mardown/ast_external_test.go b/mardown/ast_external_test.go
index fc0597d..afae085 100644
--- a/mardown/ast_external_test.go
+++ b/mardown/ast_external_test.go
@@ -28,4 +28,22 @@ func TestExternal(t *testing.T) {
if string(got) != `<figure><img alt="image alt" src="image src"></figure>` {
t.Errorf("invalid value, got %s", got)
}
+
+ lxs = lex(`
+![image alt](image src)
+source 1
+source 2
+`)
+ tree, err = ast(lxs)
+ if err != nil {
+ t.Fatal(err)
+ }
+ got, err = tree.Eval()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(got) != `<figure><img alt="image alt" src="image src"><figcaption>source 1 source 2</figcaption></figure>` {
+ t.Errorf("invalid value, got %s", got)
+ }
+
}
diff --git a/mardown/ast_list.go b/mardown/ast_list.go
index 8eb451a..f95324b 100644
--- a/mardown/ast_list.go
+++ b/mardown/ast_list.go
@@ -42,7 +42,7 @@ func list(lxs *lexers) (block, error) {
for lxs.Next() && n < 2 {
switch lxs.Current().Type {
case lexerBreak:
- n++
+ n += len(lxs.Current().Value)
case lexerList:
n = 0
tp := detectListType(lxs.Current().Value)
@@ -56,9 +56,11 @@ func list(lxs *lexers) (block, error) {
if err != nil {
return nil, err
}
+ lxs.Before() // because we must parse the last char
tree.content = append(tree.content, c)
}
}
+ lxs.Before() // because we did not use it
return tree, nil
}
diff --git a/mardown/ast_paragraph.go b/mardown/ast_paragraph.go
index 44b5dd9..23d526e 100644
--- a/mardown/ast_paragraph.go
+++ b/mardown/ast_paragraph.go
@@ -40,9 +40,10 @@ func paragraph(lxs *lexers, oneLine bool) (*astParagraph, error) {
n := 0
lxs.current-- // because we do not use it before the next
for lxs.Next() && n < maxBreak {
+ //println("p", strings.ReplaceAll(lxs.Current().Value, "\n", "/n"))
switch lxs.Current().Type {
case lexerBreak:
- n = len(lxs.Current().Value)
+ n += len(lxs.Current().Value)
case lexerQuote, lexerList:
if n > 0 {
lxs.Before() // because we did not use it
diff --git a/mardown/ast_quote.go b/mardown/ast_quote.go
index d673f61..f046445 100644
--- a/mardown/ast_quote.go
+++ b/mardown/ast_quote.go
@@ -44,7 +44,7 @@ func quote(lxs *lexers) (*astQuote, error) {
for lxs.Next() && n < 2 {
switch lxs.Current().Type {
case lexerBreak:
- n = len(lxs.Current().Value)
+ n += len(lxs.Current().Value)
quoteContinue = false
case lexerQuote:
n = 0
diff --git a/mardown/ast_test.go b/mardown/ast_test.go
index 573349e..3b2a77a 100644
--- a/mardown/ast_test.go
+++ b/mardown/ast_test.go
@@ -23,6 +23,10 @@ avec une source
1. et maintenant
2. elle l'est
- hehe
+
+![Ceci est ma pfp :3](https://cdn.anhgelus.world/pfp.jpg)
+Ma pfp hehe :D
+Elle est **magnifique**, n'est-ce pas ?
`
var parsed = `
@@ -34,6 +38,10 @@ var parsed = `
<ul><li>Ceci est une liste</li><li>pas ordonnée</li></ul>
<ol><li>et maintenant</li><li>elle l&#39;est</li></ol>
<ul><li>hehe</li></ul>
+<figure>
+<img alt="Ceci est ma pfp :3" src="https://cdn.anhgelus.world/pfp.jpg">
+<figcaption>Ma pfp hehe :D Elle est <b>magnifique</b>, n&#39;est-ce pas ?</figcaption>
+</figure>
`
func TestAst(t *testing.T) {