Référence

Référence de l’API

Verso exporte sept fonctions et trois classes d’erreur. Les déclarations de types sont livrées avec le paquet ; elles sont écrites à la main et vérifiées contre l’implémentation en CI.

compile()

compile(source: string, options?: CompileOptions): TemplateFn

Compile un template depuis une chaîne et renvoie la fonction de rendu. Lève VersoSyntaxError si le source ne s’analyse pas.

import { compile } from 'verso';

const greet = compile('Hello, {{name}}!');
greet({ name: 'Ada' });  // 'Hello, Ada!'

CompileOptions

OptionTypeDéfautDescription
namestring'(anonymous)'Affiché dans les erreurs et les piles d’appels
strictbooleanfalseLever une exception sur les propriétés manquantes au lieu de rendre une chaîne vide
allowRawbooleantrueAutoriser {{{ }}} ; mettre à false pour interdire la sortie non échappée dans tout le projet
filtersRecord<string, Function>{}Filtres supplémentaires fusionnés par-dessus ceux intégrés
resolve(path, from) => stringrésolution nodeRésolution personnalisée des partials
cachebooleantrueRéutiliser les partials compilés au sein d’un même processus
trimBlocksbooleanfalseSupprimer le saut de ligne qui suit une balise de bloc

compileFile()

compileFile(path: string, options?: CompileOptions): Promise<TemplateFn>

Lit un fichier, résout ses partials par rapport à lui et compile. La promesse renvoyée est rejetée avec VersoSyntaxError ou une erreur du système de fichiers.

const page = await compileFile('views/page.vs', { strict: true });
Mise en cache

Les templates compilés sont mis en cache par chemin absolu et mtime. En développement, mettez cache: false ou appelez clearCache() depuis votre surveillance de fichiers.

TemplateFn

template(data?: object, options?: RenderOptions): string

La valeur renvoyée par compile(). Synchrone, sauf si le template contient #defer, auquel cas elle renvoie une promesse.

PropriétéTypeDescription
template.sourcestringJavaScript émis, utile pour déboguer et pour écrire sur disque
template.namestringLe nom donné à la compilation
template.depsstring[]Chemins absolus de chaque partial atteint, pour le mode surveillance
template.asyncbooleantrue quand le template contient des blocs différés

RenderOptions

OptionTypeDescription
localsobjectValeurs accessibles via {{@name}}
signalAbortSignalInterrompt les blocs différés non encore résolus
onError(err, node) => stringRemplace un bloc en échec par une chaîne de secours au lieu de lever une exception

renderToStream()

renderToStream(template: TemplateFn, data?: object, options?: RenderOptions): Readable

Renvoie un Readable Node.js en mode chaîne, sans objets. Les blocs de premier niveau sont envoyés dès qu’ils sont prêts ; les blocs différés sont ajoutés avec un petit script en ligne qui les remet à leur place.

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);
});
Erreurs après le premier envoi

Une fois que des octets ont quitté le serveur, impossible d’envoyer une 500. Gérez ce cas avec onError, qui remplace le bloc en échec par un contenu de secours et garde le flux ouvert.

raw()

raw(value: string): RawString

Marque une chaîne comme du HTML déjà sûr pour que l’interpolation ne l’échappe pas. Le seul moyen pour un filtre ou une donnée d’émettre du balisage sans triples accolades.

import { raw } from 'verso';

page({ badge: raw('<span class="beta">beta</span>') });
Règle de revue

Traitez chaque appel à raw() comme une décision de sécurité. La règle de lint du dépôt exige un commentaire sur la ligne précédente ; reprendre cette règle dans votre projet ne coûte rien.

registerFilter() et clearCache()

registerFilter(name: string, fn: Function): void

Ajoute un filtre global, pour chaque template compilé ensuite. Préférez l’option filters par compilation : l’enregistrement global rend les templates dépendants de l’ordre de chargement des modules, ce qui est pénible à déboguer.

clearCache(path?: string): void

Supprime une entrée, ou tout le cache de compilation si on l’appelle sans argument.

Classes d’erreur

ClasseLevée quandChamps supplémentaires
VersoSyntaxErrorUn template ne s’analyse pasfile, line, column, frame
VersoLookupErrorUne propriété manque en mode strictpath, file, line
VersoRenderErrorUn filtre ou un bloc différé lève une exceptioncause, node, file, line

Les trois étendent Error et fixent name au nom de la classe. Le champ frame contient un extrait de deux lignes avec un caret sous le jeton fautif :

VersoSyntaxError: unexpected '/each', expected '/if'
  views/list.vs:14:7

  13 |   {{#if item.visible}}
  14 |     {{/each}}
     |       ^

TypeScript

Les déclarations sont fournies. TemplateFn est générique sur la forme des données, vous pouvez donc lier un template à une interface :

import type { TemplateFn } from 'verso';

interface ReportData { id: string; rows: Row[] }

const report: TemplateFn<ReportData> =
  await compileFile<ReportData>('views/report.vs');

Le compilateur ne vérifie pas le corps des templates par rapport au type — il faudrait pour cela un parseur conscient des types, et nous avons décidé deux fois de ne pas en écrire.