-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Collapse output to 20 items #160
base: next
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 8d3d231 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Interesting considerations, thanks for the early update! I looked at the code and realized that I forgot to mention one important detail in the issue description. I originally envisioned this as a purely cosmetic thing rather than a linter feature, and as such, I planned that this functionality would be added to the pretty reporter rather than the linter core. This way, all reporters get the same full diagnostics, but some reporters might choose to hide some. The inspiration for this feature came from Biome, they also have a 20-diagnostic limit. Here's how they show it: That's why I don't think we should make this thing configurable or even disable-able. If one wants to see all diagnostics, I think it's not because they want to read all of them individually. For mass-reading of diagnostics, the JSON reporter is probably better. I suggest we write "X diagnostics were hidden, run with The severity consideration is a very good point, I agree that we probably want to sort the errors first and then, if there's space left, print warnings too. If there's a rule that has produced only warnings, then we only print its diagnostics if all the errors have been printed. |
Oh, yeah, actually it makes sense to make it a cosmetic thing and move |
Overall the code looks good, I only have minor concerns about over-abstracting — such as having an entire feature for this, and also making the quota a modifiable parameter. Seems like the code could be simpler by keeping it all in one function |
@illright Let me know if you think we must rephrase/change it somehow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for noticing the bundle size workflow issue, my mistake! I think we can replace everything that isn't /[0-9a-zA-Z-._]/
(ref) with -
to overcome this.
The solution is good overall, but slightly hard to understand, I made some suggestions to improve clarity, let me know what you think
const autofixable = collapsedDiagnostics.filter((d) => (d.fixes?.length ?? 0) > 0) | ||
if (autofixable.length === collapsedDiagnostics.length) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: if I understand correctly, this code will only report how many of the printed 20 diagnostics are fixable. This might be misleading because the autofix engine doesn't know about this collapsing, so it will apply more fixes than what's promised by the output
suggestion: I think we should count and apply fixes from all diagnostics, not just the collapsed ones
'\n' | ||
'\n ' + | ||
(collapsedDiagnosticsCount < initialDiagnosticsCount | ||
? `${pc.reset(initialDiagnosticsCount - collapsedDiagnosticsCount)} diagnostics are not shown in the report as they exceed the limit allowed by Steiger` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: yeah, I had an idea to actually tell people how to see all diagnostics instead of this technical "exceed the limit" stuff that Biome prints
? `${pc.reset(initialDiagnosticsCount - collapsedDiagnosticsCount)} diagnostics are not shown in the report as they exceed the limit allowed by Steiger` | |
? `${pc.reset(initialDiagnosticsCount - collapsedDiagnosticsCount)} diagnostics are not shown, use ${pc.bold(pc.green('--reporter json'))} to see them.` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: this will print "1 diagnostics" when only 1 diagnostic was hidden
suggestion: use the s
function (imported in this file) to conditionally pluralize the word
const quotaPerBucket = buckets.slice(0).fill(0) | ||
let remainingQuota = quota | ||
|
||
for (let i = 0; remainingQuota > 0; i += 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: the fact that this is a for
loop has made it quite difficult for me to understand the rest of the loop body. A for loop is meant to take a counter variable from A to B, but this one only specifies the A, so it's not a for loop in the traditional sense. Other strange things arise as a consequence, such as assigning i = -1
, which is not a valid index, but will be made valid by the mechanics of the for loop
suggestion: let's make this a while loop, I think it more accurately reflects what we're trying to do here:
while (there is quota left) {
assign one unit of quota
}
// If it ran out of the items earlier than the quota, break | ||
if (allItems === quota - remainingQuota) { | ||
break | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: this condition also broke my head for a solid couple of minutes :D
suggestion: instead of checking this on every iteration, let's instead assign remainingQuota = Math.min(quota, allItems)
, such that there is never more quota than the total number of items
return diagnostics.slice(0).sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]) | ||
} | ||
|
||
// Export for testing purposes to be able to pass a custom quota |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: I'm not a big fan of using one thing but testing another, it slightly undermines my confidence in the tests
suggestion: how about we make collapseDiagnostics
accept the quota as an argument, and move the 20
constant to src/index.ts
instead?
|
||
const defaultSeverity = 'error' as 'warn' | 'error' | ||
|
||
// dummy rules |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (non-blocking): how about we instead write a function to generate dummy diagnostics with a simple index in the message and then call it in the test setup? This way we can even test with quota = 20
function makeDiagnostic(ruleName: string, index: number): PartialDiagnostic
const diagnosticPerRule = [
new Array(15).fill(0).map((_, index) => makeDiagnostic('rule-1', index)),
new Array(10).fill(0).map((_, index) => makeDiagnostic('rule-2', index)),
]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And in the tests that actually drop some diagnostics, we can assert by doing diagnosticPerRule[0].slice(0, 5)
. This way we also test that it doesn't change the order of diagnostics within one rule
|
||
const result = trimDiagnosticsToMeetQuota(diagnosticPerRule, 3) | ||
|
||
expect(result).toEqual([[rule1Message1], [rule2Message1], [rule3Message1]]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: for some reason, this test fails for me locally because result
also includes an empty array at the end
Closes #51
The solution is still raw and it's an early PR, so you can see the general approach and we can clarify some details.
runRules
fromapp.ts
needs to return someReport
interface, so it contains not just diagnostics but also some meta info about them. We need this to display the number of shown vs hidden diagnostics etc. other fields may appear in the future.