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
8 changes: 7 additions & 1 deletion docs/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ herb-lint --all-rules app/views/

Since the two flags pull in opposite directions, `--all-rules` and `--only` can't be combined.

Both flags also lower the [`logLevel`](#linter-options) for that run, down to the lowest severity that came up, so the rules you asked to run always get reported instead of being filtered out of the output. Passing `--log-level` explicitly keeps the level you gave it. The summary says so whenever it happens:

```
Log level hint | lowered from warning by --only
```

## Linter Configuration

Configure the linter behavior and rules:
Expand Down Expand Up @@ -184,7 +190,7 @@ Both `include` and `exclude` patterns are **additive**, they add to the defaults

- **`enabled`**: `true` or `false` - Enable or disable the linter globally
- **`failLevel`** <Badge type="info" text="v0.8.7+" />: `error`, `warning`, `info`, or `hint` - Exit with error code when diagnostics of this severity or higher are present (default: `error`). Useful for CI/CD pipelines where you want stricter enforcement. Can also be set via `--fail-level` CLI flag.
- **`logLevel`** <Badge type="info" text="^0.11.0" />: `error`, `warning`, `info`, or `hint` - Only report diagnostics of this severity or higher (default: `hint`, meaning everything is reported). This affects the CLI output only: lower-severity offenses are still counted in the summary, still respected by `failLevel`, and still shown in your editor, they just aren't printed individually or annotated in CI. Useful for keeping CI output focused on what matters. To hide a rule in the editor as well, use the rule's `severity` option with separate `editor` and `cli` values. Can also be set via `--log-level` CLI flag.
- **`logLevel`** <Badge type="info" text="^0.11.0" />: `error`, `warning`, `info`, or `hint` - Only report diagnostics of this severity or higher (default: `hint`, meaning everything is reported). This affects the CLI output only: lower-severity offenses are still counted in the summary, still respected by `failLevel`, and still shown in your editor, they just aren't printed individually or annotated in CI. Useful for keeping CI output focused on what matters. To hide a rule in the editor as well, use the rule's `severity` option with separate `editor` and `cli` values. Can also be set via `--log-level` CLI flag. Runs that pick their own rules with `--only` or `--all-rules` lower this level automatically, unless `--log-level` is passed explicitly.
- **`include`**: Array of glob patterns - Additional file patterns to lint (additive to defaults)
- **`exclude`**: Array of glob patterns - Additional patterns to exclude from linting (additive to defaults)

Expand Down
31 changes: 29 additions & 2 deletions javascript/packages/linter/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { version } from "../package.json"
import type { DiagnosticSeverity } from "@herb-tools/core"
import type { ProcessingContext } from "./cli/file-processor.js"
import type { FormatOption } from "./cli/argument-parser.js"
import type { RuleFilterFlag } from "./cli/summary-reporter.js"

export * from "./cli/index.js"

Expand Down Expand Up @@ -149,6 +150,25 @@ export class CLI {
// Hook for subclasses to add custom output after processing
}

/**
* Returns the severity `--only` or `--all-rules` should lower the log level to, together with the flag
* that asked for it, or `undefined` when the log level stays as configured.
*/
protected loweredLogLevel(counts: Record<DiagnosticSeverity, number>, effectiveLogLevel: DiagnosticSeverity, options: { only?: string[], allRules?: boolean, logLevelFlag?: DiagnosticSeverity }): { severity: DiagnosticSeverity, flag: RuleFilterFlag } | undefined {
const { only, allRules, logLevelFlag } = options
const flag: RuleFilterFlag | undefined = (only && only.length > 0) ? "--only" : (allRules ? "--all-rules" : undefined)

if (!flag) return undefined
if (logLevelFlag !== undefined) return undefined

const lowestSeverity = DIAGNOSTIC_SEVERITIES.filter(severity => counts[severity] > 0).pop()

if (!lowestSeverity) return undefined
if (meetsSeverityThreshold(lowestSeverity, effectiveLogLevel)) return undefined

return { severity: lowestSeverity, flag }
}

async run() {
await Herb.load()

Expand Down Expand Up @@ -472,15 +492,22 @@ export class CLI {

const results = await this.fileProcessor.processFiles(files, formatOption, context)

await this.outputManager.outputResults({ ...results, files }, outputOptions)

const counts: Record<DiagnosticSeverity, number> = {
error: results.totalErrors,
warning: results.totalWarnings,
info: results.totalInfo,
hint: results.totalHints
}

const lowered = this.loweredLogLevel(counts, effectiveLogLevel, { only, allRules, logLevelFlag: logLevel })

await this.outputManager.outputResults({ ...results, files }, {
...outputOptions,
logLevel: lowered?.severity ?? effectiveLogLevel,
logLevelLoweredFrom: lowered ? effectiveLogLevel : undefined,
logLevelLoweredBy: lowered?.flag
})

const showTips = formatOption !== 'json' && !useGitHubActions

if (!Config.exists(this.projectPath) && showTips) {
Expand Down
1 change: 1 addition & 0 deletions javascript/packages/linter/src/cli/argument-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export class ArgumentParser {
--log-level <severity> only report diagnostics of this severity or higher (error|warning|info|hint) [default: hint]
lower-severity offenses are still counted in the summary, but aren't
printed or annotated in CI
--only and --all-rules lower this level unless it's passed explicitly
--format output format (simple|detailed|json) [default: detailed]
--simple use simple output format (shortcut for --format simple)
--json use JSON output format (shortcut for --format json)
Expand Down
6 changes: 5 additions & 1 deletion javascript/packages/linter/src/cli/output-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { DiagnosticSeverity } from "@herb-tools/core"
import type { ThemeInput } from "@herb-tools/highlighter"
import type { FormatOption } from "./argument-parser.js"
import type { ProcessedFile, ProcessingResult } from "./file-processor.js"
import type { SummaryData } from "./summary-reporter.js"
import type { SummaryData, RuleFilterFlag } from "./summary-reporter.js"

interface OutputOptions {
formatOption: FormatOption
Expand All @@ -21,6 +21,8 @@ interface OutputOptions {
toolVersion?: string
failLevel?: DiagnosticSeverity
logLevel?: DiagnosticSeverity
logLevelLoweredFrom?: DiagnosticSeverity
logLevelLoweredBy?: RuleFilterFlag
}

interface LintResults extends ProcessingResult {
Expand Down Expand Up @@ -137,6 +139,8 @@ export class OutputManager {
filesNotFailing: notFailingFiles.size,
failLevel,
logLevel,
logLevelLoweredFrom: options.logLevelLoweredFrom,
logLevelLoweredBy: options.logLevelLoweredBy,
ruleCount,
startTime: options.startTime,
startDate: options.startDate,
Expand Down
11 changes: 11 additions & 0 deletions javascript/packages/linter/src/cli/summary-reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const SEVERITY_COLORS: Record<DiagnosticSeverity, "brightRed" | "brightYellow" |
hint: "gray"
}

export type RuleFilterFlag = "--only" | "--all-rules"

export interface SummaryData {
files: string[]
totalErrors: number
Expand All @@ -26,6 +28,8 @@ export interface SummaryData {
filesNotFailing?: number
failLevel?: DiagnosticSeverity
logLevel?: DiagnosticSeverity
logLevelLoweredFrom?: DiagnosticSeverity
logLevelLoweredBy?: RuleFilterFlag
ruleCount: number
startTime: number
startDate: Date
Expand Down Expand Up @@ -169,6 +173,13 @@ export class SummaryReporter {
console.log(` ${colorize(pad("Not shown"), "gray")} ${colorize(colorize(message, "gray"), "bold")}`)
}

if (data.logLevelLoweredFrom && data.logLevelLoweredBy) {
const level = colorize(colorize(logLevel, SEVERITY_COLORS[logLevel]), "bold")
const reason = colorize(`lowered from ${data.logLevelLoweredFrom} by ${data.logLevelLoweredBy}`, "cyan")

console.log(` ${colorize(pad("Log level"), "gray")} ${level} | ${reason}`)
}

if (ignoreDisableComments && totalWouldBeIgnored && totalWouldBeIgnored > 0) {
const message = `${colorize(colorize(`${totalWouldBeIgnored} additional ${this.pluralize(totalWouldBeIgnored, "offense")} reported (would have been ignored)`, "cyan"), "bold")}`
console.log(` ${colorize(pad("Note"), "gray")} ${message}`)
Expand Down
121 changes: 121 additions & 0 deletions javascript/packages/linter/test/__snapshots__/cli.test.ts.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading