# core/producers/tool.clippy.producer.ts

> 179 lines of code and 47 definitions.

Tree: GovLab Quality
Language: typescript
Layer: application
Canonical: https://banes-lab.com/anatomy/quality#file-quality-core-producers-tool-clippy-producer-ts
Source text: https://banes-lab.com/source/quality/core/producers/tool.clippy.producer.ts.txt

Listed in [core/producers](https://banes-lab.com/api/source/quality/core/producers.md), after [core/producers/tool.clang-tidy.producer.ts](https://banes-lab.com/source/quality/core/producers/tool.clang-tidy.producer.ts.md) and before [core/producers/tool.clj-kondo.producer.ts](https://banes-lab.com/source/quality/core/producers/tool.clj-kondo.producer.ts.md).

## Definitions

- `productOf` (lexical_declaration, line 125)
- `groupMembers` (lexical_declaration, line 78)
- `lintEntries` (lexical_declaration, line 156)
- `skipSpaces` (lexical_declaration, line 28)
- `parseCheckLine` (lexical_declaration, line 59)
- `toUnderscore` (lexical_declaration, line 68)
- `sectionLines` (lexical_declaration, line 72)
- `produce` (lexical_declaration, line 139)
- `checksOf` (lexical_declaration, line 144)
- `splitColumns` (lexical_declaration, line 44)
- `groupOf` (lexical_declaration, line 91)
- `knobs` (lexical_declaration, line 181)
- `CLIPPY` (lexical_declaration, line 11)
- `RUSTC` (lexical_declaration, line 12)
- `DRIVER` (lexical_declaration, line 13)
- `CLIPPY_PREFIX` (lexical_declaration, line 14)
- `CLIPPY_DOCS` (lexical_declaration, line 15)
- `CONF_SOURCE` (lexical_declaration, line 16)
- `LINTS_OPEN` (lexical_declaration, line 17)
- `LINTS_CLOSE` (lexical_declaration, line 18)
- `FIELD_WINDOW` (lexical_declaration, line 19)
- `MIN_COLS` (lexical_declaration, line 20)
- `CheckLine` (interface_declaration, line 22)
- `columnEnd` (lexical_declaration, line 36)
- `i` (lexical_declaration, line 46)
- `end` (lexical_declaration, line 48)
- `isTableRow` (lexical_declaration, line 55)
- `cols` (lexical_declaration, line 60)
- `meaning` (lexical_declaration, line 64)
- `from` (lexical_declaration, line 73)
- `to` (lexical_declaration, line 74)
- `build` (lexical_declaration, line 100)
- `id` (lexical_declaration, line 107)
- `short` (lexical_declaration, line 108)
- `version` (lexical_declaration, line 140)
- `lines` (lexical_declaration, line 141)
- `context` (lexical_declaration, line 146)
- `clippy` (lexical_declaration, line 147)
- `rustc` (lexical_declaration, line 152)
- `colon` (lexical_declaration, line 157)
- `eq` (lexical_declaration, line 158)
- `def` (lexical_declaration, line 159)
- `field` (lexical_declaration, line 163)
- `text` (lexical_declaration, line 182)
- `entries` (lexical_declaration, line 183)
- `open` (lexical_declaration, line 184)
- `close` (lexical_declaration, line 186)

## Contained in

- [core/producers](https://banes-lab.com/anatomy/quality/folder-quality-core-producers.md)

## Uses

- [core/aggregators/catalog.aggregator.ts](https://banes-lab.com/source/quality/core/aggregators/catalog.aggregator.ts.md)
- [core/predicates/knob.predicate.ts](https://banes-lab.com/source/quality/core/predicates/knob.predicate.ts.md)

## Linked from

- [core/aggregators](https://banes-lab.com/anatomy/quality/folder-quality-core-aggregators.md)
- [core/predicates](https://banes-lab.com/anatomy/quality/folder-quality-core-predicates.md)
- [core/producers](https://banes-lab.com/anatomy/quality/folder-quality-core-producers.md)

## Source

```typescript
import type { CatalogProduct, CatalogRule, KnobEntry } from "#types/catalog.types";
import { commandOutput, commandVersion } from "#core/adapters/invocation.adapter";
import { intAt, trailingIdentifier } from "#core/parsers/knob.parser";
import { INTEGER_TYPE } from "#configuration/constants/knob.constants";
import { byRuleId } from "#core/comparators/rule.comparator";
import { defineProducer } from "#core/registries/producer.registry";
import { isThreshold } from "#core/predicates/knob.predicate";
import { remoteText } from "#core/adapters/remote.adapter";
import { tallyBy } from "#core/aggregators/catalog.aggregator";

const CLIPPY = "clippy";
const RUSTC = "rustc";
const DRIVER = "clippy-driver";
const CLIPPY_PREFIX = "clippy::";
const CLIPPY_DOCS = "https://rust-lang.github.io/rust-clippy/master/#";
const CONF_SOURCE = "https://raw.githubusercontent.com/rust-lang/rust-clippy/master/clippy_config/src/conf.rs";
const LINTS_OPEN = "#[lints(";
const LINTS_CLOSE = ")]";
const FIELD_WINDOW = 200;
const MIN_COLS = 2;

interface CheckLine {
    level: string;
    meaning: string | null;
    name: string;
}

const skipSpaces = function skipSpaces(text: string, start: number): number {
    let i = start;
    while (i < text.length && text[i] === " ") {
        i += 1;
    }
    return i;
};

const columnEnd = function columnEnd(text: string, start: number): number {
    let i = start;
    while (i < text.length && !(text[i] === " " && text[i + 1] === " ")) {
        i += 1;
    }
    return i;
};

const splitColumns = function splitColumns(text: string): string[] {
    const cols: string[] = [];
    let i = skipSpaces(text, 0);
    while (i < text.length) {
        const end = columnEnd(text, i);
        cols.push(text.slice(i, end).trimEnd());
        i = skipSpaces(text, end);
    }
    return cols;
};

const isTableRow = function isTableRow(text: string): boolean {
    return text.length > 0 && !text.startsWith("name") && !text.startsWith("----");
};

const parseCheckLine = function parseCheckLine(text: string): CheckLine | null {
    const cols = isTableRow(text) ? splitColumns(text) : [];
    if (cols.length < MIN_COLS) {
        return null;
    }
    const meaning = cols.slice(MIN_COLS).join(" ");
    return { level: cols[1] ?? "", meaning: meaning === "" ? null : meaning, name: cols[0] ?? "" };
};

const toUnderscore = function toUnderscore(name: string): string {
    return name.split("-").join("_");
};

const sectionLines = function sectionLines(lines: readonly string[], start: string, end: string): string[] {
    const from = lines.findIndex((line) => line.trim() === start);
    const to = end === "" ? lines.length : lines.findIndex((line) => line.trim() === end);
    return to === -1 ? [] : lines.slice(from + 1, to).map((line) => line.trim());
};

const groupMembers = function groupMembers(group: string, rest: readonly string[]): [string, string][] {
    if (rest.length === 0 || group === "clippy::all") {
        return [];
    }
    const short = group.startsWith(CLIPPY_PREFIX) ? group.slice(CLIPPY_PREFIX.length) : group;
    return rest
        .join(" ")
        .split(",")
        .map((member) => toUnderscore(member.trim()))
        .filter((id) => id.length > 0)
        .map((id): [string, string] => [id, short]);
};

const groupOf = function groupOf(lines: readonly string[]): Map<string, string> {
    return new Map(
        lines
            .filter(isTableRow)
            .map(splitColumns)
            .flatMap(([group = "", ...rest]) => groupMembers(group, rest)),
    );
};

const build = function build(
    checks: readonly CheckLine[],
    tool: string,
    context: { groups: Map<string, string>; version: string },
): CatalogRule[] {
    return checks
        .map((check): CatalogRule => {
            const id = toUnderscore(check.name);
            const short = id.startsWith(CLIPPY_PREFIX) ? id.slice(CLIPPY_PREFIX.length) : id;
            return {
                canonical: null,
                category: tool === CLIPPY ? (context.groups.get(id) ?? CLIPPY) : RUSTC,
                defaultLevel: check.level,
                description: check.meaning,
                ecosystem: "rust",
                name: short,
                ruleId: id,
                tool,
                toolVersion: context.version,
                url: tool === CLIPPY ? `${CLIPPY_DOCS}/${short}` : null,
            };
        })
        .toSorted(byRuleId);
};

const productOf = function productOf(tool: string, rules: CatalogRule[], version: string): CatalogProduct {
    return {
        rules,
        source: tool,
        summary: {
            byCategory: tallyBy(rules, "category"),
            byLevel: tallyBy(rules, "defaultLevel"),
            tool,
            toolVersion: version,
            total: rules.length,
        },
    };
};

const produce = async function produce(): Promise<CatalogProduct[]> {
    const version = commandVersion(DRIVER, ["--version"]);
    const lines = commandOutput(DRIVER, ["-Whelp"])
        .split("\n")
        .map((line) => (line.endsWith("\r") ? line.slice(0, -1) : line));
    const checksOf = (start: string, end: string): CheckLine[] =>
        sectionLines(lines, start, end).flatMap((line) => parseCheckLine(line) ?? []);
    const context = { groups: groupOf(sectionLines(lines, "Lint groups loaded by this crate:", "")), version };
    const clippy = build(
        checksOf("Lint checks loaded by this crate:", "Lint groups loaded by this crate:"),
        CLIPPY,
        context,
    );
    const rustc = build(checksOf("Lint checks provided by rustc:", "Lint groups provided by rustc:"), RUSTC, context);
    return [productOf(CLIPPY, clippy, version), productOf(RUSTC, rustc, version)];
};

const lintEntries = function lintEntries(text: string, open: number, close: number): KnobEntry[] {
    const colon = text.indexOf(":", close);
    const eq = text.indexOf("=", colon);
    const def = colon !== -1 && eq !== -1 && eq - close <= FIELD_WINDOW ? intAt(text, eq + 1) : null;
    if (def === null) {
        return [];
    }
    const field = trailingIdentifier(text.slice(close + LINTS_CLOSE.length, colon));
    return text
        .slice(open + LINTS_OPEN.length, close)
        .split(",")
        .map((lint) => lint.trim())
        .filter(Boolean)
        .map((lint): KnobEntry => [
            CLIPPY,
            `${CLIPPY_PREFIX}${lint}`,
            {
                default: def,
                knob: field === "" ? "threshold" : field,
                threshold: isThreshold(field),
                type: INTEGER_TYPE,
            },
        ]);
};

const knobs = async function knobs(): Promise<KnobEntry[]> {
    const text = (await remoteText(CONF_SOURCE)) ?? "";
    const entries: KnobEntry[] = [];
    let open = text.indexOf(LINTS_OPEN);
    while (open >= 0) {
        const close = text.indexOf(LINTS_CLOSE, open);
        if (close === -1) {
            return entries;
        }
        entries.push(...lintEntries(text, open, close));
        open = text.indexOf(LINTS_OPEN, close + LINTS_CLOSE.length);
    }
    return entries;
};

defineProducer({ knobs, name: CLIPPY, produce, refresh: "manual" });
```
