# core/producers/tool.clj-kondo.producer.ts

> 77 lines of code and 24 definitions.

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

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

## Definitions

- `withMeta` (lexical_declaration, line 32)
- `sectionsOf` (lexical_declaration, line 44)
- `TOOL` (lexical_declaration, line 6)
- `VERSION` (lexical_declaration, line 7)
- `SOURCE` (lexical_declaration, line 8)
- `DOCS` (lexical_declaration, line 9)
- `HEADER_PREFIX` (lexical_declaration, line 10)
- `Section` (interface_declaration, line 12)
- `backtickAfter` (lexical_declaration, line 19)
- `open` (lexical_declaration, line 21)
- `close` (lexical_declaration, line 22)
- `afterMarker` (lexical_declaration, line 26)
- `at` (lexical_declaration, line 27)
- `rest` (lexical_declaration, line 28)
- `keyword` (lexical_declaration, line 33)
- `description` (lexical_declaration, line 34)
- `level` (lexical_declaration, line 35)
- `sections` (lexical_declaration, line 45)
- `last` (lexical_declaration, line 51)
- `ruleOf` (lexical_declaration, line 59)
- `{ description, keyword, level, title }` (lexical_declaration, line 60)
- `produce` (lexical_declaration, line 80)
- `lines` (lexical_declaration, line 81)
- `rules` (lexical_declaration, line 82)

## Contained in

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

## Linked from

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

## Source

```typescript
import type { CatalogProduct, CatalogRule } from "#types/catalog.types";
import { byRuleId } from "#core/comparators/rule.comparator";
import { defineProducer } from "#core/registries/producer.registry";
import { remoteText } from "#core/adapters/remote.adapter";

const TOOL = "clj-kondo";
const VERSION = "master";
const SOURCE = "https://raw.githubusercontent.com/clj-kondo/clj-kondo/master/doc/linters.md";
const DOCS = "https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md";
const HEADER_PREFIX = "### ";

interface Section {
    title: string;
    keyword?: string;
    description?: string;
    level?: string;
}

const backtickAfter = function backtickAfter(line: string, marker: string): string | null {
    const at = line.indexOf(marker);
    const open = at === -1 ? -1 : line.indexOf("`", at + marker.length);
    const close = open === -1 ? -1 : line.indexOf("`", open + 1);
    return close === -1 ? null : line.slice(open + 1, close).trim();
};

const afterMarker = function afterMarker(line: string, marker: string): string | null {
    const at = line.indexOf(marker);
    const rest = at === -1 ? "" : line.slice(at + marker.length).trim();
    return rest === "" ? null : rest;
};

const withMeta = function withMeta(section: Section, line: string): Section {
    const keyword = backtickAfter(line, "*Keyword:*");
    const description = afterMarker(line, "*Description:*");
    const level = backtickAfter(line, "*Default level:*");
    return {
        ...section,
        ...(keyword === null ? {} : { keyword }),
        ...(description === null ? {} : { description }),
        ...(level === null ? {} : { level }),
    };
};

const sectionsOf = function sectionsOf(lines: readonly string[]): Section[] {
    const sections: Section[] = [];
    for (const line of lines) {
        if (line.startsWith(HEADER_PREFIX)) {
            sections.push({ title: line.slice(HEADER_PREFIX.length).trim() });
            continue;
        }
        const last = sections.pop();
        if (last) {
            sections.push(withMeta(last, line));
        }
    }
    return sections;
};

const ruleOf = function ruleOf(section: Section): CatalogRule[] {
    const { description, keyword, level, title } = section;
    if (keyword === undefined || keyword === "") {
        return [];
    }
    return [
        {
            canonical: null,
            category: "linter",
            defaultLevel: level === undefined || level === "" ? null : level,
            description: description === undefined || description === "" ? null : description,
            ecosystem: "clojure",
            name: title === "" ? keyword : title,
            ruleId: keyword,
            tool: TOOL,
            toolVersion: VERSION,
            url: DOCS,
        },
    ];
};

const produce = async function produce(): Promise<CatalogProduct[]> {
    const lines = ((await remoteText(SOURCE)) ?? "").split("\n");
    const rules = sectionsOf(lines).flatMap(ruleOf).toSorted(byRuleId);
    return [{ rules, source: TOOL, summary: { tool: TOOL, toolVersion: VERSION, total: rules.length } }];
};

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