From b3d6c0c564c1a79e54e5105d0a8b60fc58a2bdee Mon Sep 17 00:00:00 2001
From: Harshil Sharma <18575143+harshilsharma63@users.noreply.github.com>
Date: Tue, 2 Dec 2025 17:21:30 +0100
Subject: [PATCH] perf: apply perfpsrint linter (#33967) (#34632)
* perf: apply perfpsrint linter (#33967)
* perf: apply perfpsrint linter
* further simplifications
* improved TestParseHashtags coverage
* more simplifications
* simplify renderBlockHTML further
---------
Co-authored-by: Jesse Hallam
* Fixed a bad merge
---------
Co-authored-by: Catena cyber <35799796+catenacyber@users.noreply.github.com>
Co-authored-by: Jesse Hallam
---
server/public/model/utils.go | 11 +-
server/public/model/utils_test.go | 56 +++++++++-
server/public/shared/markdown/fenced_code.go | 7 +-
server/public/shared/markdown/html.go | 103 ++++++++++--------
.../public/shared/markdown/indented_code.go | 7 +-
.../shared/markdown/reference_definition.go | 7 +-
6 files changed, 131 insertions(+), 60 deletions(-)
diff --git a/server/public/model/utils.go b/server/public/model/utils.go
index 527828e26c..5ddadedd1d 100644
--- a/server/public/model/utils.go
+++ b/server/public/model/utils.go
@@ -717,8 +717,8 @@ var (
func ParseHashtags(text string) (string, string) {
words := strings.Fields(text)
- hashtagString := ""
- plainString := ""
+ var hashtagStringSb strings.Builder
+ var plainString strings.Builder
for _, word := range words {
// trim off surrounding punctuation
word = puncStart.ReplaceAllString(word, "")
@@ -728,11 +728,12 @@ func ParseHashtags(text string) (string, string) {
word = hashtagStart.ReplaceAllString(word, "#")
if validHashtag.MatchString(word) {
- hashtagString += " " + word
+ hashtagStringSb.WriteString(" " + word)
} else {
- plainString += " " + word
+ plainString.WriteString(" " + word)
}
}
+ hashtagString := hashtagStringSb.String()
if len(hashtagString) > 1000 {
hashtagString = hashtagString[:999]
@@ -744,7 +745,7 @@ func ParseHashtags(text string) (string, string) {
}
}
- return strings.TrimSpace(hashtagString), strings.TrimSpace(plainString)
+ return strings.TrimSpace(hashtagString), strings.TrimSpace(plainString.String())
}
func ClearMentionTags(post string) string {
diff --git a/server/public/model/utils_test.go b/server/public/model/utils_test.go
index 9865ce82c1..67ef4bab5f 100644
--- a/server/public/model/utils_test.go
+++ b/server/public/model/utils_test.go
@@ -541,10 +541,58 @@ func TestStringArray_Equal(t *testing.T) {
}
func TestParseHashtags(t *testing.T) {
- for input, output := range hashtags {
- o, _ := ParseHashtags(input)
- require.Equal(t, o, output, "failed to parse hashtags from input="+input+" expected="+output+" actual="+o)
- }
+ t.Run("basic hashtag extraction", func(t *testing.T) {
+ for input, output := range hashtags {
+ o, _ := ParseHashtags(input)
+ require.Equal(t, o, output, "failed to parse hashtags from input="+input+" expected="+output+" actual="+o)
+ }
+ })
+
+ t.Run("long hashtag string truncation", func(t *testing.T) {
+ // Test case where hashtag string exceeds 1000 characters with a space to truncate at
+ longHashtags := "#test " + strings.Repeat("#verylonghashtag ", 50)
+ hashtagString, plainString := ParseHashtags(longHashtags)
+ require.NotEmpty(t, hashtagString)
+ require.LessOrEqual(t, len(hashtagString), 1000)
+ require.Empty(t, plainString)
+ // Ensure it truncated at a space
+ require.NotEqual(t, "", hashtagString)
+ require.True(t, hashtagString[len(hashtagString)-1] != ' ')
+ })
+
+ t.Run("long hashtag string truncation without spaces", func(t *testing.T) {
+ // Test case where hashtag string exceeds 1000 characters with no space after position 999
+ // Create a single very long hashtag that will be truncated
+ veryLongHashtag := "#" + strings.Repeat("a", 1010)
+ hashtagString, plainString := ParseHashtags(veryLongHashtag)
+ // Should be empty because no space was found to truncate at
+ require.Equal(t, "", hashtagString)
+ require.Empty(t, plainString)
+ })
+
+ t.Run("plain text extraction", func(t *testing.T) {
+ hashtagString, plainString := ParseHashtags("hello #world this is #test plain text")
+ require.Equal(t, "#world #test", hashtagString)
+ require.Equal(t, "hello this is plain text", plainString)
+ })
+
+ t.Run("only plain text", func(t *testing.T) {
+ hashtagString, plainString := ParseHashtags("no hashtags here")
+ require.Empty(t, hashtagString)
+ require.Equal(t, "no hashtags here", plainString)
+ })
+
+ t.Run("only hashtags", func(t *testing.T) {
+ hashtagString, plainString := ParseHashtags("#one #two #three")
+ require.Equal(t, "#one #two #three", hashtagString)
+ require.Empty(t, plainString)
+ })
+
+ t.Run("empty string", func(t *testing.T) {
+ hashtagString, plainString := ParseHashtags("")
+ require.Empty(t, hashtagString)
+ require.Empty(t, plainString)
+ })
}
func TestIsValidAlphaNum(t *testing.T) {
diff --git a/server/public/shared/markdown/fenced_code.go b/server/public/shared/markdown/fenced_code.go
index c8caad5561..22f43bfd63 100644
--- a/server/public/shared/markdown/fenced_code.go
+++ b/server/public/shared/markdown/fenced_code.go
@@ -23,11 +23,12 @@ type FencedCode struct {
RawCode []FencedCodeLine
}
-func (b *FencedCode) Code() (result string) {
+func (b *FencedCode) Code() string {
+ var resultSb strings.Builder
for _, code := range b.RawCode {
- result += strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End]
+ resultSb.WriteString(strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End])
}
- return
+ return resultSb.String()
}
func (b *FencedCode) Info() string {
diff --git a/server/public/shared/markdown/html.go b/server/public/shared/markdown/html.go
index f15bfb664f..fb63c4198e 100644
--- a/server/public/shared/markdown/html.go
+++ b/server/public/shared/markdown/html.go
@@ -27,69 +27,75 @@ func RenderBlockHTML(block Block, referenceDefinitions []*ReferenceDefinition) (
return renderBlockHTML(block, referenceDefinitions, false)
}
-func renderBlockHTML(block Block, referenceDefinitions []*ReferenceDefinition, isTightList bool) (result string) {
+func renderBlockHTML(block Block, referenceDefinitions []*ReferenceDefinition, isTightList bool) string {
+ var resultSb strings.Builder
+
switch v := block.(type) {
case *Document:
for _, block := range v.Children {
- result += RenderBlockHTML(block, referenceDefinitions)
+ resultSb.WriteString(RenderBlockHTML(block, referenceDefinitions))
}
case *Paragraph:
if len(v.Text) == 0 {
- return
+ return ""
}
if !isTightList {
- result += ""
+ resultSb.WriteString("
")
}
for _, inline := range v.ParseInlines(referenceDefinitions) {
- result += RenderInlineHTML(inline)
+ resultSb.WriteString(RenderInlineHTML(inline))
}
if !isTightList {
- result += "
"
+ resultSb.WriteString("
")
}
case *List:
if v.IsOrdered {
if v.OrderedStart != 1 {
- result += fmt.Sprintf(``, v.OrderedStart)
+ resultSb.WriteString(fmt.Sprintf(``, v.OrderedStart))
} else {
- result += ""
+ resultSb.WriteString("")
}
} else {
- result += ""
+ resultSb.WriteString("")
}
for _, block := range v.Children {
- result += renderBlockHTML(block, referenceDefinitions, !v.IsLoose)
+ resultSb.WriteString(renderBlockHTML(block, referenceDefinitions, !v.IsLoose))
}
if v.IsOrdered {
- result += "
"
+ resultSb.WriteString("
")
} else {
- result += ""
+ resultSb.WriteString("")
}
case *ListItem:
- result += "- "
+ resultSb.WriteString("
- ")
for _, block := range v.Children {
- result += renderBlockHTML(block, referenceDefinitions, isTightList)
+ resultSb.WriteString(renderBlockHTML(block, referenceDefinitions, isTightList))
}
- result += "
"
+ resultSb.WriteString("")
case *BlockQuote:
- result += ""
+ resultSb.WriteString("")
for _, block := range v.Children {
- result += RenderBlockHTML(block, referenceDefinitions)
+ resultSb.WriteString(RenderBlockHTML(block, referenceDefinitions))
}
- result += "
"
+ resultSb.WriteString("
")
case *FencedCode:
if info := v.Info(); info != "" {
language := strings.Fields(info)[0]
- result += ``
+ resultSb.WriteString(``)
} else {
- result += ""
+ resultSb.WriteString("")
}
- result += htmlEscaper.Replace(v.Code()) + "
"
+ resultSb.WriteString(htmlEscaper.Replace(v.Code()))
+ resultSb.WriteString("
")
case *IndentedCode:
- result += "" + htmlEscaper.Replace(v.Code()) + "
"
+ resultSb.WriteString("")
+ resultSb.WriteString(htmlEscaper.Replace(v.Code()))
+ resultSb.WriteString("
")
default:
panic(fmt.Sprintf("missing case for type %T", v))
}
- return
+
+ return resultSb.String()
}
func escapeURL(url string) (result string) {
@@ -137,31 +143,37 @@ func RenderInlineHTML(inline Inline) (result string) {
}
result += ` />`
case *InlineLink:
- result += ``
+ resultSb.WriteString(`>`)
for _, inline := range v.Children {
- result += RenderInlineHTML(inline)
+ resultSb.WriteString(RenderInlineHTML(inline))
}
- result += ""
+ resultSb.WriteString("")
+ return resultSb.String()
case *ReferenceLink:
- result += ``
+ resultSb.WriteString(`>`)
for _, inline := range v.Children {
- result += RenderInlineHTML(inline)
+ resultSb.WriteString(RenderInlineHTML(inline))
}
- result += ""
+ resultSb.WriteString("")
+ return resultSb.String()
case *Autolink:
- result += ``
+ var resultSb strings.Builder
+ resultSb.WriteString(``)
for _, inline := range v.Children {
- result += RenderInlineHTML(inline)
+ resultSb.WriteString(RenderInlineHTML(inline))
}
- result += ""
+ resultSb.WriteString("")
+ return resultSb.String()
case *Emoji:
escapedName := htmlEscaper.Replace(v.Name)
result += fmt.Sprintf(``, escapedName, escapedName)
@@ -172,25 +184,30 @@ func RenderInlineHTML(inline Inline) (result string) {
return
}
-func renderImageAltText(children []Inline) (result string) {
+func renderImageAltText(children []Inline) string {
+ var resultSb strings.Builder
for _, inline := range children {
- result += renderImageChildAltText(inline)
+ resultSb.WriteString(renderImageChildAltText(inline))
}
- return
+ return resultSb.String()
}
-func renderImageChildAltText(inline Inline) (result string) {
+func renderImageChildAltText(inline Inline) string {
switch v := inline.(type) {
case *Text:
return v.Text
case *InlineImage:
+ var resultSb strings.Builder
for _, inline := range v.Children {
- result += renderImageChildAltText(inline)
+ resultSb.WriteString(renderImageChildAltText(inline))
}
+ return resultSb.String()
case *InlineLink:
+ var resultSb strings.Builder
for _, inline := range v.Children {
- result += renderImageChildAltText(inline)
+ resultSb.WriteString(renderImageChildAltText(inline))
}
+ return resultSb.String()
}
- return
+ return ""
}
diff --git a/server/public/shared/markdown/indented_code.go b/server/public/shared/markdown/indented_code.go
index a89ee6c70c..9a4a6b8212 100644
--- a/server/public/shared/markdown/indented_code.go
+++ b/server/public/shared/markdown/indented_code.go
@@ -19,11 +19,12 @@ type IndentedCode struct {
RawCode []IndentedCodeLine
}
-func (b *IndentedCode) Code() (result string) {
+func (b *IndentedCode) Code() string {
+ var resultSb strings.Builder
for _, code := range b.RawCode {
- result += strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End]
+ resultSb.WriteString(strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End])
}
- return
+ return resultSb.String()
}
func (b *IndentedCode) Continuation(indentation int, r Range) *continuation {
diff --git a/server/public/shared/markdown/reference_definition.go b/server/public/shared/markdown/reference_definition.go
index 69e8ed9401..1c40cf83a1 100644
--- a/server/public/shared/markdown/reference_definition.go
+++ b/server/public/shared/markdown/reference_definition.go
@@ -3,6 +3,8 @@
package markdown
+import "strings"
+
type ReferenceDefinition struct {
RawDestination Range
@@ -24,10 +26,11 @@ func (d *ReferenceDefinition) Title() string {
}
func parseReferenceDefinition(markdown string, ranges []Range) (*ReferenceDefinition, []Range) {
- raw := ""
+ var rawSb strings.Builder
for _, r := range ranges {
- raw += markdown[r.Position:r.End]
+ rawSb.WriteString(markdown[r.Position:r.End])
}
+ raw := rawSb.String()
label, next, ok := parseLinkLabel(raw, 0)
if !ok {