Node.js · API
Plugin
Un plugin extiende DON.parse recorriendo cada directiva mientras se construye el árbol. Sirve para transformar argumentos (por ejemplo, resolver variables) o eliminar directivas.
interface PluginDirectiveNode {
readonly name: string | symbol;
readonly args: readonly (number | string | boolean | HeredocValue)[];
readonly children?: readonly PluginDirectiveNode[];
}
interface DonPlugin<TContext = unknown> {
readonly name: string;
initContext?(): TContext;
onDirective?(node: PluginDirectiveNode, ctx: TContext):
PluginDirectiveNode | null | void;
onEnterScope?(node: PluginDirectiveNode, ctx: TContext): void;
onExitScope?(node: PluginDirectiveNode, ctx: TContext): void;
} Hooks
-
initContext(): crea el estado del plugin una vez por cadaDON.parse. Nunca se comparte con otro plugin. Sin él,ctxesundefined. -
onDirective(node, ctx): se llama una vez por directiva, de forma ordenada según el documento (el padre antes que sus hijos). El nodo no se modifica: devuelve uno nuevo para cambiarlo,nullpara eliminar la directiva con sus hijos, o nada para dejarlo igual. Si el nodo devuelto traechildren, reemplazan a los originales. -
onEnterScope(node, ctx): justo antes de visitar los hijos de la directiva. -
onExitScope(node, ctx): justo después de visitarlos. Se llama siempre que huboonEnterScope, incluso si la directiva no tiene hijos.
Transformar y eliminar
import { DON, type DonPlugin } from "donly";
const upper: DonPlugin = {
name: "upper",
onDirective(node) {
if (node.name === "drop") return null; // elimina la directiva
if (node.name === "name") {
return {
...node,
args: node.args.map((a) => (typeof a === "string" ? a.toUpperCase() : a)),
};
}
},
};
JSON.stringify(DON.parse('name "x"\ndrop 1\nport 1', { plugins: [upper] }));
// {"name":"X","port":1} Orden de los hooks
const trace: DonPlugin<{ depth: number }> = {
name: "trace",
initContext: () => ({ depth: 0 }),
onDirective: (node) => log.push("dir " + String(node.name)),
onEnterScope: (node, ctx) => log.push("in " + String(node.name) + ++ctx.depth),
onExitScope: (node, ctx) => log.push("out " + String(node.name) + ctx.depth--),
};
DON.parse("a { b { c } }\nd", { plugins: [trace] });
// dir a, in a1, dir b, in b2, dir c, in c3,
// out c3, out b2, out a1, dir d, in d1, out d1 Plugins incluidos
scoped-variables implementa set, $nombre y
${nombre} con alcance por bloque.