# core/adapters/stylelint.adapter.ts

> 66 lines of code and 16 definitions.

Tree: GovLab Quality
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/quality#file-quality-core-adapters-stylelint-adapter-ts
Source text: https://banes-lab.com/source/quality/core/adapters/stylelint.adapter.ts.txt

Listed in [core/adapters](https://banes-lab.com/api/source/quality/core/adapters.md), after [core/adapters/remote.adapter.ts](https://banes-lab.com/source/quality/core/adapters/remote.adapter.ts.md) and before [core/adapters/tool.actionlint.adapter.ts](https://banes-lab.com/source/quality/core/adapters/tool.actionlint.adapter.ts.md).

## Definitions

- `govlabStylelintConfig` (lexical_declaration, line 22, exported)
- `SECTION` (lexical_declaration, line 20)
- `config` (lexical_declaration, line 23, exported)
- `section` (lexical_declaration, line 24, exported)
- `base` (lexical_declaration, line 25, exported)
- `ownRules` (lexical_declaration, line 26, exported)
- `typeSystem` (lexical_declaration, line 27, exported)
- `concerns` (lexical_declaration, line 28, exported)
- `emitted` (lexical_declaration, line 29, exported)
- `axes` (lexical_declaration, line 30, exported)
- `userPlugins` (lexical_declaration, line 34, exported)
- `rules` (lexical_declaration, line 35, exported)
- `basePlugins` (lexical_declaration, line 36, exported)
- `runStylelint` (lexical_declaration, line 45)
- `result` (lexical_declaration, line 46)
- `findings` (lexical_declaration, line 54)

## Contained in

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

## Uses

- [core/converters/stylelint.converter.ts](https://banes-lab.com/source/quality/core/converters/stylelint.converter.ts.md)
- [core/registries/stylelint.registry.ts](https://banes-lab.com/source/quality/core/registries/stylelint.registry.ts.md)
- [core/selectors/exclusions.selector.ts](https://banes-lab.com/source/quality/core/selectors/exclusions.selector.ts.md)

## Linked from

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

## Source

```typescript
import { arrayField, isRecord, stringArrayField } from "#core/selectors/record.selector";
import type { RunResult } from "#types/finding.types";
import type { RunnerContext } from "#types/tool.types";
import { axisPluginsFor } from "#core/factories/axis.factory";
import { defineTool } from "#core/registries/tool.registry";
import { emitStylelintConfig } from "#core/emitters/stylelint.emitter";
import govlabStylelintPlugins from "#core/plugins/stylelint.plugin";
import { loadGovlabConfig } from "#core/loaders/config.loader";
import { loadUserPlugins } from "#core/loaders/plugin.loader";
import process from "node:process";
import { registerCanon } from "#core/registries/stylelint.registry";
import { sectionOf } from "#core/selectors/config.selector";
import stylelint from "stylelint";
import { toolFinding } from "#core/factories/finding.factory";
import { typeSystemRuleOptions } from "#core/converters/stylelint.converter";
import { validConcepts } from "#core/selectors/concept.selector";
import { validateConcerns } from "#core/validators/concern.validator";
import { withMasterExclude } from "#core/selectors/exclusions.selector";

const SECTION = "stylelint";

export const govlabStylelintConfig = async (consumerRoot: string = process.cwd()): Promise<Record<string, unknown>> => {
    const config = await loadGovlabConfig(consumerRoot);
    const section = sectionOf(config, SECTION);
    const base = isRecord(section["base"]) ? section["base"] : {};
    const ownRules = isRecord(section["rules"]) ? section["rules"] : {};
    const typeSystem = config.eslint?.layout?.typeSystem;
    const concerns = validateConcerns(config.qualityMaster?.concerns ?? {}, validConcepts());
    const emitted = emitStylelintConfig({ concerns, exclude: stringArrayField(section, "exclude") });
    const axes = axisPluginsFor(typeSystem);
    for (const meta of axes.meta) {
        registerCanon(meta);
    }
    const userPlugins = await loadUserPlugins(consumerRoot, { allowGlobal: config.extensions?.global ?? false });
    const rules = { ...emitted, ...ownRules };
    const basePlugins = arrayField(base, "plugins");
    return {
        ...base,
        ignoreFiles: withMasterExclude(config, stringArrayField(base, "ignoreFiles")),
        plugins: [...basePlugins, ...govlabStylelintPlugins, ...axes.plugins, ...userPlugins.stylelint],
        rules: { ...rules, ...typeSystemRuleOptions(typeSystem, rules), ...axes.rules },
    };
};

const runStylelint = async function runStylelint(context: RunnerContext): Promise<RunResult> {
    const result = await stylelint.lint({
        allowEmptyInput: true,
        config: await govlabStylelintConfig(context.root),
        cwd: context.root,
        files: context.paths,
        fix: context.fix,
        formatter: "string",
    });
    const findings = result.results.flatMap((fileResult) =>
        fileResult.warnings.map((warning) =>
            toolFinding({
                column: warning.column,
                ecosystem: context.ecosystem,
                file: fileResult.source ?? "",
                line: warning.line,
                message: warning.text,
                ruleId: warning.rule,
                tool: SECTION,
            }),
        ),
    );
    return { findings, fixedCount: 0, output: result.report };
};

defineTool({ ecosystems: ["css"], run: runStylelint, tool: SECTION });
```
