# core/validators/css.viewport.validator.ts

> 62 lines of code and 8 definitions.

Tree: GovLab Quality
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/quality#file-quality-core-validators-css-viewport-validator-ts
Source text: https://banes-lab.com/source/quality/core/validators/css.viewport.validator.ts.txt

Listed in [core/validators](https://banes-lab.com/api/source/quality/core/validators.md), after [core/validators/css.validator.ts](https://banes-lab.com/source/quality/core/validators/css.validator.ts.md) and before [core/validators/dependency.validator.ts](https://banes-lab.com/source/quality/core/validators/dependency.validator.ts.md).

## Definitions

- `basename` (lexical_declaration, line 15)
- `mobileFinding` (lexical_declaration, line 20)
- `validate` (method_definition, line 59)
- `RULE_ID` (lexical_declaration, line 13)
- `normalized` (lexical_declaration, line 16)
- `name` (lexical_declaration, line 24)
- `baseName` (lexical_declaration, line 28)
- `ctx` (lexical_declaration, line 60)

## Contained in

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

## Uses

- [configuration/strings/validation.strings.ts](https://banes-lab.com/source/quality/configuration/strings/validation.strings.ts.md)
- [core/factories/finding.factory.ts](https://banes-lab.com/source/quality/core/factories/finding.factory.ts.md)

## Used by

- [core/loaders/config.loader.ts](https://banes-lab.com/source/quality/core/loaders/config.loader.ts.md)
- [core/matchers/exclusions.matcher.ts](https://banes-lab.com/source/quality/core/matchers/exclusions.matcher.ts.md)

## Linked from

- [configuration/strings](https://banes-lab.com/anatomy/quality/folder-quality-configuration-strings.md)
- [core/factories](https://banes-lab.com/anatomy/quality/folder-quality-core-factories.md)
- [core/loaders](https://banes-lab.com/anatomy/quality/folder-quality-core-loaders.md)
- [core/matchers](https://banes-lab.com/anatomy/quality/folder-quality-core-matchers.md)
- [core/validators](https://banes-lab.com/anatomy/quality/folder-quality-core-validators.md)

## Source

```typescript
import { CSS_EXTENSIONS, MOBILE_SUFFIX } from "#configuration/constants/validation.constants";
import {
    mobileNotImported,
    mobileNotImportedFix,
    mobileWithoutBase,
    mobileWithoutBaseFix,
} from "#configuration/strings/validation.strings";
import type { FileInput } from "#types/validation.types";
import type { Finding } from "#types/finding.types";
import { defineValidator } from "#core/registries/validation.registry";
import { projectFinding } from "#core/factories/finding.factory";

const RULE_ID = "css-mobile-imports";

const basename = function basename(path: string): string {
    const normalized = path.split("\\").join("/");
    return normalized.slice(normalized.lastIndexOf("/") + 1);
};

const mobileFinding = function mobileFinding(
    file: FileInput,
    ctx: { allContent: string; basenames: ReadonlySet<string> },
): Finding[] {
    const name = basename(file.path);
    if (!name.endsWith(MOBILE_SUFFIX)) {
        return [];
    }
    const baseName = `${name.slice(0, -MOBILE_SUFFIX.length)}.css`;
    if (!ctx.basenames.has(baseName)) {
        return [
            projectFinding({
                file: file.path,
                message: mobileWithoutBase(name, baseName),
                ruleId: RULE_ID,
                suggestion: mobileWithoutBaseFix(baseName),
            }),
        ];
    }
    if (!ctx.allContent.includes(name)) {
        return [
            projectFinding({
                file: file.path,
                message: mobileNotImported(name),
                ruleId: RULE_ID,
                suggestion: mobileNotImportedFix(name, baseName),
            }),
        ];
    }
    return [];
};

defineValidator({
    appliesTo: CSS_EXTENSIONS,
    id: RULE_ID,
    meta: {
        canonical: ["css-architecture", "responsive-design"],
        description: "Require every -mobile.css to have a base file and be imported by a barrel",
    },
    validate(files): Finding[] {
        const ctx = {
            allContent: files.map((file) => file.content).join("\n"),
            basenames: new Set(files.map((file) => basename(file.path))),
        };
        return files.flatMap((file) => mobileFinding(file, ctx));
    },
});
```
