Dokumentacja API
Verso eksportuje siedem funkcji i trzy klasy błędów. Deklaracje typów są dołączone do pakietu; pisane ręcznie i sprawdzane względem implementacji w CI.
compile()
Kompiluje szablon z łańcucha i zwraca funkcję renderującą. Rzuca VersoSyntaxError, jeśli źródła nie da się sparsować.
import { compile } from 'verso';
const greet = compile('Hello, {{name}}!');
greet({ name: 'Ada' }); // 'Hello, Ada!'
CompileOptions
| Opcja | Typ | Domyślnie | Opis |
|---|---|---|---|
name | string | '(anonymous)' | Pokazywana w błędach i ramkach stosu |
strict | boolean | false | Rzucaj wyjątek przy brakujących właściwościach zamiast renderować pusty łańcuch |
allowRaw | boolean | true | Zezwalaj na {{{ }}}; ustaw false, aby zakazać nieescapowanego wyjścia w całym projekcie |
filters | Record<string, Function> | {} | Dodatkowe filtry nakładane na wbudowane |
resolve | (path, from) => string | rozwiązywanie node | Własne rozwiązywanie partiali |
cache | boolean | true | Ponowne użycie skompilowanych partiali w obrębie jednego procesu |
trimBlocks | boolean | false | Usuń znak nowej linii po znaczniku bloku |
compileFile()
Czyta plik, rozwiązuje jego partiale względem niego i kompiluje. Zwrócona obietnica jest odrzucana z VersoSyntaxError albo błędem systemu plików.
const page = await compileFile('views/page.vs', { strict: true });
Skompilowane szablony są cache’owane według ścieżki bezwzględnej i mtime. W trakcie pracy ustaw cache: false albo wywołuj clearCache() z obserwatora plików.
TemplateFn
Wartość zwracana przez compile(). Synchroniczna, chyba że szablon zawiera #defer — wtedy zwraca obietnicę.
| Właściwość | Typ | Opis |
|---|---|---|
template.source | string | Wygenerowany JavaScript, przydatny do debugowania i zapisu na dysk |
template.name | string | Nazwa nadana przy kompilacji |
template.deps | string[] | Ścieżki bezwzględne wszystkich osiągniętych partiali, dla trybu obserwacji |
template.async | boolean | true, gdy szablon zawiera odroczone bloki |
RenderOptions
| Opcja | Typ | Opis |
|---|---|---|
locals | object | Wartości dostępne jako {{@name}} |
signal | AbortSignal | Przerywa odroczone bloki, które się jeszcze nie zakończyły |
onError | (err, node) => string | Zastępuje błędny blok tekstem zastępczym zamiast rzucać wyjątek |
renderToStream()
Zwraca Readable Node.js w trybie łańcuchowym bez obiektów. Bloki najwyższego poziomu są wysyłane, gdy się kończą; odroczone bloki są dołączane z małym skryptem inline, który przenosi je na miejsce.
import { compileFile, renderToStream } from 'verso';
const report = await compileFile('views/report.vs');
server.get('/report/:id', (req, res) => {
const controller = new AbortController();
res.on('close', () => controller.abort());
res.type('html');
renderToStream(report, { id: req.params.id }, { signal: controller.signal })
.on('error', (err) => { res.destroy(err); })
.pipe(res);
});
Gdy bajty opuściły serwer, nie da się już wysłać 500. Obsłuż to przez onError, które podmienia błędny blok na zastępczy i utrzymuje strumień przy życiu.
raw()
Oznacza łańcuch jako już bezpieczny HTML, żeby interpolacja go nie escapowała. Jedyny sposób, by filtr lub wartość danych wyemitowały znaczniki bez potrójnych nawiasów.
import { raw } from 'verso';
page({ badge: raw('<span class="beta">beta</span>') });
Traktuj każde wywołanie raw() jak decyzję dotyczącą bezpieczeństwa. Reguła lintera w repozytorium wymaga komentarza w linii powyżej; przeniesienie tej reguły do twojego projektu nic nie kosztuje.
registerFilter() i clearCache()
Dodaje filtr globalnie, dla każdego szablonu kompilowanego później. Lepiej używać opcji filters dla pojedynczej kompilacji: rejestracja globalna uzależnia szablony od kolejności ładowania modułów, co trudno debugować.
Usuwa jeden wpis albo, wywołana bez argumentów, całą pamięć podręczną kompilacji.
Klasy błędów
| Klasa | Rzucana, gdy | Dodatkowe pola |
|---|---|---|
VersoSyntaxError | Szablonu nie da się sparsować | file, line, column, frame |
VersoLookupError | W trybie ścisłym brakuje właściwości | path, file, line |
VersoRenderError | Filtr lub odroczony blok rzuca wyjątek | cause, node, file, line |
Wszystkie trzy rozszerzają Error i ustawiają name na nazwę klasy. Pole frame zawiera dwuliniowy fragment ze znacznikiem pod błędnym tokenem:
VersoSyntaxError: unexpected '/each', expected '/if'
views/list.vs:14:7
13 | {{#if item.visible}}
14 | {{/each}}
| ^
TypeScript
Deklaracje są dołączone. TemplateFn jest generyczny względem kształtu danych, więc możesz powiązać szablon z interfejsem:
import type { TemplateFn } from 'verso';
interface ReportData { id: string; rows: Row[] }
const report: TemplateFn<ReportData> =
await compileFile<ReportData>('views/report.vs');
Kompilator nie sprawdza treści szablonów względem typu — wymagałoby to parsera świadomego typów, a dwukrotnie zdecydowaliśmy, że go nie zbudujemy.