en Error Handling - chiba233/yume-dsl-token-walker GitHub Wiki
How errors are reported, what safety guarantees the interpreter provides, and how to observe errors without stopping iteration.
InterpretRuleset.onError is called before an error is thrown. It does not suppress the error — the error is always rethrown after onError returns.
Use it to log, report, or collect errors while still letting them propagate:
import { createParser, createSimpleInlineHandlers } from "yume-dsl-rich-text";
import { interpretTokens, collectNodes } from "yume-dsl-token-walker";
const parser = createParser({
handlers: createSimpleInlineHandlers(["bold"]),
trackPositions: true,
});
const tokens = parser.parse("$$bold(hello)$$");
const errors: Error[] = [];
try {
collectNodes(interpretTokens(tokens, {
createText: (text) => text,
interpret: (token) => {
if (token.type === "bold") throw new Error("boom");
return { type: "unhandled" };
},
onError: ({ error, phase, token, position }) => {
errors.push(error);
if (position) {
console.error(
`[${phase}] ${error.message} at line ${position.start.line}:${position.start.column}`,
);
}
},
}, undefined));
} catch {
// errors[] now contains the observed error
}position is forwarded from token.position — present when the upstream parser has trackPositions: true. It's a SourceSpan with start and end, each containing offset (zero-indexed), line (one-indexed), and column (one-indexed).
Every error reported through onError has a phase field:
| Phase | Trigger |
|---|---|
"interpret" |
interpret() throws, onUnhandled strategy function throws, or onUnhandled: "throw" fires |
"flatten" |
flattenText fails (e.g. circular value detected) |
"traversal" |
Structural error — text token has non-string value, or recursive token detected |
"internal" |
Unexpected internal state (e.g. unknown result type) |
If a handler feeds a token back into interpretChildren referencing itself, the interpreter detects it and throws immediately — before it can blow the stack.
Internally, a WeakSet<TextToken> tracks which tokens are currently being interpreted. If the same token object appears again during its own interpretation, an error is thrown.
flattenText tracks visited tokens per recursion path (not globally). This means:
- Shared references are safe — the same token appearing in multiple branches is fine
- True cycles throw — if a token's value chain loops back to itself,
flattenTextthrows with a descriptive error
If a token has type === "text" but its value is not a string, the interpreter throws a "traversal" error instead of silently producing garbage.
The exported flattenText() function is a standalone utility — it does not go through onError. Only errors raised inside interpretTokens / interpretTokensAsync are observed by onError.
If you call flattenText(value) directly and it encounters a circular reference, it throws immediately without any observer.