fix(docs): pair comment ids with the document order (#92) #93
+4
-6
@@ -65,6 +65,7 @@ func InjectDocxComments(src []byte, author string, comments []DocxComment) ([]by
|
|||||||
}
|
}
|
||||||
|
|
||||||
used := make([]bool, len(comments))
|
used := make([]bool, len(comments))
|
||||||
|
applied := make([]DocxComment, 0, len(comments))
|
||||||
id := 0
|
id := 0
|
||||||
newDoc := docxParaRe.ReplaceAllStringFunc(string(doc), func(p string) string {
|
newDoc := docxParaRe.ReplaceAllStringFunc(string(doc), func(p string) string {
|
||||||
txt := docxPlain(p)
|
txt := docxPlain(p)
|
||||||
@@ -73,6 +74,9 @@ func InjectDocxComments(src []byte, author string, comments []DocxComment) ([]by
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
used[i] = true
|
used[i] = true
|
||||||
|
// Record in document order so comments.xml id N matches the marker
|
||||||
|
// with id N (the spec order may differ from the document order).
|
||||||
|
applied = append(applied, c)
|
||||||
p = docxAddMarkers(p, id)
|
p = docxAddMarkers(p, id)
|
||||||
id++
|
id++
|
||||||
break
|
break
|
||||||
@@ -80,12 +84,6 @@ func InjectDocxComments(src []byte, author string, comments []DocxComment) ([]by
|
|||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
applied := make([]DocxComment, 0, len(comments))
|
|
||||||
for i, c := range comments {
|
|
||||||
if used[i] {
|
|
||||||
applied = append(applied, c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parts["word/document.xml"] = []byte(newDoc)
|
parts["word/document.xml"] = []byte(newDoc)
|
||||||
parts["word/comments.xml"] = docxBuildComments(author, applied)
|
parts["word/comments.xml"] = docxBuildComments(author, applied)
|
||||||
parts["[Content_Types].xml"] = docxAddContentType(parts["[Content_Types].xml"])
|
parts["[Content_Types].xml"] = docxAddContentType(parts["[Content_Types].xml"])
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -124,6 +125,48 @@ func TestInjectDocxCommentsNoMatch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestInjectDocxCommentsOrder guards the marker-id ↔ comments.xml pairing when
|
||||||
|
// the spec order differs from the document order.
|
||||||
|
func TestInjectDocxCommentsOrder(t *testing.T) {
|
||||||
|
src := buildTestDocx(t)
|
||||||
|
spec := []DocxComment{
|
||||||
|
{Anchor: "Nothing relevant", Text: "comment B"},
|
||||||
|
{Anchor: "The term is two years", Text: "comment A"},
|
||||||
|
}
|
||||||
|
out, applied, err := InjectDocxComments(src, "A", spec)
|
||||||
|
if err != nil || applied != 2 {
|
||||||
|
t.Fatalf("inject: applied=%d err=%v", applied, err)
|
||||||
|
}
|
||||||
|
doc := unzipPart(t, out, "word/document.xml")
|
||||||
|
cmts := unzipPart(t, out, "word/comments.xml")
|
||||||
|
|
||||||
|
// id -> text from comments.xml
|
||||||
|
byID := map[string]string{}
|
||||||
|
for _, m := range regexp.MustCompile(`(?s)<w:comment w:id="(\d+)"[^>]*>(.*?)</w:comment>`).FindAllStringSubmatch(cmts, -1) {
|
||||||
|
txt := strings.TrimSpace(stripTags(m[2]))
|
||||||
|
byID[m[1]] = txt
|
||||||
|
}
|
||||||
|
// paragraph that starts with the term text must point at "comment A"
|
||||||
|
for _, p := range regexp.MustCompile(`(?s)<w:p\b[^>]*>.*?</w:p>`).FindAllString(doc, -1) {
|
||||||
|
if !strings.Contains(stripTags(p), "The term is two years") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m := regexp.MustCompile(`<w:commentRangeStart w:id="(\d+)"/>`).FindStringSubmatch(p)
|
||||||
|
if m == nil {
|
||||||
|
t.Fatal("no commentRangeStart in the term paragraph")
|
||||||
|
}
|
||||||
|
if got := byID[m[1]]; got != "comment A" {
|
||||||
|
t.Fatalf("term paragraph points at id %s = %q, want \"comment A\"", m[1], got)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Fatal("term paragraph not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func stripTags(s string) string {
|
||||||
|
return regexp.MustCompile(`<[^>]*>`).ReplaceAllString(s, "")
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseDocxComments(t *testing.T) {
|
func TestParseDocxComments(t *testing.T) {
|
||||||
got, err := ParseDocxComments([]byte(`[{"anchor":"a","text":"b"}]`))
|
got, err := ParseDocxComments([]byte(`[{"anchor":"a","text":"b"}]`))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user