Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/dialects.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,11 @@ flowchart TD
IN["filter text"] --> LEX["Lexer: tokens<br/>(strings read as the dialect reads them)"]
LEX --> OP["an operator, as written<br/>(e.g. !=, ILIKE, ~~, ISNULL)"]
OP --> D1{"does the dialect have<br/>the operator?"}
D1 -->|"no: ILIKE, ~ in SQL:2023 and MySQL 8.4;<br/>SIMILAR TO, IS DISTINCT FROM in MySQL 8.4"| E1["operator &quot;ILIKE&quot; is not part of<br/>the SQL:2023 dialect"]
D1 -->|"no: ILIKE, ~ in SQL:2023 and MySQL 8.4;<br/>SIMILAR TO, IS DISTINCT FROM in MySQL 8.4"| E1["operator #quot;ILIKE#quot; is not part of<br/>the SQL:2023 dialect"]
D1 -->|"yes"| D2{"does it have<br/>this spelling of it?"}
D2 -->|"no: != in SQL:2023; ~~ !~~ ISNULL NOTNULL<br/>in both; BETWEEN SYMMETRIC in MySQL 8.4"| E2["!= is not part of the SQL:2023<br/>dialect: write &lt;&gt;"]
D2 -->|"no: != in SQL:2023; ~~ !~~ ISNULL NOTNULL<br/>in both; BETWEEN SYMMETRIC in MySQL 8.4"| E2["!= is not part of the SQL:2023<br/>dialect: write #lt;#gt;"]
D2 -->|"yes"| A{"allowed by<br/>WithAllowedOperators?"}
A -->|"no"| E3["operator &quot;LIKE&quot; is not allowed"]
A -->|"no"| E3["operator #quot;LIKE#quot; is not allowed"]
A -->|"yes, or no allow-list"| OK["into the AST"]
E1 --> J["errors.Join: every problem"]
E2 --> J
Expand Down
2 changes: 1 addition & 1 deletion docs/error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ flowchart TD
P --> CONS{"entire input<br/>consumed?"}
CONS -->|"no"| ADD["add 'unexpected token' error"]
CONS -->|"yes"| Q
ADD --> Q{"len(errors) &gt; 0?"}
ADD --> Q{"len(errors) #gt; 0?"}
Q -->|"yes"| J["return errors.Join(…)<br/>of *QFVFilterError"]
Q -->|"no"| OK["return AST, nil"]
```
Expand Down
2 changes: 1 addition & 1 deletion docs/filtering.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ parses into this tree (precedence makes `AND` the root, with the parenthesized
graph TD
AND["BinaryOperatorNode<br/>AND"]
AND --> GRP["GroupNode<br/>( … )"]
AND --> GT["BinaryOperatorNode<br/>&gt;"]
AND --> GT["BinaryOperatorNode<br/>#gt;"]

GRP --> OR["BinaryOperatorNode<br/>OR"]
OR --> EQ1["BinaryOperatorNode<br/>="]
Expand Down
50 changes: 50 additions & 0 deletions docs_mermaid_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package qfv

import (
"os"
"path/filepath"
"regexp"
"testing"
)

// GitHub decodes HTML entities before it hands a diagram to Mermaid, so a
// label written with &quot; reaches Mermaid as a quote that ends the label:
// docs/dialects.md's checking diagram rendered as a parse error on GitHub,
// and as a diagram everywhere else. Mermaid's own entity codes (#quot;,
// #lt;, #gt;, #amp;) are left alone by GitHub and decoded by Mermaid.
func TestNoDiagramUsesAnHTMLEntity(t *testing.T) {
t.Parallel()

files, err := filepath.Glob("*.md")
if err != nil {
t.Fatal(err)
}

docs, err := filepath.Glob("docs/*.md")
if err != nil {
t.Fatal(err)
}

block := regexp.MustCompile("(?s)```mermaid\n(.*?)```")
entity := regexp.MustCompile(`&(quot|lt|gt|amp|#[0-9]+);`)
diagrams := 0

for _, f := range append(files, docs...) {
raw, err := os.ReadFile(f)
if err != nil {
t.Fatal(err)
}

for _, m := range block.FindAllStringSubmatch(string(raw), -1) {
diagrams++

if e := entity.FindString(m[1]); e != "" {
t.Errorf("%s: a diagram uses the HTML entity %s, which GitHub decodes before Mermaid parses it: write #%s", f, e, e[1:])
}
}
}

if diagrams < 10 {
t.Fatalf("read %d diagrams, want at least 10: the docs moved and this test reads nothing", diagrams)
}
}
Loading