Naar de inhoud
Docxcelerate

Nodes

Paragraph

Tekst, gerenderd uit je data of op het aanvraagmoment opgelost uit prompts.

The workhorse. A static paragraph returns a string from your typed data; a dynamic one carries prompts and a placeholder, and is filled at request time. Both land as the same node kind, differing only by `mode`.

Helpers
paragraph
Nodesoort
paragraph
Categorie
Tekst
Wordt opgelost
Both
Children
None. Paragraphs are leaves.
Optie Type Wat het doet
id verplicht string Stable address for the node. Generation endpoints target it and build artifacts diff on it, so treat a rename as a breaking change.
render verplicht (data, availableTokens) => string Static only. Receives your typed data and the token budget, returns the text. May be async.
placeholder (data, availableTokens) => string Dynamic only. What previews show in place of generated content. Optional, but a letter that reads badly without one cannot be reviewed.
generalPrompt verplicht (data, availableTokens) => string Dynamic only. What this node should say.
infoPrompt (data, availableTokens) => string Dynamic only. Context the model should have but should not restate.
negativePrompt (data, availableTokens) => string Dynamic only. What to avoid — claims, tones, or facts it must not invent.
systemPrompt (data, availableTokens) => string Dynamic only. Role and voice, applied ahead of the other prompts.
derivers DeriverInvocation[] Values computed before the node resolves, written to derived.* and readable from a template token. Built with derive().

Er een schrijven

render krijgt je getypeerde data en het tokenbudget, en geeft een string terug. Er zit geen templatetaal tussen, dus formattering, vertakking en meervoudsvormen zijn allemaal gewoon TypeScript:

import { paragraph } from "docxcelerate";
import type { MemberData } from "../types.ts";

export const Greeting = paragraph<MemberData>({
  id: "greeting",
  render: (data) => `Dear ${data.memberName},`,
});

Hij mag async zijn — maar een node die iets ophaalt is een node die midden in een build kan mislukken, dus zet de waarde liever eerst in je data.

Het tokenbudget

Het tweede argument van render, placeholder en elke prompt is availableTokens: het budget dat aan deze node is toebedeeld, 2000 tenzij je availableTokens in de buildopties instelt. Statische nodes mogen het negeren. Dynamische horen het te gebruiken:

generalPrompt: (data, availableTokens) =>
  `Explain the change. At most ${Math.floor(availableTokens / 4)} words.`,

Vertakken hoort in de render

Een document dat een van drie dingen zegt, is één node met drie uitkomsten, niet drie nodes achter condities. Het id blijft staan, de boom houdt zijn vorm wie de ontvanger ook is, en de logica is code die je kunt testen.

Dynamische alinea’s

Een dynamische alinea ruilt render in voor prompts en een placeholder. Previewbuilds lossen hem op naar de placeholder en labelen hem; builds op het aanvraagmoment sturen de prompts. Alleen generalPrompt is verplicht — de vierde variant hieronder laat zien waar de andere drie voor zijn.

Varianten

Static

src/nodes/paragraph/static.node.ts

Data in, a line of text out.

import { paragraph } from "docxcelerate";
import type { SampleData } from "../sample-data.ts";

/** The smallest useful node: an id, and a render that turns data into a line. */
export const Greeting = paragraph<SampleData>({
  id: "greeting",
  render: (data) => `Dear ${data.memberName},`,
});
paragraph · static Open ↗
Waartoe het wordt opgelost

De node zoals hij in het DocumentModel verschijnt: de JSON die een renderer aangereikt krijgt. Geen opmaak, geen lay-out.

{
  "id": "greeting",
  "kind": "paragraph",
  "mode": "static",
  "text": "Dear Adaeze Nkemelu,"
}

Static, with branching

src/nodes/paragraph/conditional.node.ts

One node, several outcomes — and the id stays put.

import { paragraph } from "docxcelerate";
import { money, type SampleData } from "../sample-data.ts";

/**
 * Branching lives in the render, not the template: one node and one id,
 * whichever branch a member falls down.
 */
export const PriceChange = paragraph<SampleData>({
  id: "price-change",
  render: (data) => {
    const delta = data.newPrice - data.lastPrice;

    if (delta === 0) {
      return `Your ${data.plan} membership renews at ${money(data.newPrice)} ` +
        `a year — the same price you paid last year.`;
    }

    const direction = delta > 0 ? "rising" : "falling";
    const percent = Math.abs((delta / data.lastPrice) * 100).toFixed(1);

    return `Your ${data.plan} membership is ${direction} by ${percent}%, from ` +
      `${money(data.lastPrice)} to ${money(data.newPrice)} a year. That is ` +
      `${money(data.newPrice / 12)} a month from ${data.renewsOn}.`;
  },
});
paragraph · static, with branching Open ↗
Waartoe het wordt opgelost

De node zoals hij in het DocumentModel verschijnt: de JSON die een renderer aangereikt krijgt. Geen opmaak, geen lay-out.

{
  "id": "price-change",
  "kind": "paragraph",
  "mode": "static",
  "text": "Your Peak Anytime membership is rising by 5.1%, from £468 to £492 a year. That is £41 a month from 1 October 2026."
}

Dynamic

src/nodes/paragraph/dynamic.node.ts

A prompt and a placeholder. Previews show the placeholder, labelled.

import { paragraph } from "docxcelerate";
import type { SampleData } from "../sample-data.ts";

/**
 * The minimum a dynamic paragraph needs: one prompt, and a placeholder so the
 * preview still reads as a letter.
 */
export const NextSteps = paragraph<SampleData>({
  id: "next-steps",
  placeholder: (data) =>
    `Your membership renews automatically on ${data.renewsOn}. ` +
    `Nothing is needed from you unless you want to change plan.`,
  generalPrompt: (data) =>
    `In two sentences, tell ${data.memberName} that their membership renews ` +
    `automatically on ${data.renewsOn} and how to change plan before then.`,
});
paragraph · dynamic Open ↗
Waartoe het wordt opgelost

De node zoals hij in het DocumentModel verschijnt: de JSON die een renderer aangereikt krijgt. Geen opmaak, geen lay-out.

{
  "id": "next-steps",
  "kind": "paragraph",
  "mode": "dynamic",
  "text": "Your membership renews automatically on 1 October 2026. Nothing is needed from you unless you want to change plan."
}
Wat er aan het endpoint wordt gevraagd

Opgelost tegen dezelfde voorbeelddata. Een previewbuild stopt bij de placeholder; een build op het moment van de aanvraag stuurt deze mee.

general
In two sentences, tell Adaeze Nkemelu that their membership renews automatically on 1 October 2026 and how to change plan before then.

Dynamic, all four prompts

src/nodes/paragraph/prompted.node.ts

System, general, info and negative, each doing one job.

import { paragraph } from "docxcelerate";
import { money, type SampleData } from "../sample-data.ts";

/**
 * All four slots: general says what to write, info supplies facts without
 * asking for them back, negative fences off the failure modes, system fixes
 * the voice. `availableTokens` is the budget the build allotted this node.
 */
export const Apology = paragraph<SampleData>({
  id: "pool-closure",
  placeholder: () =>
    `The main pool is closed for resurfacing until 12 October. ` +
    `The teaching pool and all land-based classes are running as normal.`,
  systemPrompt: () =>
    `You write for a public leisure centre. Plain British English, second ` +
    `person, no marketing language.`,
  generalPrompt: (data, availableTokens) =>
    `Apologise to ${data.memberName} for the main pool closure and say what ` +
    `is still open. At most ${Math.floor(availableTokens / 4)} words.`,
  infoPrompt: (data) =>
    `The main pool at ${data.centreName} is resurfacing until 12 October. ` +
    `The teaching pool, gym and classes are unaffected. Members on ` +
    `${data.plan} paying ${money(data.newPrice)} a year get two guest passes ` +
    `as compensation.`,
  negativePrompt: () =>
    `Do not promise a refund, do not give a reopening date beyond 12 October, ` +
    `and do not restate the price.`,
});
paragraph · dynamic, all four prompts Open ↗
Waartoe het wordt opgelost

De node zoals hij in het DocumentModel verschijnt: de JSON die een renderer aangereikt krijgt. Geen opmaak, geen lay-out.

{
  "id": "pool-closure",
  "kind": "paragraph",
  "mode": "dynamic",
  "text": "The main pool is closed for resurfacing until 12 October. The teaching pool and all land-based classes are running as normal."
}
Wat er aan het endpoint wordt gevraagd

Opgelost tegen dezelfde voorbeelddata. Een previewbuild stopt bij de placeholder; een build op het moment van de aanvraag stuurt deze mee.

system
You write for a public leisure centre. Plain British English, second person, no marketing language.
general
Apologise to Adaeze Nkemelu for the main pool closure and say what is still open. At most 500 words.
info
The main pool at Riverside Leisure Centre is resurfacing until 12 October. The teaching pool, gym and classes are unaffected. Members on Peak Anytime paying £492 a year get two guest passes as compensation.
negative
Do not promise a refund, do not give a reopening date beyond 12 October, and do not restate the price.

Aantekeningen

  • Beide modi lossen op naar kind: "paragraph". Een renderer leest mode als het hem al iets uitmaakt; hij vertakt nooit op welke helper je hebt aangeroepen.
  • Een lege string levert een lege alinea op, niet géén node. Laat de node uit de boom weg om hem echt te laten vervallen.
  • Renderers escapen de tekst. Een alinea kan geen markup de pagina in smokkelen, en is niet de plek voor opmaak.

Deze pagina bewerken op GitHub ↗