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
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ extension MaintainerInfoIndex {
valueToCopy: badgeMarkdown(for: type))
}

func packageScoreCategories() -> Node<HTML.BodyContext> {
.forEach(0..<scoreCategories.count, { index in
static func packageScoreCategories(for categories: [PackageScore]) -> Node<HTML.BodyContext> {
return .forEach(0..<categories.count, { index in
.div(
.class("score-trait"),
.p("\(scoreCategories[index].title)"),
.p("\(scoreCategories[index].score) points"),
.p("\(scoreCategories[index].description)")
.p("\(categories[index].title)"),
.p("\(categories[index].score) points"),
.p("\(categories[index].description)")
Copy link
Member Author

@finestructure finestructure Mar 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is here - this function used the somewhat expensive scoreCategories multiple times and in a loop, leading to noticeably bad performance.

Making the function static makes it easy to re-use the externally computed value here. This way, there's no risk it can again accidentally be called multiple times without being aware of the cost.

)
})
}
Expand All @@ -66,7 +66,7 @@ extension MaintainerInfoIndex {
"https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/discussions/2591"
}

var scoreCategories: [PackageScore] {
func scoreCategories() -> [PackageScore] {
Copy link
Member Author

@finestructure finestructure Mar 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scoreCategories is not a cheap computation and it's best practice not to make them properties - sort of to signal that they're not cheap.

guard let scoreDetails else { return [] }
return Score.Category.allCases
.sorted { $0.title < $1.title }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ enum MaintainerInfoIndex {
}

override func content() -> Node<HTML.BodyContext> {
.div(
let scoreCategories = model.scoreCategories()
return .div(
.h2("Information for \(model.packageName) Maintainers"),
.p(
.text("Are you the author, or a maintainer of "),
Expand Down Expand Up @@ -188,15 +189,15 @@ enum MaintainerInfoIndex {
"This package has a total score of \(model.score) points. The Swift Package Index uses package score in combination with the relevancy of a search query to influence the ordering of search results."
),
.p(
"The score is currently evaluated based on \(model.scoreCategories.count) traits, and the breakdown of each trait is shown below."
"The score is currently evaluated based on \(scoreCategories.count) traits, and the breakdown of each trait is shown below."
),
.div(
.class("package-score"),
.text("Total – \(model.score) points")
),
.div(
.class("package-score-breakdown"),
model.packageScoreCategories()
Model.packageScoreCategories(for: scoreCategories)
),
.p(
"The package score is a work in progress. We have an ",
Expand Down
4 changes: 2 additions & 2 deletions Tests/AppTests/MaintainerInfoIndexModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ struct MaintainerInfoIndexModelTests {

do {
model.scoreDetails?.numberOfDependencies = 0
let categories = model.scoreCategories
let categories = model.scoreCategories()
#expect(categories["Dependencies"]?.description == "Has no dependencies.")
}
do {
model.scoreDetails?.numberOfDependencies = nil
let categories = model.scoreCategories
let categories = model.scoreCategories()
#expect(categories["Dependencies"]?.description == "No dependency information available.")
}
}
Expand Down
Loading