# Kommandolinjen

> Kommandoene i @fristil/designsystem, med flagg, utdata og exit-koder. Sjekk markup og hele sider, hent regelboka for kodeagenter, ta over en komponent og lag et tema.

Pakken har en kommandolinje med sju kommandoer. Den har ingen avhengigheter, og du trenger ikke installere noe ekstra:

```bash
npx @fristil/designsystem <kommando>
```

Står pakken i `package.json`, heter kommandoen `fristil`, så `npx fristil sjekk` og et skript med `fristil sjekk` gjør det samme. `npx @fristil/designsystem` uten kommando, eller med `--hjelp`, viser hele oversikten.

| Kommando | Gjør |
| - | - |
| `sjekk` | sjekker markup mot Fristil, i filer, fra standard inn eller fra en adresse |
| `agent` | skriver regelboka for kodeagenter for miljøet ditt |
| `overta` | kopierer kildekoden til én komponent inn i prosjektet |
| `tema` | lager et fargetema av merkefargene dine |
| `sjekk-tema` | kontrollerer at et tema holder kontrastkravene |
| `manifest` | skriver manifestet sjekken bruker, med fragmentene fra `overta` |
| `lsp` | språkserveren for editorer, se [Editoren](/editoren.md#spr%C3%A5kserveren) |

## Uten Node

Kommandoene er skrevet én gang, i Rust, og bygget som en WebAssembly-modul for WASI. `npx` kjører den med Node, men den samme modulen kjører også uten, og svarer det samme, byte for byte. Velg det som allerede finnes på maskinen:

| Har du | Kjør |
| - | - |
| Java 17 eller nyere | `java -jar fristil.jar sjekk skjema.html` |
| [wasmtime](https://wasmtime.dev) | `wasmtime run --dir=. --env FRISTIL_PACKAGE=package fristil.wasm sjekk skjema.html` |
| Rust | `cargo install --git https://github.com/MarkusAugust/fristil fristil`, og så `fristil sjekk skjema.html` |

`fristil.jar` og `fristil.wasm` ligger ved hver [utgivelse på GitHub](https://github.com/MarkusAugust/fristil/releases/latest), med samme versjon som npm-pakken. Ingen av dem er signert med et sertifikat. GitHub attesterer i stedet hvilken commit og hvilken arbeidsflyt hver fil ble bygd av, og det kan du kontrollere selv:

```bash
gh attestation verify fristil.jar --repo MarkusAugust/fristil
```

Jar-en har alt i seg og trenger ingen avhengigheter. Den kjørbare fila og `fristil.wasm` har ingen data: de leser manifestet, fargekontrakten, regelbøkene og komponentene fra `@fristil/designsystem` i `node_modules`, eller fra mappa `FRISTIL_PACKAGE` peker på. Uten Node henter du pakken fra npm-registeret og pakker den ut, så ligger den i `package/`:

```bash
curl -sL https://registry.npmjs.org/@fristil/designsystem/-/designsystem-0.35.0.tgz | tar xz
FRISTIL_PACKAGE=package fristil sjekk skjema.html
```

Bytt ut versjonen med den du vil sjekke mot. Uten pakken stopper kommandoen og sier hva den mangler.

En adresse hentes av verten, siden WASI ikke har nettverk. `npx` og `java -jar` henter både `http://` og `https://`. Den kjørbare fila fra `cargo install` henter `http://`, som er det en lokal server svarer på. For `https://` fra `cargo install` sender du siden inn selv: `curl -s https://… | fristil sjekk --rendret`.

### Ulempene med wasmtime

wasmtime er med for den som har det fra før, eller ikke har Node, Java eller Rust. Det er den svakeste av vertene, og det bør du vite før du velger den:

- **Du må stole på en tredjepart.** wasmtime installeres fra [wasmtime.dev](https://wasmtime.dev), utenfor npm, Maven og cargo, og er laget av Bytecode Alliance, ikke av Fristil.
- **Ingen adresser.** wasmtime har ikke nettverk, og ingen vert henter siden for modulen. `fristil sjekk http://…` sier at den ikke fikk kontakt. Send siden inn selv: `curl -s http://localhost:8080/skjema | wasmtime run --dir=. --env FRISTIL_PACKAGE=package fristil.wasm sjekk --rendret`.
- **Bare mappene du åpner.** wasmtime ser bare det du gir den med `--dir`. Med `--dir=.` virker stier under arbeidsmappa, og en fil utenfor gir «Fant ikke fila», selv om den finnes. Pakken må også ligge under en mappe du åpner, og `FRISTIL_PACKAGE` gis med `--env`, siden wasmtime ikke gir modulen miljøet ditt. Språkserveren trenger `--dir=/::/`, som gir den hele filsystemet.
- **Ingen beskjed om standard inn.** De andre vertene sier «Leser markup fra standard inn» når du kjører `sjekk` uten filer i en terminal. wasmtime kan ikke se det, så kommandoen venter stille til du avslutter med Ctrl-D.
- **Windows er ikke prøvd.** De andre vertene oversetter `C:\…` til det modulen forstår. I wasmtime må du åpne stasjonen selv med `--dir`.
- **Ikke prøvd i CI.** `npx`, `java -jar` og den kjørbare fila prøves på hver endring, med de samme kjøringene. wasmtime er prøvd for hånd.

## sjekk

`sjekk` er den samme kontrollen som [editoren](/editoren.md) kjører mens du skriver. Den kjenner hver klasse, hvert element, hvert attributt og hver lovlige verdi i pakken du har installert.

```bash
npx @fristil/designsystem sjekk maler/*.html
npx @fristil/designsystem sjekk http://localhost:8080/skjema
curl -s http://localhost:8080/skjema | npx @fristil/designsystem sjekk --rendret
```

Den leser tre slags inndata:

- **filer**, oppgitt som argumenter;
- **standard inn**, når ingen filer er oppgitt;
- **en adresse** som begynner med `http://` eller `https://`. Den hentes av kommandolinja, se [Uten Node](#uten-node). En side som svarer noe annet enn 2xx, eller med noe annet enn HTML, gir feilkode i stedet for å bli sjekket.

Hvert funn skrives som en kompilator skriver det, med fil, linje og kolonne:

```text
skjema.html:4:27: advarsel: data-variant kan ikke være «outline» på button. Lovlige verdier: secondary, ghost, danger, og primary uten attributt.
skjema.html:5:13: advarsel: Klassen «fs-modal» finnes ikke i Fristil.


2 funn i 1 fil.
```

| Flagg | Betydning |
| - | - |
| `--rendret` | sjekk filer og standard inn som hele sider, med koblingen |
| `--css=<fil>` | sjekk også at stilarkene styler markupen. Se [Med stilarkene](#med-stilarkene) |
| `--manifest=<fil>` | sjekk også en komponent du har tatt over. Se [overta](#overta) |

Exit-koden er 0 når det ikke er noen funn, og 1 ellers, også når alle funnene er advarsler. En advarsel i en mal er en feil ingen kompilator ser. Tom standard inn, filer som alle er tomme, en fil som ikke finnes, og en adresse som ikke svarer eller svarer med en tom side, gir også 1. Én tom fil blant flere, som en tom partial i et glob, er ikke en feil.

### Maler og hele sider

En mal er ofte delt i biter. En ledetekst kan stå i én fil og feltet i en annen, og malsyntaks som `{{ }}`, `{% %}`, `<?= ?>`, `@variabel` og `<%= %>` står der verdien kommer senere. Uten flagg sjekker `sjekk` derfor bare det som kan avgjøres i én fil: elementer, klasser, attributter, verdier, at hvert `<fs-field>` har en ledetekst, og at en del som skal stå én gang, ikke står flere ganger. Et `<fs-field>` med to kontroller kobler bare den første, og en `fs-table` med to `<caption>` får navnet sitt fra den første. Hvilke deler det gjelder, står i manifestet som `unique`. Andre deler kan stå flere ganger, som knappene i panelet til `<fs-popover>`. Står det malsyntaks i komponenten, også `v-if` eller et uttrykk i `{…}`, sier regelen ingenting, siden et vilkår kan gi to deler i malen og én på siden.

En side slik serveren sender den, er hel. Da kan `sjekk` også kreve at koblingen stemmer:

- hver id i `for`, `aria-describedby`, `aria-labelledby` og `aria-controls` finnes på siden, og `for` peker på et felt eller en knapp;
- ingen id står mer enn én gang;
- hvert felt med en `fs-`-klasse har en ledetekst: en `<label for>`, en `<label>` rundt, `aria-label` eller `aria-labelledby`;
- hver synlige hjelpetekst og feilmelding er pekt på fra `aria-describedby`. En tekst er ikke synlig når den selv eller en forelder har `hidden`, eller står i en lukket `<dialog>` eller `<details>`. Et statusfelt, med `role="status"`, `role="alert"` eller `aria-live`, leses opp av seg selv og trenger ingen kobling;
- hver lenke i `<fs-error-summary>` går til en id som finnes.

En adresse sjekkes alltid slik. Filer og standard inn sjekkes slik med `--rendret`. Bar markup inni `<fs-field>` gir ingen funn, siden web-komponenten setter koblingen i nettleseren. Det samme gjelder et felt inni `<fs-suggestion>`. En id som er skrevet og peker feil, meldes uansett hvor den står.

To ting leses ikke som en del av siden. Innholdet i en `<template>` er ikke i dokumentet, og i en shadow root, `<template shadowrootmode>`, har id-ene sitt eget rom. Markup som står i en attributtverdi, som et kodeeksempel bak en kopieringsknapp, eller inni en `<textarea>`, er tekst. Ingen av dem sjekkes.

```text
http://localhost:8080/skjema:12:30: feil: for="epost" peker på id-en «epost», som ikke finnes på siden. Skjermleseren mister ledeteksten. Skriv for på ledeteksten og id på feltet i malen, eller legg ledeteksten rundt feltet. Lages markupen med JavaScript, gjør fs.field({ id }) det.
```

Det er denne sjekken som virker likt i alle språk. HTML-en serveren sender, ser lik ut enten den kommer fra Kotlin, Go, PHP eller Node, og det er den som sjekkes, ikke koden som lager den.

### Med stilarkene

Markupen kan være riktig og likevel se feil ut: stilarket til komponenten er ikke lastet, eller en variant har ingen regel. Med `--css` leser `sjekk` stilarkene siden laster, med det de importerer, og sier fra om begge deler:

```bash
npx @fristil/designsystem sjekk --css=public/app.css --manifest=src/ui/button/fristil-manifest.json maler/*.html
```

```text
maler/knapp.html:1:28: advarsel: data-variant="glass" på button har ingen regel i stilarkene, så den gjør ingenting synlig. Style verdien, eller ta den bort.
maler/kort.html:1:13: advarsel: Klassen «fs-card» står i markupen, men ingen av stilarkene styler den. Er fristil.css, eller stilarket til card, lastet?


2 funn i 2 filer.
```

Den første meldingen kommer for en verdi manifestet kjenner, men som ingen av stilarkene styler. En verdi Fristil ikke har, som `data-variant="glass"` på `fs-button`, avvises før stilarkene leses, med beskjed om de lovlige verdiene. Meldingen er nyttigst for en komponent du har [tatt over](#overta): legger du til en variant i fragmentet, men ikke i CSS-en, er markupen gyldig og ser ut som standard. Utdataene over er fra en slik kopi: `knapp.html` er `<button class="app-button" data-variant="glass">`, med `glass` lagt til i fragmentet. `@import` følges til filer ved siden av og til pakker i `node_modules`, som `@fristil/designsystem/fristil.css`. `--css` kan gis flere ganger. Stilarkene leses med en ekte CSS-leser, så nesting, `:is()`, `:where()`, `@layer` og `@media` forstås som nettleseren forstår dem.

### Den rendrede siden

Det serveren sender, er ikke alltid det brukeren ser. Web-komponentene legger til markup, et skript kan sette en klasse, og stilarkene er de nettleseren faktisk lastet. `diagnoseRendered` sjekker siden slik nettleseren har rendret den, med Playwright:

```ts
import { diagnoseRendered } from "@fristil/designsystem/diagnostics"


test("skjemaet er riktig slik det vises", async ({ page }) => {
  await page.goto("http://localhost:8080/skjema")
  expect(await diagnoseRendered(page)).toEqual([])
})
```

Den gir det `diagnosePage` gir, og det stilarkene ikke styler. Et stilark fra et CDN leses også, når det svarer med `Access-Control-Allow-Origin`, som jsDelivr og unpkg gjør. Med [Fristil for Kotlin](/kotlin.md#den-rendrede-siden) heter det `assertFristilRendered`.

### I testene og i CI

Med en server som kjører, er én linje nok:

```bash
npx @fristil/designsystem sjekk http://localhost:8080/ http://localhost:8080/skjema
```

Den samme sjekken finnes som funksjoner, for tester skrevet i JavaScript eller TypeScript:

```ts
import { diagnoseMarkup, diagnosePage } from "@fristil/designsystem/diagnostics"


expect(diagnoseMarkup(mal)).toEqual([]) // en mal eller en bit av en side
expect(diagnosePage(html)).toEqual([]) // en hel side, med koblingen
```

Hvert funn har `start`, `end`, `line`, `column`, `severity`, `rule` og `message`, og noen har en `fix` editoren kan tilby. Sjekken er den samme Rust-kjernen som editorene bruker, bygget til WebAssembly og med i pakken.

Er appen skrevet i et annet språk, kjører testen kommandoen over HTML-en den rendrer. I Kotlin:

```kotlin
@Test
fun `skjemaet er koblet riktig`() {
    val html = app.render("/skjema")
    val sjekk = ProcessBuilder("npx", "@fristil/designsystem", "sjekk", "--rendret")
        .redirectErrorStream(true)
        .start()
    sjekk.outputStream.use { it.write(html.toByteArray()) }
    val utdata = sjekk.inputStream.bufferedReader().readText()
    assertEquals(0, sjekk.waitFor(), utdata)
}
```

Testen feiler med funnene som melding, og det er meldingen en kodeagent leser og retter etter.

Uten Node i CI bytter du `npx @fristil/designsystem` med `java -jar fristil.jar`. Med [Fristil for Kotlin](/kotlin.md) blir det `assertFristil(html)`, med den samme sjekken kjørt i JVM-en.

## agent

Skriver regelboka for kodeagenter til standard ut. Ingen fil skrives noe sted.

```bash
npx @fristil/designsystem agent
npx @fristil/designsystem agent --rammeverk=datastar
```

Uten flagg leses miljøet av avhengighetene i `package.json`: Astro, React, Datastar, eller et byggesteg som Vite. Finnes det ingen `package.json`, som i en Kotlin- eller Go-app, er det regelboka for maler. Hvilken det ble, og hvorfor, står på standard feil.

| `--rammeverk` | Regelboka for |
| - | - |
| `html` | håndskrevet HTML uten byggesteg, der nettleseren laster filene direkte |
| `maler` | serverskrevet HTML: Go-maler, Razor, PHP, Jinja, ERB og andre, og HTML skrevet i kode |
| `bundles` | et byggesteg der markupen er vanlig HTML: Vue, Svelte, Solid, Lit og Vite |
| `react` | React |
| `astro` | Astro |
| `datastar` | HTML med Datastar |

Hvordan agenten finner regelboka, står på [Kodeagenter](/kodeagenter.md).

## overta

Kopierer kildekoden til én komponent inn i prosjektet: TypeScript-fila og stilarket. Kopien er din fra det øyeblikket den er skrevet, og kommandoen gjør tre ting for at den skal kunne være det:

- **Kopien får nytt navn.** `fs-button` blir `app-button` i klassene, taggene, `customElements.define` og selektorene. Kopien kan dermed stå ved siden av originalen, og du bytter navnet i markupen der kopien skal brukes. Variablene fra temaet, `--fs-*`, er de samme, så kopien følger temaet ditt som før.
- **Henvisningene ut av komponenten skrives om** til pakken, så resten av systemet fortsatt kommer fra `@fristil/designsystem` og kan oppgraderes.
- **Et fragment av manifestet skrives ved siden av**, `fristil-manifest.json`, med klassene, elementene og verdiene til kopien under det nye navnet. Med det sjekker `sjekk` markupen for kopien også:

```bash
npx @fristil/designsystem overta button --ut=src/ui
npx @fristil/designsystem sjekk --manifest=src/ui/button/fristil-manifest.json maler/*.html
```

Uten `--manifest` lar `sjekk` alt som ikke begynner med `fs-` være. Med det sjekkes bare kopiens egne navn, `app-button` med varianter og elementer, ikke resten av prosjektets klasser. Endrer du kopien, for eksempel med en ny variant, skriver du den inn i fragmentet også. `--manifest` kan gis flere ganger, én gang for hver kopi.

| Flagg | Betydning |
| - | - |
| `--ut=<mappe>` | hvor kopien skal ligge. Standard: `src/fristil` |
| `--overskriv=ja` | skriv over en kopi som finnes fra før |

Uten navn lister kommandoen komponentene. Når du bør ta over en komponent, og hva du bør prøve først, står på [Tilpasning](/tilpasning.md#n%C3%A5r-css-ikke-er-nok).

## manifest

Skriver manifestet `sjekk` bruker: Fristils klasser, elementer og lovlige verdier, med fragmentene fra `overta` lagt til. Det er det en editor eller et annet verktøy trenger for å kjenne ordforrådet prosjektet faktisk har.

```bash
npx @fristil/designsystem manifest --manifest=src/ui/button/fristil-manifest.json --ut=build/fristil/manifest.json
```

| Flagg | Betydning |
| - | - |
| `--manifest=<fil>` | et fragment fra `overta`. Kan gis flere ganger |
| `--ut=<fil>` | skriv til fil i stedet for til standard ut |

[Gradle-pluginen](/kotlin.md#gradle-pluginen) skriver den samme fila til `build/fristil/manifest.json` når `manifests` har fragmenter.

## tema

Lager et fargetema av merkefargene dine, med lyst og mørkt utseende og kontrastkravene oppfylt. Temaet skrives til standard ut, eller til en fil.

```bash
npx @fristil/designsystem tema --aksent=#7c3aed --fare=#b3261e \
  --suksess=#2b6940 --advarsel=#8a5a00 --ut=tema.css
npx @fristil/designsystem tema fristil.tema.json --ut=tema.css
```

| Flagg | Betydning |
| - | - |
| `--aksent`, `--fare`, `--suksess`, `--advarsel`, `--noytral`, `--besokt` | fargene for rollene, heksadesimalt |
| `--merke1`, `--merke2`, `--merke3` | merkefarger for flater og kategorier |
| `--skrift` | skriftstakken temaet skal bruke |
| `--knapp-hjorner`, `--felt-hjorner`, `--flate-hjorner` | hjørnene på knapper, felt og flater |
| `--knapp-ramme`, `--knapp-vekt` | rammetykkelsen og vekten på knappeteksten |
| `--ut=<fil>` | skriv til fil i stedet for til standard ut |

Hva hver rolle styrer, og hvordan temaet tas i bruk, står på [Eget tema](/eget-tema.md).

## sjekk-tema

Kontrollerer et tema du har skrevet selv. Kommandoen leser `--fs-color-*`-verdiene i hver blokk og sier hvilken celle som ryker, og hvorfor.

```bash
npx @fristil/designsystem sjekk-tema tema.css
```

Ett brudd gir feilkode. Et tema laget med `tema` holder kravene fra før.

Et tema uten farger, med bare skrift og form, har ingen kontrast å kontrollere. Kommandoen sier det og avslutter uten feilkode. En fil uten noen `--fs-*`-verdier gir feilkode, for da har sjekken ikke sett på noe.
