HackerOS · Dokumentacja Formatów

.hk &
.hacker

Formaty plików konfiguracyjnych i metadanych ekosystemu HackerOS.
.hk jest głównym formatem konfiguracji — potężnym zamiennikiem YAML.
.hacker służy do opisu modułów i narzędzi w ekosystemie.

// spis treści
  1. Format .hk
    1. Wprowadzenie
    2. Składnia
    3. Typy wartości
    4. Zagnieżdżanie
    5. Interpolacja
    6. Błędy
    7. Porównanie z YAML
  2. Format .hacker
  3. Rust API

Format .hk

Czytelny, hierarchiczny format konfiguracji dla ekosystemu HackerOS. Zastępuje YAML wszędzie tam gdzie potrzebna jest jasna struktura, silne typowanie i wsparcie dla interpolacji.

Wprowadzenie

Pliki .hk składają się z sekcji (odpowiedniki tabel w TOML) zawierających klucze i wartości. Każda sekcja tworzy zagnieżdżoną mapę. Format jest czytelny dla ludzi, obsługuje komentarze, wielopoziomowe zagnieżdżanie i interpolację zmiennych.

Format .hk jest używany jako główny plik konfiguracyjny narzędzi, menedżera pakietów hpm oraz repozytoriów bibliotek HackerOS.
.hk przykład podstawowy
! To jest komentarz — zaczyna się od '!'

[metadata]
-> name    => Hacker Lang
-> version => 1.5
-> stable  => true
-> tags    => ["lang", "compiler", "hacker"]

[build]
-> output  => "./dist"
-> target  => linux-x86_64
-> debug   => false

Składnia

Element Składnia Opis
Komentarz ! treść Linia zaczynająca się od ! jest ignorowana
Sekcja [nazwa] Najwyższy poziom hierarchii, tworzy mapę klucz-wartość
Klucz L1 -> klucz => wartość Klucz na pierwszym poziomie zagnieżdżenia
Klucz L2 --> klucz => wartość Klucz na drugim poziomie zagnieżdżenia
Klucz L3 ---> klucz => wartość Klucz na trzecim poziomie (i głębiej)
Mapa inline -> nazwa_mapy Linia bez => — tworzy podmapy
Klucz kropkowy -> a.b.c => val Skrót tworzący zagnieżdżone mapy: a → b → c
Klucze mogą zawierać litery, cyfry, _, - i . (kropki tworzą automatyczne zagnieżdżenie). Klucz w cudzysłowach ("klucz") jest traktowany jako literał — kropki wewnątrz nie powodują zagnieżdżenia.

Typy wartości

Parser automatycznie wykrywa typ wartości. Dostępne typy:

string

Ciąg znaków

Z cudzysłowami lub bez. Wersja cytowana obsługuje sekwencje ucieczki: \n \t \r \" \\

number

Liczba

Liczby całkowite i zmiennoprzecinkowe. Parsowane jako f64. Przykłady: 42, 3.14, -1.5

bool

Boolean

Wartości true / false (bez rozróżniania wielkości liter). Np. True, FALSE są poprawne.

array

Tablica

Lista wartości oddzielonych przecinkami w nawiasach kwadratowych. Elementy mogą być różnych typów. Np. [1, "dwa", true]

map

Mapa

Zagnieżdżona struktura klucz-wartość. Tworzona przez podwójne strzałki lub klucze z kropkami.

.hk wszystkie typy
[types]
-> tekst_plain   => hello world
-> tekst_quoted  => "hello, world\nwith newline"
-> liczba_int    => 42
-> liczba_float  => 3.14
-> flaga         => true
-> tablica       => [1, 2.5, true, "cztery"]

Zagnieżdżanie

Głębokość zagnieżdżenia określa liczba myślników przed >. Każdy dodatkowy myślnik to jeden poziom głębiej. Alternatywnie można użyć kropek w kluczu jako skrótu.

.hk zagnieżdżanie — styl myślnikowy
[libraries]
! Mapa L1: "obsidian"
-> obsidian
!   Klucze L2 wewnątrz "obsidian"
--> version     => 0.2
--> description => Biblioteka inspirowana zenity.
--> authors     => ["HackerOS Team <hackeros068@gmail.com>"]
--> so-download => https://github.com/Bytes-Repository/obsidian-lib/releases/download/v0.2/libobsidian_lib.so

-> yuy
--> version     => 0.2
--> description => Twórz ładne interfejsy CLI
.hk zagnieżdżanie — klucze z kropką
[config]
! Tworzy config → database → host
-> database.host     => localhost
-> database.port     => 5432
-> database.ssl      => true

! Trzy poziomy głębokości
-> server.tls.cert   => /etc/ssl/cert.pem
-> server.tls.key    => /etc/ssl/key.pem
Nie można mieszać klucza prostego i klucza z kropką wskazujących na to samo miejsce w drzewie. -> a => 1 a potem -> a.b => 2 spowoduje błąd KeyConflict.

Interpolacja

Wartości tekstowe mogą zawierać referencje do innych kluczy lub zmiennych środowiskowych, używając składni ${...}. Parser automatycznie rozwiązuje referencje, wykrywa cykle i błędne odwołania.

.hk interpolacja — referencje i env
[project]
-> name     => MyApp
-> version  => 1.0

[paths]
! Referencja do klucza z innej sekcji
-> base     => /opt/${project.name}
-> config   => ${paths.base}/config
-> logs     => ${paths.base}/logs

! Zmienna środowiskowa (prefix "env:")
-> home     => ${env:HOME}
-> user     => ${env:USER}

[data]
-> numbers  => [10, 20, 30]
! Indeksowanie tablicy
-> first    => ${data.numbers[0]}
SkładniaPrzykładOpis
${sekcja.klucz} ${project.name} Referencja do klucza w innej sekcji
${sekcja.mapa.klucz} ${build.opts.level} Referencja głęboko zagnieżdżona
${sekcja.tablica[n]} ${data.list[0]} Indeksowanie elementu tablicy (od 0)
${env:NAZWA} ${env:HOME} Zmienna środowiskowa; pusta jeśli nieustawiona

Błędy parsowania

Parser zwraca precyzyjne błędy z numerem linii i kolumny. Każdy błąd ma wbudowany hint wyświetlany w terminalu.

Parse { line, column, message }

Błąd składni. Zawiera numer linii i kolumny oraz opis problemu. Terminal pokazuje wskaźnik ^ w odpowiednim miejscu.

TypeMismatch { expected, found }

Próba odczytu wartości jako nieodpowiedni typ. Np. odczyt liczby z klucza który jest mapą.

InvalidReference(path)

Interpolacja wskazuje na nieistniejący klucz. Sprawdź, czy ścieżka sekcja.klucz istnieje.

CyclicReference(path)

Dwie wartości interpolują się nawzajem. Np. a => ${b} i b => ${a}.

KeyConflict(key)

Duplikat klucza lub konflikt między kluczem prostym a kluczem z kropką wskazującym to samo miejsce.

MissingField(name)

Wymagane pole nie zostało znalezione podczas deserializacji struktury.

terminal przykładowy output błędu
error: parse error
  → at 4:3

  -< klucz => wartość
    ^
  Expected '>' after dashes

Hint: Try: key => value

Porównanie z YAML

.hk
[server]
-> host    => localhost
-> port    => 8080
-> ssl     => true
-> tls
--> cert  => /etc/cert.pem
--> key   => /etc/key.pem
-> allowed => ["GET", "POST"]
YAML (równoważny)
server:
  host: localhost
  port: 8080
  ssl: true
  tls:
    cert: /etc/cert.pem
    key: /etc/key.pem
  allowed:
    - GET
    - POST

Brak znaczących wcięć

Zagnieżdżenie przez myślniki — nie przez spacje. Brak błędów wynikających z tabów vs spacji.

Wbudowana interpolacja

Natywne ${ref} i ${env:VAR} bez zewnętrznych narzędzi. YAML nie ma tego wbudowanego.

Precyzyjne błędy

Błąd wskazuje linię, kolumnę i daje hint naprawczy. YAML-owe błędy bywają kryptyczne.

Zachowana kolejność

Parser używa IndexMap — kolejność kluczy w pliku jest zachowana przy serializacji.

Format .hacker

Lekki format metadanych dla modułów, aplikacji i narzędzi w ekosystemie HackerOS. Obsługuje trzy wersje o różnym poziomie szczegółowości.

Każdy plik .hacker to zawartość ujęta w nawiasy kwadratowe [ ... ]. Parser automatycznie wykrywa wersję na podstawie struktury zawartości.

Wersje formatu .hacker
v1 — prosty
v2 — sekcje
v3 — metadane

Wersja 1 to fallback — dowolny tekst między nawiasami. Używana np. do oznaczenia numeru wersji lub krótkiego opisu.

.hacker v1składnia
[ 0.2 ]

! lub wieloliniowo:
[
  dowolny tekst
  w kilku liniach
]

Wersja 2 zawiera nagłówek i sekcje z listami wartości. Używana np. w plikach repozytorium opisujących dostępne kernele, narzędzia, wersje.

.hacker v2składnia
[
 Nazwa projektu         ! nagłówek — linie przed pierwszą sekcją

 jadro:                  ! nazwa sekcji + dwukropek
 = xanmod               ! wartość sekcji — prefix "= "
 = liquorix

 narzedzia:
 = hpm
 = hl

 wersje:
 = 0.1
 = 0.2
 = 1.1
]

Wersja 3 opisuje konkretny moduł lub aplikację przez cztery wymagane pola. Używana jako główny plik opisu aplikacji HackerOS.

.hacker v3składnia
[
 = application           ! nagłówek (= )
 => gui                   ! typ aplikacji (=> )
 -> aplication for cybersecurity  ! opis (-> )
 --> main.hacker          ! ścieżka pliku (--> )
]
PrefixPoleOpis
= headerNazwa / nagłówek modułu
=> typeTyp: gui, cli, lib, itd.
-> descriptionKrótki opis modułu
--> fileŚcieżka do głównego pliku

Wykrywanie wersji

Parser próbuje wersje w kolejności: v2 → v3 → v1. V1 jest zawsze akceptowany jako fallback — jeśli plik nie pasuje do v2 ani v3, cała zawartość trafia do pola content.

Każdy plik .hacker musi zaczynać się od [ i kończyć na ] (z opcjonalnymi białymi znakami). Pusty plik ([]) zwraca błąd EmptyContent.

Rust API

Publiczne funkcje eksportowane przez crate hk-parser i hacker-parser.

hk-parser

parse_hk(input)
Parsuje string jako plik .hk. Zwraca HkConfig (IndexMap sekcji).
→ Result<HkConfig, HkError>
load_hk_file(path)
Wczytuje plik z dysku i parsuje. Obsługuje BufReader wewnętrznie.
→ Result<HkConfig, HkError>
resolve_interpolations(config)
Rozwiązuje wszystkie ${...} w miejscu. Modyfikuje config. Wykrywa cykle.
→ Result<(), HkError>
serialize_hk(config)
Serializuje HkConfig z powrotem do stringa w formacie .hk. Zachowuje kolejność.
→ String
write_hk_file(path, config)
Zapisuje zserializowany config do pliku na dysku.
→ io::Result<()>

Enum HkValue — metody

.as_string()
Konwertuje String, Number lub Bool na String. Błąd dla Array/Map.
→ Result<String, HkError>
.as_number()
Zwraca wartość jako f64. Błąd jeśli wartość nie jest typu Number.
→ Result<f64, HkError>
.as_bool()
Zwraca wartość jako bool. Błąd jeśli wartość nie jest typu Bool.
→ Result<bool, HkError>
.as_array()
Zwraca referencję do Vec<HkValue>. Błąd jeśli to nie tablica.
→ Result<&Vec<HkValue>, HkError>
.as_map()
Zwraca referencję do IndexMap<String, HkValue>. Błąd jeśli to nie mapa.
→ Result<&IndexMap<String, HkValue>, HkError>
Rustprzykład użycia API
use hk_parser::{load_hk_file, resolve_interpolations};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut config = load_hk_file("config.hk")?;
    
    // Rozwiąż interpolacje (env vars, referencje)
    resolve_interpolations(&mut config)?;
    
    // Odczyt zagnieżdżonej wartości
    let server = config["server"].as_map()?;
    let host   = server["host"].as_string()?;
    let port   = server["port"].as_number()? as u16;
    
    println!("Connecting to {}:{}", host, port);
    Ok(())
}

hacker-parser

parse(input)
Parsuje string jako plik .hacker. Zwraca enum z wariantem V1, V2 lub V3.
→ Result<HackerFile, ParseError>
parse_file(path)
Wczytuje plik z dysku i parsuje jako .hacker.
→ Result<HackerFile, ParseError>
Rustdopasowanie wariantu
use hacker_parser::{parse_file, HackerFile};

let file = parse_file("app.hacker")?;

match file {
    HackerFile::V1(v) => println!("v1 content: {}", v.content),
    HackerFile::V2(v) => {
        println!("header: {}", v.header);
        for (section, values) in &v.sections {
            println!("  {}: {:?}", section, values);
        }
    }
    HackerFile::V3(v) => {
        println!("app: {} ({})", v.header, v.ty);
        println!("desc: {}", v.description);
        println!("entry: {}", v.file);
    }
}