Skip to content

Instantly share code, notes, and snippets.

@psimsa
Created May 7, 2026 08:33
Show Gist options
  • Select an option

  • Save psimsa/766abf0cac3e5dd863393d7bed2b3931 to your computer and use it in GitHub Desktop.

Select an option

Save psimsa/766abf0cac3e5dd863393d7bed2b3931 to your computer and use it in GitHub Desktop.
Repository Wiki — generated by GitNexus
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Handlebars.Net — Wiki</title>
<script src="https://cdn.jsdelivr.net/npm/marked@11.0.0/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
--bg:#ffffff;--sidebar-bg:#f8f9fb;--border:#e5e7eb;
--text:#1e293b;--text-muted:#64748b;--primary:#2563eb;
--primary-soft:#eff6ff;--hover:#f1f5f9;--code-bg:#f1f5f9;
--radius:8px;--shadow:0 1px 3px rgba(0,0,0,.08);
}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
line-height:1.65;color:var(--text);background:var(--bg)}
.layout{display:flex;min-height:100vh}
.sidebar{width:280px;background:var(--sidebar-bg);border-right:1px solid var(--border);
position:fixed;top:0;left:0;bottom:0;overflow-y:auto;padding:24px 16px;
display:flex;flex-direction:column;z-index:10}
.content{margin-left:280px;flex:1;padding:48px 64px;max-width:960px}
.sidebar-header{margin-bottom:20px;padding-bottom:16px;border-bottom:1px solid var(--border)}
.sidebar-title{font-size:16px;font-weight:700;color:var(--text);display:flex;align-items:center;gap:8px}
.sidebar-title svg{flex-shrink:0}
.sidebar-meta{font-size:11px;color:var(--text-muted);margin-top:6px}
.nav-section{margin-bottom:2px}
.nav-item{display:block;padding:7px 12px;border-radius:var(--radius);cursor:pointer;
font-size:13px;color:var(--text);text-decoration:none;transition:all .15s;
white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nav-item:hover{background:var(--hover)}
.nav-item.active{background:var(--primary-soft);color:var(--primary);font-weight:600}
.nav-item.overview{font-weight:600;margin-bottom:4px}
.nav-children{padding-left:14px;border-left:1px solid var(--border);margin-left:12px}
.nav-group-label{font-size:11px;font-weight:600;color:var(--text-muted);
text-transform:uppercase;letter-spacing:.5px;padding:12px 12px 4px;user-select:none}
.sidebar-footer{margin-top:auto;padding-top:16px;border-top:1px solid var(--border);
font-size:11px;color:var(--text-muted);text-align:center}
.content h1{font-size:28px;font-weight:700;margin-bottom:8px;line-height:1.3}
.content h2{font-size:22px;font-weight:600;margin:32px 0 12px;padding-bottom:6px;border-bottom:1px solid var(--border)}
.content h3{font-size:17px;font-weight:600;margin:24px 0 8px}
.content h4{font-size:15px;font-weight:600;margin:20px 0 6px}
.content p{margin:12px 0}
.content ul,.content ol{margin:12px 0 12px 24px}
.content li{margin:4px 0}
.content a{color:var(--primary);text-decoration:none}
.content a:hover{text-decoration:underline}
.content blockquote{border-left:3px solid var(--primary);padding:8px 16px;margin:16px 0;
background:var(--primary-soft);border-radius:0 var(--radius) var(--radius) 0;
color:var(--text-muted);font-size:14px}
.content code{font-family:'SF Mono',Consolas,'Courier New',monospace;font-size:13px;
background:var(--code-bg);padding:2px 6px;border-radius:4px}
.content pre{background:#1e293b;color:#e2e8f0;border-radius:var(--radius);padding:16px;
overflow-x:auto;margin:16px 0}
.content pre code{background:none;padding:0;font-size:13px;line-height:1.6;color:inherit}
.content table{border-collapse:collapse;width:100%;margin:16px 0}
.content th,.content td{border:1px solid var(--border);padding:8px 12px;text-align:left;font-size:14px}
.content th{background:var(--sidebar-bg);font-weight:600}
.content img{max-width:100%;border-radius:var(--radius)}
.content hr{border:none;border-top:1px solid var(--border);margin:32px 0}
.content .mermaid{margin:20px 0;text-align:center}
.menu-toggle{display:none;position:fixed;top:12px;left:12px;z-index:20;
background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);
padding:8px 12px;cursor:pointer;font-size:18px;box-shadow:var(--shadow)}
@media(max-width:768px){
.sidebar{transform:translateX(-100%);transition:transform .2s}
.sidebar.open{transform:translateX(0);box-shadow:2px 0 12px rgba(0,0,0,.1)}
.content{margin-left:0;padding:24px 20px;padding-top:56px}
.menu-toggle{display:block}
}
.empty-state{text-align:center;padding:80px 20px;color:var(--text-muted)}
.empty-state h2{font-size:20px;margin-bottom:8px;border:none}
</style>
</head>
<body>
<button class="menu-toggle" id="menu-toggle" aria-label="Toggle menu">&#9776;</button>
<div class="layout">
<nav class="sidebar" id="sidebar">
<div class="sidebar-header">
<div class="sidebar-title">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/><path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/></svg>
Handlebars.Net
</div>
<div class="sidebar-meta" id="meta-info"></div>
</div>
<div id="nav-tree"></div>
<div class="sidebar-footer">Generated by GitNexus</div>
</nav>
<main class="content" id="content">
<div class="empty-state"><h2>Loading…</h2></div>
</main>
</div>
<script>
var PAGES = {"javascript-handlebars-cli-packaging":"# JavaScript Handlebars CLI & Packaging\n\n# Handlebars CLI & Packaging Module\n\nThis module provides the command-line interface for precompiling Handlebars templates and the Ruby gem packaging helper. It handles template loading from files, strings, or stdin, precompilation via the core Handlebars compiler, optional minification, and source map generation.\n\n## Architecture Overview\n\nThe main entry point is the `cli` function exported from `lib/precompiler.js`. It orchestrates the entire precompilation pipeline:\n\n1. **Template Loading** – `loadTemplates` (which delegates to `loadStrings` and `loadFiles`) collects template sources and their names.\n2. **Precompilation** – Each template is compiled with `Handlebars.precompile()`.\n3. **Output Assembly** – The results are wrapped into a JavaScript closure (or simple output) and written to stdout or a file.\n4. **Optional Minification** – If requested, the output is minified via uglify-js.\n5. **Source Map Handling** – When a source map output path is given, the precompiler reconstructs `SourceNode` objects and writes the map to disk.\n\nA small Ruby module (`components/lib/handlebars/source.rb`) provides paths to the precompiled JavaScript files for integration into Rails or other Ruby environments using the `handlebars-source` gem.\n\n```mermaid\nflowchart LR\n A[\"cli()\"] --> B[\"loadTemplates()\"]\n B --> C[\"loadStrings()\"]\n B --> D[\"loadFiles()\"]\n C --> E[\"arrayCast()\"]\n A --> F[\"Handlebars.precompile()\"]\n A --> G[\"SourceNode (source-map)\"]\n A --> H[\"minify() (optional)\"]\n A --> I[\"fs.writeFileSync (output)\"]\n```\n\n## Key Components\n\n### `export function cli(opts)`\nMain orchestration function. It:\n- Checks for `--version`.\n- Validates input: at least one template, no conflict between `--simple` and `--min`, correct mode for multiple templates.\n- Normalizes `known` helpers into a hash.\n- Builds either simple output or a namespace wrapper (`Handlebars.templates` or `Handlebars.partials`).\n- Iterates over `opts.templates`, calling `Handlebars.precompile()` for each.\n- Handles source map reconstruction (uses `SourceMapConsumer` and `SourceNode`).\n- Optionally minifies the combined output with `minify()`.\n- Writes the final JavaScript (and source map) to disk.\n\n### `export function loadTemplates(opts, callback)`\nAsync loader that combines string templates (from `--string` flags or stdin) and file templates (from `--files` or `--directory`). The callback receives `(err, opts)` with `opts.templates` populated.\n\n### `function loadStrings(opts, callback)`\nReads template strings from the `opts.string` array (or from stdin when a string is `'-'`). Validates that the number of names matches the number of strings. Returns an array of `{name, path, source}` objects.\n\n### `function loadFiles(opts, callback)`\nRecursively loads template files from `opts.files` and `opts.directory`. It:\n- Builds a regex from `opts.extension` (default `handlebars`).\n- Uses a queue (via `neo-async/whilst`) to walk files and directories.\n- Strips the BOM if `opts.bom` is set.\n- Computes template names relative to `opts.root` or using `basename`.\n\n### `function arrayCast(value)`\nEnsures a value is an array. If `null` or `undefined`, returns `[]`; if not an array, wraps it in one.\n\n### `async function minify(output, sourceMapFile)`\nDynamically imports `uglify-js` (handles both ESM and CommonJS exports). If the module is not available, it logs a warning and returns the output unchanged. Otherwise, it calls `uglify.minify()` with the source map content.\n\n### Ruby Module `Handlebars::Source`\nProvides two class methods:\n- `bundled_path` – path to the full `handlebars.js` in the gem.\n- `runtime_bundled_path` – path to `handlebars.runtime.js`.\n\nThese are used by Rails asset pipeline and other Ruby tools to locate the prebuilt JavaScript files.\n\n## Data Flow\n\n1. **Input Resolution** – The CLI wrapper (not shown) parses command-line arguments and passes them as `opts` to `cli`. `opts.templates` is initially empty; `loadTemplates` populates it.\n2. **Precompilation** – `cli` iterates over `opts.templates` and calls `Handlebars.precompile(source, options)`.\n3. **Source Map Assembly** – If `opts.map` is set, the precompiled code (returned as a string with a `.map` property) is converted into a `SourceNode` using `SourceMapConsumer` and `SourceNode.fromStringWithSourceMap`. The final output is generated via `toStringWithSourceMap()`.\n4. **Minification** – Applied to the entire output object (code + map) after assembly.\n5. **Output** – Written to `opts.output` file or printed to stdout.\n\n## Integration with the Core Codebase\n\n- `Handlebars.precompile()` is imported from `'./handlebars.js'`.\n- Source map classes (`SourceMapConsumer`, `SourceNode`) come from the `source-map` package.\n- The `neo-async` library is used for asynchronous control flow.\n- `uglify-js` is an optional peer dependency for minification.\n- The Ruby module `source.rb` is part of the `handlebars-source` gem and references the built JavaScript files in the gem’s `lib` directory.\n\n## Usage Example\n\n```bash\n# Precompile all .handlebars files in a templates directory, output a combined script\nhandlebars templates/ -f compiled.js\n\n# With namespace, source map, and minification\nhandlebars templates/ -f compiled.min.js -m compiled.min.js.map -k each if --min\n```","javascript-handlebars-compiler":"# JavaScript Handlebars Compiler\n\n# JavaScript Handlebars Compiler Module\n\n## Overview\n\nThe Handlebars Compiler transforms Handlebars template strings or pre-parsed ASTs into JavaScript functions that can be executed at runtime. It is the core compilation pipeline of the Handlebars templating engine, converting declarative templates into imperative JavaScript code.\n\nThe module consists of four main files:\n\n- **`compiler.js`** – Compiler class that walks the AST and emits a sequence of opcodes (a low-level intermediate representation).\n- **`javascript-compiler.js`** – JavaScriptCompiler class that translates those opcodes into executable JavaScript source code.\n- **`code-gen.js`** – CodeGen utility for building JavaScript source strings with optional source map support.\n- **`ast.js`** – AST helper functions used during compilation to classify expressions.\n- **`source-node.*.js`** – Platform-specific wrappers around SourceNode (browser stub vs Node `source-map` library).\n\nThe two entry points are `compile()` and `precompile()` exported from `compiler.js`. Both accept an input string or parsed AST and return either a compiled template function or a JSON-parseable template specification.\n\n---\n\n## Key Components\n\n### 1. AST Helpers (`ast.js`)\n\nProvides static methods used by the compiler to analyze AST nodes:\n\n- **`helperExpression(node)`** – Returns `true` if a mustache or block statement is definitely a helper call (has parameters or a hash, or is a `SubExpression`).\n- **`scopedId(path)`** – Detects paths like `.foo`, `this.foo` (relative/this references).\n- **`simpleId(path)`** – Returns `true` if the path is a single, unscoped, non-depth identifier (e.g., `foo` but not `../foo` or `this.foo`).\n\nThese helpers drive the `classifySexpr` logic in the compiler.\n\n### 2. Opcode Compiler (`compiler.js`)\n\nThe `Compiler` class walks an AST using the visitor pattern (`accept(node)`) and emits an array of opcode objects. Each opcode is `{ opcode, args, loc }`. Key methods:\n\n- **`compile(program, options)`** – Entry point, resets state, then calls `accept(program)`.\n- **`accept(node)`** – Dispatches to `this[node.type](node)`.\n- **`Program / BlockStatement / MustacheStatement / SubExpression / PathExpression / ...`** – Visitor methods that generate opcodes.\n- **`classifySexpr(sexpr)`** – Decides whether an expression is `\"simple\"`, `\"helper\"`, or `\"ambiguous\"` based on AST helpers and `knownHelpers` options.\n- **`opcode(name, ...args)`** – Pushes an opcode to the internal list.\n- **`compileProgram(program)`** – Recursively compiles a child block into a separate child compiler instance, producing a sub-template referenced by a GUID.\n- **`blockParamIndex(name)`** – Checks if a name refers to a block parameter (e.g., `|foo|`).\n\nThe opcodes form an intermediate representation that is later consumed by the JavaScriptCompiler.\n\n### 3. JavaScript Code Generator (`javascript-compiler.js`)\n\n`JavaScriptCompiler` interprets the opcode sequence and outputs executable JavaScript source code. It manages a value stack, inline expressions, registers, hash maps, and buffers.\n\nKey concepts:\n\n- **Stack management** – `push`, `popStack`, `replaceStack`, `flushInline` simulate a virtual stack. In expressions that are simple (e.g., literals) they may be inlined; otherwise they are assigned to temporary variables (`stack1`, `stack2`, …).\n- **Buffer management** – Output is accumulated via `appendToBuffer` and merged into a single function body during `createFunctionContext`.\n- **Source merging** – `mergeSource()` concatenates all generated lines, intelligently combining appending operations into a single `return` or `buffer +=` statement to minimize code size.\n- **Aliasing** – `aliasable(name)` creates a shared source node reference for frequently used runtime helpers (e.g., `container.lambda`, `container.escapeExpression`), enabling shorter variable names when minified.\n- **Program deduplication** – `matchExistingProgram` compares child environments using `equals()` to reuse identical block templates.\n\nEach opcode (e.g., `append`, `lookupOnContext`, `invokeHelper`) is implemented as a method with the same name.\n\n### 4. Code Generation Utility (`code-gen.js`)\n\n`CodeGen` wraps a list of source chunks and provides methods to build JavaScript code:\n\n- `push`, `prepend`, `wrap`, `merge`\n- `quotedString` – Escapes a string for inclusion in JavaScript source.\n- `objectLiteral` – Generates a JavaScript object literal.\n- `functionCall` – Generates a function call expression.\n- `generateList` / `generateArray` – Comma-separated lists.\n\nIt supports two modes: in browser, chunks are concatenated as plain strings; in Node, they produce actual SourceNode objects from the `source-map` package for source map generation.\n\n---\n\n## Compilation Pipeline\n\n```\nInput (string or AST)\n |\n v\n env.parse(input, options) -- produces AST (using @handlebars/parser)\n |\n v\n compileEnvironment()\n |\n v\n Abstract_Compiler.compile(ast, options) -- produces opcodes and child environments\n |\n v\n JavaScriptCompiler.compile(environment, options, context, asObject)\n |\n v\n Output: template function or JSON spec\n```\n\n### Two Entry Points\n\n- **`compile(input, options, env)`** – Returns a reusable template function. Compilation is deferred until the first invocation (lazy compile, then cached).\n- **`precompile(input, options, env)`** – Returns a raw template specification object (JSON-serializable) that can be transmitted and later evaluated by `Handlebars.template()`.\n\nBoth call `compileEnvironment()` internally, which parses the input and runs the compiler pipeline.\n\n---\n\n## Detailed Class Diagram\n\n```mermaid\nclassDiagram\n class Compiler {\n +compile(program, options)\n +accept(node)\n +opcode(name, ...args)\n +classifySexpr(sexpr)\n +compileProgram(program)\n -opcodes[]\n -children[]\n }\n\n class JavaScriptCompiler {\n +compile(environment, options, context, asObject)\n -push(expr)\n -popStack(wrapped)\n -flushInline()\n -replaceStack(callback)\n -mergeSource(varDeclarations)\n -preamble()\n +append()\n +appendEscaped()\n +lookupOnContext(parts, falsy, strict, scoped)\n +nameLookup(parent, name)\n -internalNameLookup(parent, name)\n }\n\n class CodeGen {\n +push(source, loc)\n +prepend(source, loc)\n +wrap(chunk, loc)\n +merge()\n +quotedString(str)\n +objectLiteral(obj)\n +functionCall(fn, type, params)\n }\n\n class AST {\n +helpers.helperExpression(node)\n +helpers.scopedId(path)\n +helpers.simpleId(path)\n }\n\n Compiler ..> AST : uses helpers\n JavaScriptCompiler ..> CodeGen : uses for code output\n JavaScriptCompiler ..> Compiler : uses compilerInfo\n JavaScriptCompiler ..> AST : uses simpleId\n```\n\n---\n\n## Key Opcode Examples\n\n| Opcode | Stack effect | Description |\n|--------|--------------|-------------|\n| `pushContext` | → context | Pushes current context (depth0 or depths[N]) |\n| `lookupOnContext` | → value | Resolves property path on current context |\n| `lookupData` | → value | Resolves `@data` variable |\n| `pushString` | → string | Pushes a quoted string literal |\n| `pushLiteral` | → value | Pushes a raw literal (number, boolean, null, undefined) |\n| `pushProgram` | → programExpr | Pushes a sub-template (or null) |\n| `invokeHelper` | → result | Calls a helper function |\n| `invokeAmbiguous` | → result | Calls either a helper or falls back to context property |\n| `append` | buffer += ... | Appends a value to output buffer (with null handling) |\n| `appendEscaped` | buffer += escaped | Appends an escaped value |\n| `emptyHash` | → {} | Pushes an empty hash object |\n| `assignToHash` | hash[key] = value | Sets a hash key (pair popped from stack) |\n\n---\n\n## Runtime Integration\n\nThe compiled function expects a `container` object that provides runtime services. Key container properties accessed via `aliasable`:\n\n- `container.lambda` – Evaluate inline lambdas.\n- `container.escapeExpression` – HTML escape.\n- `container.hooks.blockHelperMissing` – Fallback for missing block helpers.\n- `container.hooks.helperMissing` – Fallback for missing regular helpers.\n- `container.lookupProperty` – Safe property access (used if provided; otherwise a default function is generated by `lookupPropertyFunctionIsUsed`).\n- `container.invokePartial` – Partial resolution and invocation.\n- `container.program` – Instantiate a compiled sub-program.\n- `container.data` – Access `@data` variables.\n- `container.strict` / `container.strictLookup` – Strict mode property access with error on missing.\n\n---\n\n## Usage Example (High-Level)\n\n```javascript\nimport Handlebars from 'handlebars';\n\n// compile() returns a function\nconst template = Handlebars.compile('Hello {{name}}!');\nconsole.log(template({ name: 'World' })); // \"Hello World!\"\n\n// precompile() returns a spec\nconst spec = Handlebars.precompile('Hello {{name}}!');\n// spec is a JSON-parseable object with compiler info and main function body\n```\n\n---\n\n## Notes\n\n- The compiler supports two source node implementations: a lightweight browser stub (`source-node.browser.js`) and the full `source-map` package (`source-node.node.js`). The correct version is selected at build time (typically via bundler aliasing).\n- The `JavaScriptCompiler.RESERVED_WORDS` table is used to avoid generating invalid JavaScript identifiers.\n- Strict mode (`options.strict`) generates additional runtime checks via `container.strict` and `container.strictLookup`.\n- The compiler deduplicates identical sub-programs by comparing their opcode sequences using `Compiler.prototype.equals()`.","javascript-handlebars-core":"# JavaScript Handlebars Core\n\n# JavaScript Handlebars Core Module\n\n## Overview\n\nThe **Handlebars Core** module provides the runtime environment for executing Handlebars templates. It separates the *compilation* phase (parsing and code generation) from the *execution* phase (rendering with data). The core exposes two main entry points:\n\n- **Full build** (`handlebars.js`): includes both compiler and runtime, suitable for browser usage where templates are compiled at runtime.\n- **Runtime-only build** (`handlebars.runtime.js`): includes only the runtime, intended for precompiled templates.\n\nBoth are built on a shared set of foundational components: environment, helpers, partials, decorators, and the rendering engine.\n\n## Architecture and Key Components\n\n### 1. `HandlebarsEnvironment` (`base.js`)\n\nThe central registry for helpers, partials, and decorators. It initialises default helpers and decorators, and provides `register`/`unregister` methods. The `create()` function in `handlebars.runtime.js` creates a new `HandlebarsEnvironment` and extends it with runtime utilities.\n\n```js\nlet hb = new base.HandlebarsEnvironment();\nUtils.extend(hb, base);\nhb.SafeString = SafeString;\n// ...\n```\n\n### 2. Runtime Engine (`runtime.js`)\n\nContains the core rendering logic:\n\n- **`template(templateSpec, env)`** – wraps a compiled template spec into a renderable function `ret`. It performs version checking, sets up the container object (providing property lookup, partial invocation, helper wiring), and returns `ret`.\n- **`checkRevision(compilerInfo)`** – validates compiler/runtime version compatibility.\n- **`invokePartial(partial, context, options)`** – executes a partial, handling `partial-block` propagation.\n- **`resolvePartial(partial, context, options)`** – resolves partial references by name.\n- **`wrapProgram(container, i, fn, ...)`** – creates a closure for a sub-program (block) with correct depth and data.\n- **`noop()`** – returns an empty string for falsy blocks.\n\n### 3. Compiler Integration (`handlebars.js`)\n\nThe full build imports the compiler and attaches its API to the Handlebars object:\n\n```js\nimport { Compiler, compile, precompile } from './handlebars/compiler/compiler.js';\nimport JavaScriptCompiler from './handlebars/compiler/javascript-compiler.js';\nhb.compile = (input, options) => compile(input, options, hb);\nhb.precompile = (input, options) => precompile(input, options, hb);\nhb.AST = AST;\nhb.Compiler = Compiler;\nhb.JavaScriptCompiler = JavaScriptCompiler;\nhb.Parser = Parser;\nhb.parse = parse;\nhb.parseWithoutProcessing = parseWithoutProcessing;\n```\n\nThe runtime build does **not** include these; instead, `env.compile` is checked optionally for dynamic partial compilation.\n\n### 4. Utilities (`utils.js`)\n\nShared helpers used across the codebase:\n\n- `escapeExpression(string)` – escapes HTML characters (`&<>\"'`=).\n- `extend(obj, ...sources)` – copies own properties.\n- `createFrame(object)` – creates a prototypal frame for data context.\n- `isEmpty(value)`, `isFunction(value)`, `isArray(value)`, `isMap(value)`, `isSet(value)`.\n\n### 5. SafeString\n\nA simple wrapper that prevents further escaping. Its `toString` and `toHTML` methods return the raw string.\n\n### 6. Logger (`logger.js`)\n\nA configurable logging utility used for warnings like proto-access denials. Levels: `debug`, `info`, `warn`, `error`.\n\n## Template Execution Flow\n\nThe rendering pipeline consists of several distinct stages:\n\n```mermaid\ngraph LR\n A[template()] --> B[checkRevision]\n A --> C[_setup]\n C --> D[createProtoAccessControl]\n C --> E[addHelpers / passLookupPropertyOption]\n C --> F[moveHelperToHooks]\n A --> G[executeDecorators]\n G --> H[main (compiled fn)]\n H --> I[container helpers/partials/decorators]\n I --> J[lookup / lookupProperty]\n J --> K[resultIsAllowed]\n K --> L[checkWhiteList]\n L --> M[logUnexpectedPropertyAccessOnce]\n```\n\n**Step-by-step:**\n\n1. **`template(spec, env)`** receives a compiled template object (`spec`) and a `HandlebarsEnvironment` (`env`). It checks revision compatibility via `env.VM.checkRevision(spec.compiler)`.\n\n2. A **container object** is created with methods for property lookup, partial invocation, lambda evaluation, etc. This object is passed to the compiled template function.\n\n3. **`_setup(options)`** is called on each render. It merges global and local helpers/partials/decorators, creates the proto-access control object, and moves `helperMissing`/`blockHelperMissing` into `container.hooks`.\n\n4. **`addHelpers`** wraps each helper function with `passLookupPropertyOption`, which injects `container.lookupProperty` into the helper options via `wrapHelper`. This allows helpers to respect prototype access controls.\n\n5. The compiled `main` function is executed with the container and context. It produces a string by invoking sub-expressions, blocks, and partials.\n\n6. **Property lookups** go through `container.lookup` or `container.strict` → `lookupProperty`. For each property access, `resultIsAllowed` checks the proto-access whitelist. Unauthorised accesses are logged once via `logUnexpectedPropertyAccessOnce`.\n\n7. **Partials** are resolved by `resolvePartial` and invoked by `invokePartial`. If a partial is missing and a compiler is available (`env.compile`), it will compile the partial on the fly.\n\n8. **Decorators** are applied via `executeDecorators` to both the top-level template and each sub-program.\n\n## Internal Utilities\n\n### Proto-Access Control (`internal/proto-access.js`)\n\nPrevents access to prototype properties by default. Two whitelists (properties and methods) can be configured at runtime via `allowedProtoProperties` and `allowedProtoMethods` options. The function `createProtoAccessControl` builds a control object used by `lookupProperty`.\n\n### Helper Wrapping (`internal/wrapHelper.js`)\n\n`wrapHelper(helper, transformOptionsFn)` returns a wrapper that modifies the options object before passing it to the helper. This is used to inject `lookupProperty` into helpers so they can perform safe lookups.\n\n### `no-conflict.js`\n\nSaves the previous `globalThis.Handlebars` and provides a `.noConflict()` method to restore it, mimicking the familiar jQuery pattern.\n\n## Export Structure (`index.js`, `runtime.js`)\n\nBoth builds re-export the Handlebars object as the default export. The runtime build (`runtime.js`) only exports the runtime module. Compiler-related members (`compile`, `precompile`, `AST`, `Parser`, `Compiler`, `JavaScriptCompiler`, `print`) are available only in the full build.\n\n```js\n// From index.js\nexport const { create, compile, precompile, parse, COMPILER_REVISION, VM, template, SafeString, ... } = handlebars;\nexport { PrintVisitor, print };\nexport default handlebars;\n```\n\nNamed exports (e.g. `COMPILER_REVISION`, `template`) are provided for CommonJS interoperability – tools like `handlebars-loader` rely on these being directly accessible via `require('handlebars')`.","javascript-handlebars-helpers-decorators":"# JavaScript Handlebars Helpers & Decorators\n\n# Handlebars Helpers & Decorators Module\n\nThis module provides the default built-in helpers (`#if`, `#each`, `#with`, etc.) and the inline decorator that ships with Handlebars. It also includes infrastructure for registering helpers, handling missing ones, and promoting helpers to runtime hooks.\n\n## Purpose\n\n- Define the standard set of block and expression helpers that every Handlebars template can use.\n- Provide a `blockHelperMissing` fallback that handles `{{#foo}}` when `foo` is a primitive, array, or object.\n- Implement the `helperMissing` fallback to either silently return `undefined` (for missing field syntax `{{foo}}`) or throw an error (for called helpers).\n- Move helpers into the runtime hooks system during template execution for non‑reentrant helpers (e.g., `helperMissing` and `blockHelperMissing` are moved by `moveHelperToHooks` to avoid re‑assignment during execution).\n- Register the `inline` decorator, which allows partials to be defined inline in template decorators.\n\n## Registration Flow\n\nAt `HandlebarsEnvironment` construction (in `handlebars/base.js`), `registerDefaultHelpers` and `registerDefaultDecorators` are called:\n\n```js\n// handlebars/base.js (simplified)\nexport class HandlebarsEnvironment {\n constructor() {\n registerDefaultHelpers(this);\n registerDefaultDecorators(this);\n }\n}\n```\n\nEach `register*` function calls `instance.registerHelper('name', fn)` (or `instance.registerDecorator` for decorators). The helpers are stored in `instance.helpers` (a map). The decorator is stored in `instance.decorators`.\n\nWhen a compiled template runs (via `_setup` in `runtime.js`), `moveHelperToHooks` moves the `helperMissing` and `blockHelperMissing` helpers from `instance.helpers` to `instance.hooks`. This makes them unavailable for direct template call but still accessible for the runtime’s resolution logic (preventing infinite recursion during execution).\n\n```mermaid\nflowchart LR\n A[HandlebarsEnvironment] --> B[registerDefaultHelpers]\n A --> C[registerDefaultDecorators]\n B --> D[blockHelperMissing]\n B --> E[each]\n B --> F[helperMissing]\n B --> G[if]\n B --> H[log]\n B --> I[lookup]\n B --> J[with]\n C --> K[inline decorator]\n L[Template execution] --> M[moveHelperToHooks]\n M --> N[hooks.helperMissing]\n M --> O[hooks.blockHelperMissing]\n```\n\n## Helper Implementations\n\nAll helpers are registered via `instance.registerHelper(name, fn)` and receive `(context, options)` (or `(conditional, options)` for if/unless, etc.). They return a string of rendered content.\n\n### `blockHelperMissing`\n- **Triggers** when a `{{#foo}}...{{/foo}}` is used and no explicit helper `foo` is defined.\n- Behavior:\n - `true`: render the block with current context (`fn(this)`).\n - `false`, `null`, `undefined`: render the inverse block (`inverse(this)`).\n - Array with length > 0: delegate to `#each`.\n - Array empty: render inverse.\n - Otherwise: render the block with the value as new context (`fn(context, options)`).\n\n### `#each`\n- Iterates over arrays, Map, Set, plain objects, and any iterable (detected via `Symbol.iterator`).\n- Sets `@index`, `@key`, `@first`, `@last` in the data frame.\n- Uses a one‑step offset for plain objects to detect the last iteration without scanning twice.\n\n### `helperMissing`\n- Two‑argument (options only, called as `{{foo}}`): returns `undefined` (silent miss).\n- More than one argument (called as `{{foo bar}}`): throws an error.\n\n### `#if` and `#unless`\n- Requires exactly one argument.\n- Treats `conditional` as falsy if `isEmpty` or if falsy && `options.hash.includeZero` is not set (i.e., `0` is truthy by default, but can be made falsy via `includeZero=true`).\n- `#unless` is a simple wrapper: swaps `fn` and `inverse`.\n\n### `#with`\n- Requires exactly one argument.\n- If `context` is non‑empty, sets it as the new block context (available as `this` inside the block).\n- If empty, renders inverse.\n\n### `log`\n- Logs messages at a configurable level.\n- Level can come from `options.hash.level` or `options.data.level` (default `1`).\n- Calls `instance.log(...args)`.\n\n### `lookup`\n- Used for dynamic property access: `{{lookup obj field}}`.\n- Returns `undefined` if `obj` is falsy (note: in v4.x it returns the falsy value; v5.0 will change to `== null` check).\n- Otherwise delegates to `options.lookupProperty(obj, field)` (the runtime’s safe property access).\n\n## Decorator Implementations\n\n### `inline`\n- Register decorator `inline`, which works similarly to a helper but is meant to wrap a template block.\n- It captures the block’s partial `options.fn` and stores it as a named partial under `props.partials[options.args[0]]`.\n- The returned function wraps the original `fn` and temporarily overrides `container.partials` with the new partials during execution, restoring the original after.\n- This allows inline partial definitions like `{{#*inline \"myPartial\"}}...{{/inline}}`.\n\n## Connections to the Rest of the Codebase\n\n| File | Connection |\n|------|------------|\n| `handlebars/base.js` | Calls `registerDefaultHelpers` and `registerDefaultDecorators` during `HandlebarsEnvironment` construction. |\n| `handlebars/runtime.js` | Calls `moveHelperToHooks` inside `_setup` for each template execution. |\n| `handlebars/utils.js` | Provides `isEmpty`, `isFunction`, `isArray`, `isMap`, `isSet`, `createFrame`, `extend`. |\n| `@handlebars/parser` | Provides `Exception` type used for error throwing. |\n\n## Key Design Decisions\n\n1. **Helper missing behavior** distinguishes between `{{foo}}` (field access) and `{{foo bar}}` (helper call) – this enables safe templating with missing variables.\n2. **`each` optimisation** for plain objects avoids allocating an intermediate keys array by iterating one step out‑of‑sync.\n3. **Move‑to‑hooks** mechanism ensures that `helperMissing` and `blockHelperMissing` are not re‑evaluated during execution, avoiding infinite recursion and improving performance.\n4. **Decorator partials** are implemented as a wrapper function that temporarily shadows the container’s partials – this keeps the global partials registry untouched.","net-handlebars-compatibility-layer":"# .NET Handlebars Compatibility Layer\n\n# .NET Handlebars Compatibility Layer\n\nThis module provides a drop-in compatible API surface that mirrors the original Handlebars.Net library (v1.x). It wraps the new core engine (`Handlebars.Engine`) behind the same class names, delegate types, and method signatures that existing Handlebars.Net users expect. Migrating to the new engine requires only changing the package reference – application code using `HandlebarsDotNet.Handlebars`, `HandlebarsDotNet.EncodedTextWriter`, `HandlebarsDotNet.Context`, etc. continues to work unchanged.\n\n## Overview\n\nThe compatibility layer is a thin set of adapters. It does **not** reimplement template parsing or execution. Instead, every public method on the familiar `Handlebars` static class translates its arguments into the core engine’s types and delegates all work to the new implementation. The same approach is used for helper registration, partial registration, and configuration.\n\n```\nUser Code (old API)\n │\n ▼\n Compatibility Layer\n ┌─────────────────────┐\n │ Handlebars (static) │──► calls core Handlebars.Engine\n │ Context │──► uses core RuntimeUtils\n │ EncodedTextWriter │──► delegates to TextWriter + optional encoding\n │ Arguments │──► wraps object[]\n │ HelperOptions │──► wraps core HelperOptions\n │ Delegates │──► signatures matching old API\n └─────────────────────┘\n │\n ▼\n Core Engine (Handlebars.Engine, Parser, Compiler, Runtime)\n```\n\n## Key Types and Their Roles\n\n### `Handlebars` (static class)\nThe main entry point. Mirrors the original static API exactly:\n\n- `Handlebars.Compile(string template)` → returns `HandlebarsTemplate<object, object>`\n- `Handlebars.Compile(TextReader template)` → returns `HandlebarsTemplate<TextWriter, object, object>`\n- `Handlebars.RegisterHelper(string, ...)` – six overloads covering all helper delegate types\n- `Handlebars.RegisterTemplate(string, string)` – registers a partial\n\nAll methods internally call the singleton `Core.Engine _engine = new()`. The returned template delegates are simple lambdas that call `_engine.Compile(template).Render(context ?? data!)`.\n\n### `Context` (readonly struct)\nWraps the current data object passed to a template. Its indexer `this[string segment]` performs property lookup using `Core.RuntimeUtils.LookupProperty`, the same mechanism used by the core engine. This ensures consistent behaviour (e.g. camelCase matching, null handling).\n\n### `Arguments` (readonly struct)\nRepresents the `{{helper arg1 arg2}}` arguments. It has constructors for 1–5 arguments plus a `params` array constructor, and implicit conversion from `object?[]`. Length and indexer provide safe access (out-of-range returns null).\n\n### `EncodedTextWriter` (struct, `IDisposable`)\nWraps a `TextWriter` and optionally applies HTML escaping. Methods `Write(string)`, `Write(StringBuilder)`, `Write(ReadOnlySpan<char>)`, `Write(string, params object[])`, `Write(char)`, `Write(object)`, `Write<T>()` all honour the `_encode` flag (unless `SuppressEncoding` is set). The `ToString()` method returns the underlying writer’s string content. Escaping is delegated to `Core.RuntimeUtils.EscapeExpression`.\n\n### `HandlebarsConfiguration` (class)\nExposes two properties that maps to core `CompileOptions`:\n- `ThrowOnUnresolvedBindingExpression` → `CompileOptions.Strict`\n- `NoEscape` → `CompileOptions.NoEscape`\n\nThe internal `ToCompileOptions()` method is used by the core engine (though currently the static `Handlebars` class does not pass configuration to the engine; this is a known gap that will be addressed).\n\n### `HelperOptions` / `BlockHelperOptions` / `DecoratorOptions` / `BlockDecoratorOptions`\nReadonly structs passed to helper delegates. They bundle the helper name, the current `Context`, a hash dictionary, and data dictionary. `BlockHelperOptions` additionally carries `Program` and `Inverse` delegates (representing the block body and else branch). These structs are constructed inside the adapter lambdas that wrap core helper registrations.\n\n### Delegate Types (in `Delegates.cs`)\nDefines nine delegate signatures that exactly match the original Handlebars.Net library. They are used as parameter types in the `RegisterHelper` overloads. The naming convention (e.g. `HandlebarsHelper`, `HandlebarsBlockHelper`, `HandlebarsTemplate<,,>`) makes it immediately recognisable to existing users.\n\n## The `Handlebars` Facade – Helper Registration Flows\n\nEach `RegisterHelper` overload constructs a lambda that bridges the legacy signature to the core engine’s `RegisterHelper` method. The table below summarises the mapping:\n\n| Legacy delegate signature | Core engine signature |\n|--------------------------|-----------------------|\n| `HandlebarsHelper` | `(TextWriter, object, object[])` |\n| `HandlebarsHelperWithOptions` | `(TextWriter, Core.HelperOptions, object, object[])` |\n| `HandlebarsReturnHelper` | `(TextWriter, object, object[])` – writes returned value |\n| `HandlebarsReturnWithOptionsHelper` | `(TextWriter, Core.HelperOptions, object, object[])` – writes returned value |\n| `HandlebarsBlockHelper` | `(TextWriter, Core.HelperOptions, object, object[])` | \n| `HandlebarsReturnBlockHelper` | `(TextWriter, Core.HelperOptions, object, object[])` – writes returned value |\n\nIn all cases the adapter:\n1. Creates an `EncodedTextWriter` from the output `TextWriter`\n2. Wraps the context object in `new Context(context)`\n3. Wraps the object array in `new Arguments(args)`\n4. For options-aware overloads, constructs the legacy `HelperOptions` or `BlockHelperOptions` from `Core.HelperOptions`\n5. Calls the user-provided legacy delegate\n6. If the delegate is a return helper, writes the returned value to the output writer\n\n## Integration with the Core Engine\n\nThe compatibility layer depends on the core `Handlebars` namespace (the new engine’s internal types). Key internal calls:\n\n- `Core.RuntimeUtils.EscapeExpression` – used by `EncodedTextWriter.Write` when encoding is enabled.\n- `Core.RuntimeUtils.LookupProperty` – used by `Context.this[string]`.\n- `Core.Engine.Compile` – used by `Handlebars.Compile`.\n- `Core.Engine.RegisterHelper` – used by all `Handlebars.RegisterHelper` overloads.\n- `Core.Engine.RegisterPartial` – used by `Handlebars.RegisterTemplate`.\n\nThe core engine’s `HelperOptions` struct is converted to the legacy `HelperOptions`/`BlockHelperOptions` structs using the `Name`, `Hash`, `Data`, `Program`, and `Inverse` properties.\n\n## Testing\n\nThe compatibility layer is exercised by tests in `CompatTests.cs`, which call `Handlebars.Compile` and `Handlebars.RegisterHelper` using the old API and verify rendering results. Test scenarios include:\n\n- Basic variable substitution with and without escaping\n- Inline helpers (`{{helper arg}}`) that write output\n- Inline helpers with options (`{{helper arg hash=value}}`)\n- Return-value helpers (output written from returned string)\n- Block helpers (`{{#helper}}...{{/helper}}`) with and without `else`\n- Partial registration and inclusion\n- `#each` loops \n- `#if` / `#else` blocks\n\nThese tests ensure the adapter behaves identically to the original library for common use cases.\n\n## Configuration Gap\n\nThe current `Handlebars` static class does **not** pass `HandlebarsConfiguration` to the core engine. Both `ThrowOnUnresolvedBindingExpression` and `NoEscape` are stored but never applied. A future update will integrate configuration by calling `_engine.Compile(template, Configuration.ToCompileOptions())` in the `Compile` methods.\n\n## Summary\n\nThe compatibility layer is a safety net for existing Handlebars.Net users. It provides:\n\n- Exact replica of the public API surface (types, delegates, method signatures)\n- Zero‑cost adaptation (only allocation of wrappers; no duplicate parsing logic)\n- Guaranteed behavioural parity for all standard template features\n\nWhen contributing to this module, always verify that any change preserves the mapping between legacy and core APIs, and run the full `CompatTests` suite.","net-handlebars-core":"# .NET Handlebars Core\n\n# Handlebars Core Module\n\nThis module implements a full Handlebars template engine in .NET, directly porting the architecture of handlebars.js v4+. It uses a stack-based bytecode interpreter rather than runtime code generation, making it AOT-safe and suitable for environments that restrict dynamic IL emit.\n\nThe core pipeline is: \n**Template string → Parser → AST → Compiler → Opcodes → BytecodeInterpreter → output**\n\n## Architecture Overview\n\n```mermaid\ngraph TD\n A[\"Template String\"] -->|Parser.Parse| B[\"AST (Program)\"]\n B -->|Compiler.Compile| C[\"CompiledProgram (Opcodes list)\"]\n C -->|BytecodeInterpreter.RenderData| D[\"Execute(opcodes)\"]\n D -->|per opcode| E[\"Output (TextWriter)\"]\n \n F[\"Engine\"] -->|Compile| C\n F -->|RegisterHelper/Partial/Decorator| G[\"Helper/Partial/Dict\"]\n G --> D\n C -->|Children| H[\"Nested CompiledPrograms\"]\n H -->|Closure| D\n```\n\nThe **Engine** is the public entry point. It manages helper/partial/decorator registrations, compiles templates with caching, and delegates rendering to the bytecode interpreter.\n\n## Key Components\n\n### Parser (`Parser.cs`)\n\nA recursive-descent parser that consumes a template string and produces an AST matching the `@handlebars/parser` output format. Key methods:\n\n- `static Program Parse(string template)` – entry point\n- `Program ParseProgram()` – top-level loop, dispatches to content and expression parsers\n- `Node ParseMustacheOrRelated()` – routes `{{...}}` to comment, raw block, mustache, block, partial, or decorator parsers\n- `BlockStatement ParseBlockOpening(...)` – handles `{{#path}}`, `{{^path}}`, including block params (`as |foo|`), `{{else}}`, `{{else if}}`, and closing tags\n- Whitespace control is applied during parsing via tilde strip flags on open/close delimiters.\n\n### AST (`Ast.cs`)\n\nImmutable records with JSON serialization support (for potential debugging or round-tripping). Important types:\n\n- `Node` – base class, polymorphic on `type` string\n- `Program` – root node, contains `Body`, `Strip`, `BlockParams`\n- `MustacheStatement`, `BlockStatement`, `PartialStatement`, `PartialBlockStatement`, `Decorator`, `DecoratorBlock`\n- `MustacheExpression` – base for `PathExpression`, `SubExpression`, `StringLiteral`, `NumberLiteral`, `BooleanLiteral`\n- `Hash` and `HashPair` – for `key=value` parameters\n- `StripFlags` – whitespace control markers (open/close), with `Empty`, `Default`, `OpenOnly`, `CloseOnly` presets\n\nAll nullable properties are omitted during JSON serialization when null, matching JavaScript `undefined` behavior.\n\n### Compiler (`Compiler.cs`)\n\nPort of handlebars.js `compiler.js`. It walks the AST and emits opcodes sequentially. State tracking includes:\n\n- `_opcodes` – current opcode list fragment\n- `_children` – list of nested `CompiledProgram`s (for blocks, inline partials)\n- `_blockParams` – current block params scopes\n- `_depths` – set of accessed context depths\n- `_useBloc`kParams, `_useDepths`, `_useDecorators` – feature detection flags\n\nKey methods:\n\n- `CompiledProgram Compile(Program ast)` – entry point, returns the root program with all children\n- `int CompileProgram(...)` – recursively compiles a nested program body, returns its ID in `_children`\n- `void Program(Program)` – processes body nodes with whitespace stripping, then `Accept`s each node\n- `void Accept(Node)` – dispatches to type-specific handlers\n- `void MustacheStatement(...)` – classifies the expression as helper, ambiguous, or simple, then calls appropriate emission\n- `void BlockStatement(...)` – handles block helpers, ambiguous blocks, and simple blocks\n- Classification helpers: `ClassifySexpr`, `ClassifyPath`, `IsSimpleId`, `IsEligibleSimpleId`\n- `void SetupFullMustacheParams(...)` – emits params, program/inverse closures, and hash\n- `void Emit(Opcode, params object[] args)` – adds an `OpcodeInfo` to `_opcodes`\n\nWhitespace control is implemented statically during compilation via methods like `StripElseStandalone`, `ApplyOpenStandalone`, `ApplyCloseStandalone`, and tilde strip helpers.\n\n### Opcodes (`Opcodes.cs`)\n\nThe full opcode set matches handlebars.js internal opcodes. Each is an `Opcode` enum value with an `object[]` of arguments.\n\n| Opcode | Purpose |\n|---|---|\n| `PushLiteral` | Push a raw literal value (number, bool) |\n| `PushString` | Push a string literal |\n| `PushProgram` | Push a child program closure (or null) |\n| `PushHash` | Begin collecting hash pairs |\n| `PopHash` | Complete hash and push the dictionary |\n| `PushContext` | Push current context at last `GetContext` depth |\n| `EmptyHash` | Push an empty dictionary or null |\n| `GetContext` | Set `_lastContextDepth` for subsequent `PushContext`/`LookupOnContext` |\n| `LookupOnContext` | Resolve a dotted path on the current/depth context |\n| `LookupBlockParam` | Resolve a block parameter by depth+index |\n| `LookupData` | Resolve a `@data` variable |\n| `ResolvePossibleLambda` | If top of stack is a delegate, invoke it as a lambda |\n| `InvokeHelper` | Call a registered helper by name (with fallback) |\n| `InvokeKnownHelper` | Call a helper known to exist (no fallback) |\n| `InvokeHelperReturn` | Call helper, capture output as string, push it (for sub-expression params) |\n| `InvokeAmbiguous` | Context-dependent: try helper, then fallback to path value |\n| `BlockValue` | Called for simple block expressions, delegates to `blockHelperMissing` |\n| `AmbiguousBlockValue` | Conditional on `_lastHelper` |\n| `Append` | Pop and append unescaped value |\n| `AppendEscaped` | Pop, HTML-escape, and append |\n| `AppendContent` | Append static content string |\n| `InvokePartial` | Render a partial by name |\n| `RegisterDecorator` | Register an inline partial or invoke a decorator |\n| `AssignToHash` | Assign top-of-stack to current hash with given key |\n\nThe `CompiledProgram` record holds the opcode list, children, compiler metadata, and feature flags.\n\n### BytecodeInterpreter (`BytecodeInterpreter.cs`)\n\nA stack-based VM that executes the compiled opcodes. Key state:\n\n- `_output` – the target `TextWriter`\n- `_stack` – value stack (`Stack<object?>`)\n- `_context` – current model object\n- `_depthsStack` – parent context frames for cascading lookups\n- `_data` – `@data` variables\n- `_helpers`, `_partials`, `_decorators` – dictionaries injected by the `Engine`\n- `_programs` – child `CompiledProgram`s (indexed by ID)\n- `_blockParams` – block parameter scopes\n- `_partialBlock` – `@partial-block` closure for partial blocks (`{{#> name}}`)\n- `_decoratorPartials` – inline partials registered via decorator syntax\n\nMain entry: \n- `void RenderData(CompiledProgram, object, TextWriter, Dictionary<string,object?>?)` – sets up state and calls `Execute(opcodes)`. \n- `void Execute(List<OpcodeInfo>)` – iterates through opcodes and dispatches to private `Do*` methods. \n- `void RenderClosure(ProgramClosure)` – executes a child program as a closure, saving/restoring interpreter state.\n\nHelper invocation uses a fast path for typed delegates (`Action<TextWriter, HelperOptions, object, object[]>` or `Action<TextWriter, object, object[]>`), falling back to `DynamicInvoke`.\n\nThe `ProgramClosure` nested class wraps a `CompiledProgram` and provides an `Invoke` method that temporarily swaps interpreter state to render the program in a given context.\n\n### Engine (`Engine.cs`)\n\nThe public API, equivalent to `HandlebarsEnvironment` in JS. Key members:\n\n- `static Engine Default { get; }` – singleton instance\n- `Engine(CompileOptions?)` – creates isolated instance with built-in helpers (`if`, `unless`, `each`, `with`, `lookup`, `log`, `helperMissing`, `blockHelperMissing`)\n- `Template Compile(string, CompileOptions?)` – parses, compiles, caches (SHA256-based key), returns a `Template` instance\n- `string Render(string, object)` – compile and render in one call\n- `RegisterHelper`, `UnregisterHelper`, `RegisterPartial`, `UnregisterPartial`, `RegisterDecorator`, `UnregisterDecorator` – register/unregister with instance-level dictionaries; increments `_configVersion` to invalidate cache\n\nThe `Template` class (not shown in full) holds the `CompiledProgram`, options, and a `BytecodeInterpreter`, and provides `Render(object)` and `Render(object, TextWriter)` methods.\n\n### Error Handling\n\n`HandlebarsException` extends `System.Exception` with `LineNumber` and `Column` properties. It formats messages in the pattern `\"message - line:col\"`, consistent with handlebars.js.\n\n## CompileOptions\n\nControls compilation behavior:\n\n- `CompilationMode` – currently only `Interpreted` (bytecode) is implemented\n- `KnownHelpers` – set of helper names to treat as known (avoids ambiguous classification)\n- `KnownHelpersOnly` – when true, only known helpers are classified as helpers; everything else is simple\n- `Strict` – throws on undefined properties (implies `AssumeObjects`)\n- `AssumeObjects` – skips existence checks for properties during lookups\n- `NoEscape` – disables HTML escaping\n- `PreventIndent` – prevents partial indentation\n- `ExplicitPartialContext` – ensures partials receive explicit context\n- `Compat` – enables recursive context chain lookup (Handlebars v2 compatibility)\n- `SrcName` – source name for debugging (unused in current code)\n\n## Usage Example\n\n```csharp\nvar engine = new Handlebars.Engine();\nengine.RegisterHelper(\"greet\", (TextWriter output, object context, object[] args) =>\n{\n output.Write($\"Hello, {args[0]}!\");\n});\n\nstring template = \"{{greet name}}\";\nstring result = engine.Render(template, new { name = \"World\" });\n// result: \"Hello, World!\"\n```\n\nInline partials and decorators are supported via the `{{#*inline}}` syntax, registered as decorators and rendered via `InvokePartial` and `RegisterDecorator`.","net-handlebars-helpers":"# .NET Handlebars Helpers\n\n# .NET Handlebars Helpers Module\n\n## Overview\n\nThis module implements the built-in Handlebars helpers that ship with the .NET Handlebars engine. Each helper is a static method in its own class, matching the original JavaScript handlers from `handlebars.js` (version 4.x). The module provides:\n\n- `#each` – iteration over arrays, objects, dictionaries, and enumerables.\n- `#if` / `#unless` – conditional rendering.\n- `{{log}}` – debug logging to trace output.\n- `{{lookup}}` – dynamic property access.\n- `#with` – context scope change.\n\nAll helpers are registered by the engine during template compilation and are invoked at render time via the `HelperOptions` callback pattern.\n\n## Helper Classes\n\n### EachHelper (`#each`)\n\n`EachHelper.Each()` iterates a collection passed as the first argument. It supports:\n\n- **IList** (e.g., `List<T>`, arrays)\n- **IDictionary** (key–value pairs)\n- **IEnumerable** (materialized to a list)\n- **System.Text.Json.JsonElement** (both arrays and objects)\n- **Scallar values** – treated as a single-item context, rendered if truthy, otherwise the inverse block.\n\nDuring iteration it creates a _data frame_ (a `Dictionary<string, object?>` with `index`, `key`, `first`, `last`, and a link to the parent data via `_parent`). This data is passed as the second parameter to the program closure, making it available inside the loop as `@index`, `@key`, `@first`, `@last`.\n\nIf no argument is provided, or the collection is null/empty, the inverse block (if any) is rendered.\n\n### IfHelper (`#if` and `#unless`)\n\n`IfHelper.If()` evaluates its single argument for truthiness (using `RuntimeUtils.IsTruthy` and `RuntimeUtils.IsEmpty`). Truthy values that are not empty trigger the main (`options.Program`) block; otherwise the inverse block is rendered.\n\n`IfHelper.Unless()` inverts the logic: renders the main block when the condition is falsy or empty.\n\nBoth helpers throw `HandlebarsException` if called with more or fewer than one argument.\n\n### LogHelper (`{{log}}`)\n\nWrites messages to `System.Diagnostics.Trace`. The `level` parameter can be set via hash arguments (e.g., `{{log level=2 \"message\"}}`). All positional arguments are joined with spaces and logged with a `[Handlebars <level>]` prefix. The default level is `1`.\n\n### LookupHelper (`{{lookup}}`)\n\nPerforms dynamic property access. Expects two arguments: an object and a property name. Uses `RuntimeUtils.LookupProperty` to resolve the value. If the value is non-null, it writes the string representation. Returns silently if arguments are missing, or if the object or field name is null.\n\n### WithHelper (`#with`)\n\nChanges the context for the enclosed block. The first argument becomes the new context if it is truthy; otherwise the inverse block runs with the original context. Supports delegates (e.g., sub-expressions) which are invoked with the current context.\n\n## Dependencies and Integration\n\nAll helpers depend on two utility members from the core runtime:\n\n| Helper | RuntimeUtils Method Used | Exception |\n|--------------|---------------------------------|---------------------|\n| EachHelper | `ConvertJsonElement` | – |\n| | `IsTruthy` | – |\n| IfHelper | `IsTruthy`, `IsEmpty` | `HandlebarsException` |\n| UnlessHelper | `IsTruthy`, `IsEmpty` | `HandlebarsException` |\n| LookupHelper | `LookupProperty` | – |\n| WithHelper | `IsTruthy` | – |\n\n`EachHelper.CreateDataFrame` is also called internally by the engine when handling block helpers that are not explicitly defined (see `BlockHelperMissing` in `Engine.cs`).\n\n```mermaid\ngraph TD\n subgraph Helpers\n Each[EachHelper.Each]\n If[IfHelper.If]\n Unless[IfHelper.Unless]\n Log[LogHelper.Log]\n Lookup[LookupHelper.Lookup]\n With[WithHelper.With]\n end\n\n subgraph Core Runtime\n RT[RuntimeUtils]\n Exception[HandlebarsException]\n Engine[Engine]\n end\n\n Each -->|ConvertJsonElement, IsTruthy| RT\n If -->|IsTruthy, IsEmpty| RT\n Unless -->|IsTruthy, IsEmpty| RT\n With -->|IsTruthy| RT\n Lookup -->|LookupProperty| RT\n If -->|throw| Exception\n Unless -->|throw| Exception\n Engine -->|registers| Helpers\n Engine -->|BlockHelperMissing calls| Each.CreateDataFrame\n```\n\n### Registration\n\nHelpers are registered in the `Engine` constructor or during configuration. The typical registration flow:\n\n1. Engine creates a `HandlebarsConfiguration` with default helpers.\n2. Each helper is wrapped as a `HandlebarsHelper` delegate matching the signature `(TextWriter, HelperOptions, object, object[])`.\n3. During template compilation, sub-expression `#if`, `#each`, etc. are mapped to these delegates.\n\n## Usage Examples\n\n```handlebars\n{{#each items}}\n {{@index}}: {{this.name}}\n{{/each}}\n\n{{#if user.isAdmin}}\n Admin panel\n{{/if}}\n\n{{log \"Rendering user:\" user.name level=2}}\n\n{{lookup person \"address\"}}\n\n{{#with user.preferences as |prefs|}}\n Theme: {{prefs.theme}}\n{{/with}}\n```\n\n## Implementation Notes\n\n- All helpers follow the same pattern: unwrap possible delegates, perform logic, invoke `options.Program` or `options.Inverse` (cast to `ProgramClosure`).\n- The `CreateDataFrame` method is public and shared; the engine reuses it when a block helper is missing and default iteration is attempted.\n- String values are explicitly not iterated (unlike JavaScript `for...of` on strings). This matches older Handlebars.js behavior.\n- The `LogHelper` does not write to the output stream; it only emits trace messages.\n- JSON element handling is performed eagerly – arrays and objects are converted to plain CLR types before iteration.","other-components":"# Other — components\n\n# Other — Components Module\n\n## Purpose\n\nThe **components** module provides distribution packaging configuration for Handlebars.js. It contains manifest files for multiple package managers and distribution systems, enabling developers to install Handlebars via their preferred tool (e.g., Bower, Composer, NuGet, RubyGems, JSPM). The module has no runtime code — it exists solely to describe how Handlebars.js should be packaged and consumed.\n\n## Key Files\n\n| File | Package System | Purpose |\n|------|----------------|---------|\n| `bower.json` | Bower (legacy) | Defines the Bower package name, version, and main file (`handlebars.js`). |\n| `component.json` | Component (legacy) | Older component format; explicitly lists scripts and main entry point. |\n| `composer.json` | Composer (PHP) | Packages Handlebars as a PHP component; requires `robloach/component-installer`. |\n| `handlebars-source.gemspec` | RubyGems | Wraps Handlebars.js source (`handlebars.js` and `handlebars.runtime.js`) into a Ruby gem called `handlebars-source`. |\n| `handlebars.js.nuspec` | NuGet (.NET) | Defines the NuGet package `handlebars.js` for use in .NET projects. |\n| `package.json` | npm / JSPM | Configures the package for JSPM module loader; sets main module, exports (`Handlebars`), and minification build settings. |\n\n## How It Works\n\nEach file follows the standard format of its respective ecosystem. When a developer runs a package manager command (e.g., `bower install handlebars`, `composer require components/handlebars.js`, `Install-Package handlebars.js`), these manifests are read to:\n\n- Determine which files to download (typically `handlebars.js` or `handlebars.runtime.js`).\n- Declare dependencies (if any).\n- Set up module exports or shims (e.g., `Handlebars` global).\n- Provide metadata such as version, license, author, and description.\n\nThe version number is kept consistent across all manifests: most currently specify `5.0.0-alpha.1`.\n\n## Dependencies\n\n- **Composer** (`composer.json`): Requires `robloach/component-installer` to install as a component.\n- **All others**: Declare no runtime dependencies; Handlebars is a standalone library.\n\n## Connection to the Codebase\n\nThese files reside in the `components/` subdirectory alongside the core Handlebars.js source. They are published when a release of Handlebars.js is cut, ensuring that each distribution channel receives the correct version. The actual runtime and compiler source code lives outside this module; these manifests **do not contain any JavaScript logic** but reference the main `handlebars.js` and `handlebars.runtime.js` files.\n\nDevelopers contributing to the packaging system should update all manifests in tandem when changing version numbers, license, or included files.","other-golden":"# Other — golden\n\n# Module: Other — golden\n\n## Overview\n\nThe `other — golden` module is a static test fixture suite for validating the Handlebars parser. It provides a set of input templates (`.hbs` files) and their corresponding expected ASTs (`.ast.json` files). A test runner loads each `.hbs` template, parses it with the parser under test, and asserts that the produced AST matches the golden JSON exactly.\n\nBecause this module contains only data files (no executable code), it has no internal, outgoing, or incoming function calls, and no execution flows.\n\n## File Pairs and Naming Convention\n\nEach test case consists of a pair of files:\n- `<n>.hbs` – the raw Handlebars template string\n- `<n>.ast.json` – the expected AST serialized as JSON\n\nThe index `n` runs from 0 to 29 (30 test cases total). The pairs are independent; the numbering does not imply any ordering beyond organizational convenience.\n\n## AST Node Types Covered\n\nThe golden suite exercises every core node type emitted by the parser:\n\n| Node Type | Description |\n|------------------------|-------------------------------------------------|\n| `Program` | Root of every AST; contains a `body` array |\n| `ContentStatement` | Static text content |\n| `MustacheStatement` | `{{...}}` expression (escaped or unescaped) |\n| `BlockStatement` | Block helper like `{{#if}}...{{/if}}` |\n| `DecoratorBlock` | Decorator `{{#*inline}}...{{/inline}}` |\n| `PartialStatement` | `{{> partial}}` |\n| `PartialBlockStatement`| `{{#> layout}}...{{/layout}}` |\n| `CommentStatement` | `{{! comment }}` |\n| `PathExpression` | Path reference (e.g., `name`, `foo.bar`, `../`) |\n| `NumberLiteral`, `BooleanLiteral`, `StringLiteral` | Literal parameter values |\n| `SubExpression` | Nested helper call `(subexpr param)` |\n| `Hash` / `HashPair` | Named arguments `key=value` |\n\n## Feature Coverage Table\n\n| # | Template | Key AST Nodes | Feature Tested |\n|----|---------------------------------|------------------------------------------------|----------------------------------------|\n| 0 | `Hello {{name}}!` | ContentStatement, MustacheStatement | Simple interpolation with text |\n| 1 | `{{#if active}}yes{{else}}no{{/if}}` | BlockStatement, inverse Program | Block helper with `else` branch |\n| 2 | `{{#each items}}item{{/each}}` | BlockStatement | Block helper (each) |\n| 3 | `{{^inverted}}body{{/inverted}}`| BlockStatement with only `inverse` | Inverse-only block |\n| 4 | `{{> partial}}` | PartialStatement | Partial include |\n| 5 | `{{#> layout}}body{{/layout}}` | PartialBlockStatement | Partial block (layout) |\n| 6 | `{{{unescaped}}}` | MustacheStatement, `escaped: false` | Unescaped interpolation |\n| 7 | `{{! comment here}}` | CommentStatement | Comment |\n| 8 | `{{helper param1 key=value}}` | MustacheStatement, Hash, HashPair | Helper with positional and hash args |\n| 9 | `{{helper (subexpr param)}}` | MustacheStatement, SubExpression | Subexpression as parameter |\n| 10 | `{{helper 42}}` | NumberLiteral | Number literal parameter |\n| 11 | `{{helper true false}}` | BooleanLiteral (true and false) | Boolean literal parameters |\n| 12 | `{{helper \"str\"}}` | StringLiteral | String literal parameter |\n| 13 | `{{foo.bar.baz}}` | PathExpression with `tail: [\"bar\",\"baz\"]` | Path lookup |\n| 14 | `{{../../parent}}` | PathExpression with `depth: 2` | Relative path (upward) |\n| 15 | `{{#each items as |item idx|}}it{{/each}}` | BlockStatement, `blockParams` | Block parameters (`as |item idx|`) |\n| 16 | `{{#*inline \"foo\"}}bar{{/inline}}` | DecoratorBlock | Decorator (inline partial) |\n| 17 | `before {{name}} after` | ContentStatement, MustacheStatement | Interpolation with surrounding text |\n| 18 | Identical to 17 | (same) | Duplicate test (retained for history) |\n| 19 | Identical to 2 | (same) | Duplicate test (retained for history) |\n| 20 | Identical to 3 | (same) | Duplicate test (retained for history) |\n| 21 | Identical to 4 | (same) | Duplicate test (retained for history) |\n| 22 | Identical to 5 | (same) | Duplicate test (retained for history) |\n| 23 | Identical to 8 | (same) | Duplicate test (retained for history) |\n| 24 | Identical to 10 | (same) | Duplicate test (retained for history) |\n| 25 | Identical to 11 | (same) | Duplicate test (retained for history) |\n| 26 | Identical to 9 | (same) | Duplicate test (retained for history) |\n| 27 | Identical to 16 | (same) | Duplicate test (retained for history) |\n| 28 | Identical to 15 | (same) | Duplicate test (retained for history) |\n| 29 | `{{~name}}` | MustacheStatement with `strip.open: true` | Whitespace stripping (open side) |\n\nThe duplicated tests (cases 17–28) are historical artifacts and are kept to preserve exact test expectations.\n\n## Usage in Test Suite\n\nThis module is consumed by a test harness that:\n\n1. Iterates over all golden pairs (typically by enumerating `0..29`).\n2. Reads `N.hbs` as a string.\n3. Parses the string using the parser’s `parse()` function (or equivalent entry point).\n4. Serializes the resulting AST to JSON.\n5. Loads `N.ast.json` and performs a deep comparison.\n6. Reports a failure if the two JSON structures differ.\n\nThe golden suite provides a precise, versioned baseline for parser correctness. Any change to the parser that alters the AST shape for these inputs must be reflected by updating the corresponding `.ast.json` file.","other-handlebars-compat":"# Other — Handlebars.Compat\n\n# Handlebars.Compat Module\n\n## Overview\n\nThe `Handlebars.Compat` module is a lightweight compatibility shim for the Handlebars.NET library. It provides an API surface for consumers who previously depended on the `Handlebars` class under an alternative namespace or who require a non‑breaking migration path when upgrading between major versions.\n\n## Purpose\n\n- Enable existing code that references `Handlebars` directly (without a fully qualified namespace) to continue compiling after the core library changed its default namespace or class naming.\n- Provide a single project reference that re‑exports the core `Handlebars` functionality under the alias `Core`, allowing explicit disambiguation when both `Handlebars` and other libraries share the same namespace.\n- Serve as a dedicated location for future backward‑compatibility work without polluting the main `Handlebars` project.\n\n## Architecture\n\nThe module is a minimal C# project with **no implementation files**. Its entire behavior is defined in the project file:\n\n```xml\n<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <TargetFramework>net10.0<\/TargetFramework>\n <ImplicitUsings>enable<\/ImplicitUsings>\n <Nullable>enable<\/Nullable>\n <RootNamespace>HandlebarsDotNet<\/RootNamespace>\n <\/PropertyGroup>\n\n <ItemGroup>\n <Using Include=\"Handlebars\" Alias=\"Core\" />\n <\/ItemGroup>\n\n <ItemGroup>\n <ProjectReference Include=\"..\\Handlebars\\Handlebars.csproj\" />\n <\/ItemGroup>\n<\/Project>\n```\n\nKey design decisions:\n\n- **Root namespace**: `HandlebarsDotNet` – matches the core library, so all types are automatically available without additional `using` directives.\n- **Alias directive**: `using Handlebars as Core;` makes the `Handlebars` class (from the core project) accessible under the alias `Core`. This allows a consumer to write `Core.Compile(...)` as a drop‑in replacement.\n- **Project reference**: Points directly to `..\\Handlebars\\Handlebars.csproj`, ensuring that any changes in the core library are immediately available.\n\n## How to Use\n\n1. **Add a reference** to `Handlebars.Compat` instead of (or in addition to) the core `Handlebars` project.\n\n2. **Use the alias** to access the static `Handlebars` API:\n\n```csharp\nusing Core; // provided by the compat module\n\nstring template = \"Hello {{name}}\";\nvar action = Core.Compile(template);\n```\n\nAlternatively, if you do not want the alias, you can still write:\n\n```csharp\nHandlebarsDotNet.Handlebars.Compile(template);\n```\n\nThe compat module does **not** introduce any new methods, overloads, or types – it is purely a namespace/alias convenience layer.\n\n## Relationship to the Main Module\n\n- **Dependency direction**: `Handlebars.Compat` depends on `Handlebars` (core). No dependency flows in the opposite direction.\n- **Code duplication**: None. All functionality is inherited via the project reference.\n- **Build output**: The compat module produces its own assembly (`Handlebars.Compat.dll`), but that assembly contains no compiled code – only the alias directive is evaluated at compile time for projects that consume it.\n\n## When to Use This Module\n\n- You have an existing codebase that references `Handlebars` directly and you want to migrate to the latest version of Handlebars.NET without rewriting every `using` statement.\n- You are building a library that exposes both `Handlebars` and another class named `Handlebars` (e.g., from a different package) and need to disambiguate via the `Core` alias.\n- You want to isolate compatibility concerns in a separate project for cleaner versioning and release management.","other-handlebars-js":"# Other — handlebars.js\n\n# Handlebars.js — Root Module Configuration\n\nThis module contains the project-level configuration and utility scripts for the Handlebars.js template engine. It is not a library itself, but the orchestration layer that defines how the library is built, linted, tested, and distributed.\n\n## Purpose\n\nThe root module provides:\n\n- **Build system** – Rspack-based bundling for browser distributions.\n- **Testing framework** – Vitest projects for Node, browser, and integration tests.\n- **Linting & formatting** – ESLint (browser compat) and oxlint/oxfmt.\n- **Golden file generation** – A script that produces reference outputs for regression testing.\n- **Package metadata** – npm package definition, exports, scripts, and dependencies.\n\n## Key Files\n\n| File | Role |\n|------|------|\n| `package.json` | Package metadata, scripts, dependencies, exports map. |\n| `rspack.config.js` | Rspack build configuration for UMD bundles (handlbars.js and handlbars.runtime.js, both minified and unminified). |\n| `vitest.config.js` | Multi-project Vitest setup: Node, browser, tasks, publish, and Rspack smoke tests. |\n| `eslint.config.js` | Flat ESLint config using `eslint-plugin-compat` to check browser API compatibility in `lib/` only. |\n| `generate_golden.js` | Script that runs a set of representative template compilations and writes results to a JSON file for golden comparison. |\n\n## Build System (`rspack.config.js`)\n\nThe build uses Rspack to create four UMD bundles:\n\n```\ndist/\n├── handlebars.js # Full compiler + runtime (unminified)\n├── handlebars.min.js # Full compiler + runtime (minified)\n├── handlebars.runtime.js # Runtime only (unminified)\n└── handlebars.runtime.min.js # Runtime only (minified)\n```\n\nThe function `createConfig(entry, filename, minimize)` encapsulates shared options:\n- **Entry** – either `./lib/handlebars.js` (full library) or `./lib/handlebars.runtime.js` (runtime subset).\n- **Output** – UMD with library name `Handlebars`, exported as default.\n- **Minification** – uses `SwcJsMinimizerRspackPlugin` with two compression passes.\n- **License banner** – prepended to both unminified (via `BannerPlugin`) and minified (via `preamble`) builds.\n- **Target** – `['web', 'browserslist']` ensuring browser compatibility.\n\n## Testing (`vitest.config.js`)\n\nVitest is configured with multiple **projects**, each with its own scope:\n\n```\nnode → spec/*.js (Node environment)\ntasks → tasks/tests/*.test.js (fork pool)\nrspack → tests/rspack/*.test.js\npublish → tasks/tests/publish-to-aws.test.js\nbrowser → spec/*.js (Chromium via Playwright, excludes precompiler/source-map tests)\n```\n\nCoverage thresholds are enforced at **99% statements, 98% branches, 100% functions, 99% lines** for `lib/` (excluding the source-node wrappers).\n\n## Linting (`eslint.config.js`)\n\nESLint is used exclusively for browser API compatibility checks. The flat config:\n- Ignores everything except `lib/`.\n- Applies `compat.configs['flat/recommended']` only to `lib/**/*.js`.\n- Reports unused disable directives as off (handled by oxlint).\n\nAll other linting (code style, correctness) is delegated to **oxlint** and formatting to **oxfmt**.\n\n## Golden File Generation (`generate_golden.js`)\n\nThis standalone script (`node generate_golden.js`) exercises a curated set of template–input–expected triples sourced from the test suite (basic, blocks, builtins). For each case it:\n1. Creates a fresh `Handlebars` environment via `Handlebars.create()`.\n2. Compiles the template with optional compile options.\n3. Executes with input and optional runtime options.\n4. Records the result (or error) alongside the expected output.\n\nThe output is written to `/tmp/golden_results.json` as a JSON array. Any mismatches between `result` and `expected` are printed to the console. This is used to detect regressions after parser or compiler changes.\n\n## Architecture Overview\n\n```mermaid\nflowchart LR\n subgraph Build\n rspack.config.js -->|bundles| dist/handlebars.js\n rspack.config.js -->|bundles| dist/handlebars.min.js\n rspack.config.js -->|bundles| dist/handlebars.runtime.js\n rspack.config.js -->|bundles| dist/handlebars.runtime.min.js\n end\n\n subgraph Test\n vitest.config.js --> spec/*.js[node]\n vitest.config.js --> spec/*.js[browser]\n vitest.config.js --> tasks/tests\n vitest.config.js --> tests/rspack\n end\n\n subgraph Lint\n eslint.config.js --> lib/*.js[compat]\n oxlint -->|all JS| lib/*.js\n oxfmt -->|format| .\n end\n\n subgraph Golden\n generate_golden.js --> lib/index.js\n generate_golden.js --> /tmp/golden_results.json\n end\n\n package.json --> scripts\n scripts --> build,test,lint,golden\n```\n\n## Integration with the Codebase\n\n- The library’s source lives under `lib/` (not shown here as separate modules). This root module configures how those sources are compiled, tested, and linted.\n- The `generate_golden.js` script directly imports `lib/index.js` and serves as a high-level integration test for the compiler and runtime.\n- Rspack bundles are consumed by the browser test project and by downstream users via the `dist/` directory.\n- Package exports (`\".\"`, `\"./runtime\"`, `\"./package.json\"`) define public API surfaces for Node and bundler consumers.","other-handlebars-test":"# Other — Handlebars.Test\n\n# Handlebars.Test — Test Suite\n\nThe `Handlebars.Test` project contains the complete test suite for the Handlebars library. It is a xUnit project targeting .NET 10, referencing both the core library (`Handlebars`) and the compatibility layer (`Handlebars.Compat`). The tests are largely ported from the official [handlebars.js test suite](https://github.com/handlebars-lang/handlebars.js/tree/master/spec), ensuring behavioral parity with the reference JavaScript implementation.\n\n## Purpose\n\nThe test suite validates every stage of the Handlebars pipeline:\n\n- **Parsing** – AST construction from template strings via `Parser.Parse()`\n- **Compilation** – Opcode generation from AST via `Compiler.Compile()`\n- **Rendering** – Template execution with various data models, helpers, and partials\n- **Helper and decorator integration** – Block helpers, sub-expressions, hash arguments, `helperMissing`, `blockHelperMissing`\n- **Built-in helpers** – `#if`, `#unless`, `#each`, `#with`, `#log`, `#lookup`\n- **Whitespace control** – `~` strip markers around mustaches, blocks, and partials\n- **Compat mode** – Recursive context lookups, `KnownHelpersOnly`\n- **Golden-file regression** – AST serialization/deserialization match against Node.js output\n\nThe tests also serve as **executable specifications**, directly documenting expected behavior for edge cases, error handling, and API contracts.\n\n## Architecture\n\n```\n┌─────────────────────────────┐\n│ TestHelper │\n│ Fluent builder: Expect │\n│ .Template() .WithInput() │\n│ .WithHelper() .ToCompileTo()│\n└───────────┬─────────────────┘\n │ uses\n ▼\n┌─────────────────────────────┐\n│ Handlebars Engine API │\n│ Engine.Compile() │\n│ Parser.Parse() │\n│ Compiler.Compile() │\n│ Template.Render() │\n└─────────────────────────────┘\n ▲\n │ tests\n┌───────────┴─────────────────┐\n│ Test Classes │\n│ BasicTests, BlocksTests, │\n│ BuiltinsTests, HelperTests, │\n│ ParserTests, CompilerTests, │\n│ PartialTests, etc. │\n└─────────────────────────────┘\n```\n\nThe fluent `Expect` helper (defined in `TestHelper.cs`) lowers boilerplate by chaining template, data, helpers, partials, compile options, and assertion into a single expression.\n\n## Key Test Categories\n\n### 1. Parser Tests (`ParserTests.cs`)\n\nVerify AST node types and properties against golden JSON files generated by the handlebars.js parser. Covers:\n\n- Simple `{{name}}`\n- Block with `{{else}}`\n- Escaped vs unescaped `{{{ }}}`\n- Comments `{{! }}`\n- Dotted paths `{{foo.bar.baz}}`\n- Depth paths `{{../../parent}}`\n\nGolden files are stored under `test/golden/parser/` and loaded by index. The test re-serializes the parsed AST and compares structural equivalence.\n\n### 2. Compiler Tests (`CompilerTests.cs`)\n\nVerify opcode sequences produced by `Compiler.Compile()`. For example:\n\n- `\"Hello {{name}}!\"` emits 9 opcodes including `GetContext`, `LookupOnContext`, `ResolverPossibleLambda`, `InvokeAmbiguous`, `AppendEscaped`\n- Known helpers produce `InvokeKnownHelper` instead of `InvokeAmbiguous`\n- Comments produce zero opcodes\n- Partial templates set `UsePartial` and emit `InvokePartial`\n- Decorator blocks set `UseDecorators` and emit `RegisterDecorator`\n\n### 3. Rendering Tests (`RenderingTests.cs`)\n\nBasic integration tests covering:\n\n- Simple path interpolation\n- Escaped vs unescaped output (HTML encoding)\n- Block helpers `#if`/`#else`\n- `#each` iteration\n- Comments rendering nothing\n- Dotted path resolution\n- Missing helpers throwing\n\n### 4. Basic Tests (`BasicTests.cs`)\n\nPorted from handlebars.js `spec/basic.js`. Tests core Mustache semantics:\n\n- Most basic variable interpolation\n- Backslash escaping (`\\{{foo}}`, `\\\\{{foo}}`)\n- Multi-line templates\n- Compiling with string, object, and undefined contexts\n- Comments and comment whitespace stripping (`{{~! ~}}`, `{{~!-- --~}}`)\n- Boolean, zero, and false values as block conditions\n- Paths with hyphens\n- Nested paths, empty strings, null/empty intermediate objects\n- The `this` keyword in paths and helpers\n- Newlines and escaping in text/expressions\n\n### 5. Block Tests (`BlocksTests.cs`)\n\nPorted from `spec/blocks.js`. Covers:\n\n- Array iteration with `{{#goodbyes}}...{{/goodbyes}}`\n- Empty blocks\n- Complex lookups with `../` parent references\n- Deeply nested blocks\n- Inverted sections (`{{^goodbyes}}`)\n- Standalone `{{else}}` with whitespace stripping\n- Compat mode for deep recursive lookups\n- Decorator application (mustache and block decorators)\n\n### 6. Built-in Helper Tests (`BuiltinsTests.cs`)\n\nExhaustively tests `#if`, `#unless`, `#with`, `#each`, `#log`, and `#lookup`:\n\n- Conditional truthiness (booleans, strings, arrays, functions, zero)\n- `#with` context scoping and `#else` fallback\n- `#each` with arrays, dictionaries, `@index`, `@key`, `@first`, `@last`\n- Block params (`as |value index|`)\n- Nested `#each` and `@first`/`@last` scoping\n- `#log` renders empty string\n- `#lookup` for dynamic property access\n\n### 7. Helper Tests (`HelperTests.cs`)\n\nPorted from `spec/helpers.js`. Tests:\n\n- Block helpers with identical and complex lookups\n- Helpers returning undefined\n- Block helpers staying in context vs passing new context\n- Nested block helpers\n- Inverted block helpers (`else`)\n- Hash arguments (positional + key=value)\n- Boolean hash arguments\n- `helperMissing` and custom fallback\n- `KnownHelpers` and `KnownHelpersOnly` modes\n- `blockHelperMissing` resolution\n- Lambda resolution in ambiguous calls\n- Name field propagation in `HelperOptions`\n- Block params precedence over context, helpers, and parent block params\n- Argument validation (`#if`/`#unless` too few/many args)\n\n### 8. Partial Tests (`PartialTests.cs`)\n\nPorted from `spec/partials.js`. Covers:\n\n- Basic inline partials `{{#*inline \"name\"}}...{{/inline}}`\n- Registered partials via `RegisterPartial`\n- Dynamic partials via sub-expressions `{{> (helper)}}`\n- Partial within partial (pipeline)\n- Slash paths, integer partial names\n- Empty partials\n- `ToThrow` for missing partials\n\n### 9. Whitespace Tests (`WhitespaceTests.cs`)\n\nVerifies whitespace stripping around mustaches (`{{~`), blocks (`{{#if~}}`), and partials (`{{>~}}`). Tests both sides and newline handling.\n\n### 10. Compatibility Tests (`CompatTests.cs`)\n\nUses the `Handlebars.Compat` assembly (namespace `HandlebarsDotNet`) to verify the high-level API:\n\n- `HandlebarsDotNet.Handlebars.Compile()` and `RegisterHelper()`\n- Helper overloads: `EncodedTextWriter`, `Context`, `Arguments`\n- Return-value helpers\n- If/else and each loops\n- Escaped and unescaped output\n\n### 11. Golden Render Tests (`GoldenRenderTests.cs`)\n\nInline golden test cases that compare C# output against known JavaScript results. Uses `Engine.Default` for rendering. Covers:\n\n- Basic, escaping, comments, if/unless, each, with, lookup\n- String context, undefined context, null context\n- Escaped backslash, whitespace stripping\n- Dictionary iteration with block params\n\n### 12. AST Serialization Tests (`AstSerializationTests.cs`)\n\nEnsures AST nodes serialize/deserialize correctly to JSON (using `System.Text.Json`). Tests `Program`, `MustacheStatement`, `PathExpression`, `BooleanLiteral`, `StripFlags`.\n\n### 13. Data Tests (`DataTests.cs`)\n\nPorted from `spec/data.js`. Tests `@`-prefixed variables:\n\n- `@root`, `@index`, `@first`, `@last`, `@key`\n- Data frame inheritance through nested blocks\n- Custom data helpers via `opts.Hash`\n\n### 14. Regression Tests (`RegressionTests.cs`)\n\nTests for specific bugs and edge cases from GitHub issues:\n\n- `GH94` – null author property in nested objects\n- `GH150` – inverted sections with falsy values\n- `GH408` – multiple `{{#.}}` loops\n- `GS428` – nested if/else rendering\n- `GH375` – Unicode line terminators\n\n### 15. Strict Tests (`StrictTests.cs`)\n\nPorted from `spec/strict.js`. Tests `CompileOptions.Strict` mode which throws on missing properties instead of rendering empty. Also covers `ExplicitUndefined`, `AssumeObjects`, and `NoEscape` options.\n\n### 16. Subexpression Tests (`SubExpressionTests.cs`)\n\nPorted from `spec/subexpressions.js`. Tests nested helper calls `{{helper (inner param)}}` in both mustache and block contexts, with hash arguments.\n\n## Connecting to the Codebase\n\nThe test project references two source projects:\n\n- **Handlebars** – Core library containing `Engine`, `Parser`, `Compiler`, `Template`, `ProgramClosure`, `HelperOptions`, etc.\n- **Handlebars.Compat** – Backward-compatible wrapper providing the `HandlebarsDotNet` API.\n\nThe tests exercise the public API surface directly. Helper and partial registrations go through `Engine.RegisterHelper()`, `Engine.RegisterPartial()`, `Engine.RegisterDecorator()`. Rendering uses `Engine.Compile(template).Render(data)`.\n\nThe `Expect` builder internally calls these same APIs, providing a fluent shorthand.\n\n## Test Helpers and Utilities\n\n- **`Expect`** (static class in `TestHelper.cs`) – Fluent builder with methods: `Template(string)`, `WithInput(object)`, `WithHelper(string, Delegate)`, `WithHelpers(Dictionary)`, `WithPartial(string, string)`, `WithPartials(Dictionary)`, `WithDecorator(string, Action)`, `WithCompileOptions(CompileOptions)`, `ToCompileTo(string)`, `ToThrow(string)`.\n- **`RuntimeUtils.LookupProperty`** – Reflection-based property access, used in helper lambdas.\n- **`ProgramClosure`** – Represents a compiled child program, used inside block helpers to invoke the main and inverse programs.\n\n## Running the Tests\n\n```\ndotnet test src/Handlebars.Test/Handlebars.Test.csproj\n```\n\nThe test project uses xUnit and standard .NET test infrastructure. Some tests are marked `[Fact(Skip = \"...\")]` indicating known behavioral differences from handlebars.js (e.g., parser rejecting certain syntax, missing `else if` support, decorator pipeline limitations).","other-handlebars-testapp":"# Other — Handlebars.TestApp\n\n# Handlebars.TestApp — Command-Line Template Renderer\n\n## Overview\n\n`Handlebars.TestApp` is a minimal console application that demonstrates and tests the core **Handlebars** library. It loads a Handlebars template from disk, optionally merges it with a JSON context file, then renders the result to standard output. It serves as both a development/testing tool and a quick reference for the library's API.\n\n## Usage\n\n```text\nHandlebars.TestApp <template> [values.json]\n```\n\n- **`<template>`** — path to a `.hbs` file. If the path is relative, it is resolved relative to the `templates/` directory inside the application's output folder.\n- **`values.json`** (optional) — JSON file containing the context data passed to the template. If omitted, an empty object is used.\n\n### Examples\n\n```bash\n# Render hello.hbs with hello.json\nHandlebars.TestApp hello.hbs hello.json\n\n# Render advanced.hbs with advanced.json (template uses #if and #each)\nHandlebars.TestApp advanced.hbs advanced.json\n\n# Render a template without context\nHandlebars.TestApp absolute/path/template.hbs\n```\n\n## Architecture & Execution Flow\n\nThe application follows a linear pipeline:\n\n1. **Argument validation** — checks that a template argument is provided and the file exists.\n2. **Context loading** — reads the optional JSON file and deserializes it into either a `Dictionary<string, object>` (for objects) or a `List<object>` (for arrays). Defaults to an empty anonymous object.\n3. **Template compilation** — reads the template file content and uses `Handlebars.Engine.Compile(template)` to produce a compiled `Template` object.\n4. **Rendering** — calls `compiled.Render(model)` and writes the result to stdout.\n\n```\n┌─────────────┐ ┌──────────────┐ ┌────────────┐ ┌───────────┐\n│ Startup │────>│ Parse args │────>│ Load JSON │────>│ Compile │\n│ (Program.cs)│ │ & resolve │ │ context │ │ template │\n└─────────────┘ │ paths │ └────────────┘ └──────┬────┘\n └──────────────┘ │\n v\n ┌──────────┐\n │ Render │\n │ & output │\n └──────────┘\n```\n\n## Key Components\n\n### `Program.cs` (Entry Point)\n\n- **`Main(string[] args)`** — the `static int Main` method (top-level statements in modern C#). Returns exit code 0 on success, 1 on error.\n- **`ResolvePath(string path)`** — resolves a relative template/JSON path by combining it with `AppContext.BaseDirectory/templates/`. If the path is already absolute (`Path.IsPathRooted`), it is returned unchanged.\n\nThe application uses `System.Text.Json` for JSON deserialization. It treats JSON objects as `Dictionary<string, object>` and JSON arrays as `List<object>`. This matches the convention used by the Handlebars library for dynamic model objects.\n\n### Templates (`templates/` directory)\n\nFour sample files are distributed with the application:\n\n| File | Description |\n|----------------|--------------------------------------------------|\n| `hello.hbs` | Simple `Hello {{name}}!` |\n| `hello.json` | `{\"name\": \"World\"}` |\n| `advanced.hbs` | Demonstrates `{{#if}}`, `{{nested.*}}`, `{{#each}}` |\n| `advanced.json` | Complex context with nested object and array |\n\nThe `.hbs` files are copied to the output directory as `Content` with `PreserveNewest`.\n\n## Connection to the Handlebars Library\n\n`Handlebars.TestApp` consumes the `Handlebars` project via a `ProjectReference` in its `.csproj`. The key library APIs used are:\n\n- **`Handlebars.Engine`** — instantiated with `new Engine()`. No custom configuration is applied.\n- **`Engine.Compile(string template)`** — returns a `Template` object (type `Handlebars.Template`).\n- **`Template.Render(object model)`** — renders the compiled template with the provided model and returns a `string`.\n\nThe `model` object can be an anonymous type, a `Dictionary<string, object>`, or a `List<object>` — the Handlebars library handles all common .NET types natively.\n\n## Sample Output\n\nUsing `advanced.hbs` with `advanced.json` produces:\n\n```\nHello Pavel!\nDOB: 1990-01-01\nAge: 30\nIs Active: True\nHere are some fruits:\n\n - apple\n - banana\n - cherry\n```\n\n## Build & Run\n\nThe project targets .NET 10. Build and run from the solution root:\n\n```bash\ndotnet run --project src/Handlebars.TestApp -- hello.hbs hello.json\n```","other-handlebars":"# Other — Handlebars\n\n# Handlebars Module\n\n## Overview\n\nThe **Handlebars** module provides a lightweight, AOT-compatible implementation for rendering [Handlebars](https://handlebarsjs.com/) templates. It is designed to be used as a self-contained library with no external dependencies. Currently, the module serves as a project shell; all public APIs are yet to be implemented.\n\n## Project Configuration\n\n- **Target framework:** `net10.0`\n- **Language features:** Implicit usings, nullable reference types enabled\n- **AOT compatibility:** `IsAotCompatible=true` — the module is ready for Native AOT deployment.\n- **Test accessibility:** `InternalsVisibleTo` granted to the `Handlebars.Test` assembly, allowing unit tests to access internal types and members.\n\n## Project Structure\n\n```\nsrc/Handlebars/\n├── Handlebars.csproj\n├── (future source files)\n└── (future public API)\n```\n\nThe module contains no source files at this time. It is a placeholder for a future Handlebars template engine implementation.\n\n## Intended Responsibilities\n\nOnce implemented, the module will be responsible for:\n\n- Parsing Handlebars template strings into an AST (Abstract Syntax Tree).\n- Compiling the AST into executable render functions.\n- Evaluating templates against a data context.\n- Supporting built-in helpers (e.g., `if`, `each`, `with`) and custom helper registration.\n- Maintaining AOT compatibility to avoid runtime code generation.\n\n## Integration with the Codebase\n\nThis module is an independent library within the `Other` category. It does not currently reference or depend on any other project in the solution. Similarly, no other project depends on it. Its primary consumer will be any application that needs server‑side template rendering without external runtime dependencies.\n\n## Testing Strategy\n\nUnit tests reside in the sibling project `Handlebars.Test` (not shown here). The `InternalsVisibleTo` attribute enables white‑box testing of internal parsing and compilation logic.\n\n## Next Steps\n\n- Define the public API (e.g., `Handlebars.Compile(string template)` and `Handlebars.Render(string template, object data)`).\n- Implement the parser, compiler, and runtime evaluation engine.\n- Add comprehensive test coverage for all helpers and edge cases.\n\n---\n\n*No architecture diagram is necessary for this module because it currently contains no components and has no connections to other modules.*","other-spec":"# Other — spec\n\n# Handlebars.js Test Suite (spec Module)\n\n## Overview\n\nThe `spec` module (contained in `handlebars.js/spec/`) is the comprehensive test suite for the Handlebars templating engine. It validates all core features including parsing, compilation, runtime execution, built-in helpers, custom helpers, partials, decorators, data handling, security constraints, and regression fixes. Tests are written in Jasmine (BDD style) and are executed both in Node.js and in browsers via a smoke test.\n\n## Architecture\n\nThe test suite is organized by feature area. Each spec file focuses on a specific set of Handlebars capabilities. Tests use a shared helper infrastructure (`expectTemplate`, `CompilerContext`, `handlebarsEnv`) to reduce boilerplate and ensure consistent behavior.\n\n```mermaid\ngraph TD\n subgraph \"Spec Files\"\n AST[ast.js]\n BASIC[basic.js]\n BLOCKS[blocks.js]\n BUILTINS[builtins.js]\n COMPILER[compiler.js]\n DATA[data.js]\n HELPERS[helpers.js]\n PARTIALS[partials.js]\n PRECOMPILER[precompiler.js]\n REGRESSIONS[regressions.js]\n SECURITY[security.js]\n SOURCEMAP[source-map.js]\n UTILS[utils.js]\n JAVASCRIPT_COMPILER[javascript-compiler.js]\n end\n\n subgraph \"Core Libraries\"\n BASE[lib/handlebars/base.js]\n COMPILER_LIB[lib/handlebars/compiler.js]\n RUNTIME[lib/handlebars/runtime.js]\n UTILS_LIB[lib/handlebars/utils.js]\n PARSER[lib/handlebars/parser.js]\n AST_LIB[lib/handlebars/compiler/ast.js]\n end\n\n BASIC -->|expectTemplate| COMPILER_LIB\n BLOCKS -->|registerDecorator, unregisterDecorator| BASE\n BUILTINS -->|registerHelper| BASE\n HELPERS -->|registerHelper, unregisterHelper| BASE\n PARTIALS -->|registerPartial, unregisterPartial| BASE\n COMPILER -->|compile, precompile| COMPILER_LIB\n COMPILER -->|equals| AST_LIB\n AST -->|helperExpression| AST_LIB\n AST -->|parse| PARSER\n DATA -->|createFrame| RUNTIME\n SECURITY -->|resetLoggedPropertyAccesses| BASE\n REGRESSIONS -->|registerHelper, registerPartial| BASE\n REGRESSIONS -->|escapeExpression| UTILS_LIB\n UTILS -->|toHTML?| UTILS_LIB\n JAVASCRIPT_COMPILER -->|nameLookup, compilerInfo| COMPILER_LIB\n PRECOMPILER -->|cli| lib/precompiler.js\n```\n\n## Key Components\n\n### Spec Files\n\n| File | Focus |\n|------|-------|\n| `ast.js` | AST node structure, helper expression detection, line/column location |\n| `basic.js` | Fundamental expression evaluation, escaping, context types (booleans, zeros, functions), string/number/boolean literals |\n| `blocks.js` | Block helpers, inverted sections, decorators (registration, execution, nesting) |\n| `builtins.js` | Built-in helpers: `#if`, `#with`, `#each`, `#log`, `#lookup` (including iteration over Maps, Sets, iterables) |\n| `compiler.js` | `Handlebars.compile`, `Handlebars.precompile`, AST-based compilation, error location, option validation |\n| `data.js` | `@data` variables (`@foo`, `@root`, `@index`, etc.), data inheritance, frame creation |\n| `helpers.js` | Custom helper registration, parameter passing, hash options, helperMissing, knownHelpers, block params, name conflicts |\n| `partials.js` | Partial template inclusion, parameterized partials, dynamic partials |\n| `precompiler.js` | CLI precompiler tool, file loading, template naming, output options |\n| `regressions.js` | Regression tests for known issues (cross-version compatibility, edge cases) |\n| `security.js` | Prototype property access restrictions, `lookupProperty` safety |\n| `source-map.js` | Source map generation correctness |\n| `utils.js` | Utility functions (SafeString, escapeExpression, etc.) |\n| `javascript-compiler.js` | API override points (`nameLookup`, `compilerInfo`, buffer initialization) |\n\n### Test Infrastructure\n\n- **`expectTemplate`**: Core test helper that creates a template from a string, sets input data, helpers, options, and compiles to a target output.\n - `.withInput(data)` – provides context\n - `.withHelpers(helpers)` – registers local helpers\n - `.withHelper(name, fn)` – single helper\n - `.withCompileOptions(options)` – compile-time flags (`compat`, `knownHelpersOnly`, `data`, `strict`)\n - `.withRuntimeOptions(options)` – runtime data overrides\n - `.toCompileTo(expected)` – asserts compiled output\n - `.toThrow(Error, message)` – asserts error\n\n- **`CompilerContext`**: Bridges browser and Node environments, provides `compile` / `template` functions, manages `Handlebars` instance.\n\n- **`handlebarsEnv`**: Global `Handlebars` object used for registration and configuration in tests.\n\n### Artifacts / Fixtures\n\nThe `spec/artifacts/` directory contains sample template files (`*.handlebars`, `*.hbs`) used by precompiler tests and partial tests. The `spec/expected/` directory holds expected output strings for precompilation tests.\n\n## Integration with Core Libraries\n\nTests exercise the full Handlebars pipeline:\n\n1. **Parsing**: `Handlebars.parse()` (from `lib/handlebars/parser.js`)\n2. **AST validation**: `helperExpression` in `lib/handlebars/compiler/ast.js`\n3. **Compilation**: `Handlebars.compile()` and `Handlebars.precompile()` from `lib/handlebars/compiler.js`\n4. **Runtime execution**: `VM.template`, `executeDecorators`, `lookupProperty` from `lib/handlebars/runtime.js`\n5. **Helper/decorator registration**: `registerHelper`, `registerDecorator`, etc. from `lib/handlebars/base.js`\n6. **Utility functions**: `escapeExpression`, `SafeString` from `lib/handlebars/utils.js`\n\n## Execution Flow Example\n\nA typical test in `blocks.js` for a decorator:\n\n```\nspec/blocks.js → registerDecorator(lib/handlebars/base.js)\n → Handlebars.compile(lib/handlebars/compiler.js)\n → runtime: program → wrapProgram → executeDecorators → decorator function\n → output assertion\n```\n\nThis pattern ensures that both compile-time and runtime behavior are validated together.\n\n## Smoke Test\n\nThe file `spec/index.html` provides a minimal browser-based smoke test that verifies the UMD bundle works correctly in a browser environment. It runs a small set of sanity checks without Jasmine.","other-src":"# Other — src\n\n# Other — src Module\n\n## Overview\n\nThe **Other — src** module defines the solution structure for the Handlebars templating library. It groups four projects that together implement, test, and demonstrate the core Handlebars engine. This module is the entry point for building and developing the library within the larger codebase.\n\n## Project Structure\n\nThe solution file `Handlebars.slnx` references the following projects:\n\n| Project | Path | Purpose |\n|---------|------|---------|\n| `Handlebars` | `Handlebars/Handlebars.csproj` | Main library – Handlebars template parser and renderer |\n| `Handlebars.Test` | `Handlebars.Test/Handlebars.Test.csproj` | Unit tests for the core library |\n| `Handlebars.Compat` | `Handlebars.Compat/Handlebars.Compat.csproj` | Compatibility layer for legacy APIs or third-party integration |\n| `Handlebars.TestApp` | `Handlebars.TestApp/Handlebars.TestApp.csproj` | Sample application demonstrating library usage |\n\nThe root directory for the solution is assumed to be the same as the location of `Handlebars.slnx`. All project paths are relative.\n\n## Key Components\n\n### Handlebars (Core Library)\n\nThe primary deliverable. Contains the template parser, compiler, runtime, and helper registration. This project is referenced by all other projects in the solution.\n\n### Handlebars.Test\n\nHolds xUnit/NUnit tests (project type inferred) for the core library. Uses `Handlebars` as a dependency. Ensures correctness of parsing, rendering, and helper execution.\n\n### Handlebars.Compat\n\nProvides backward-compatible APIs for consumers migrating from older versions of Handlebars or other template engines. This project may define wrapper interfaces or extension methods that map to the core library’s public API.\n\n### Handlebars.TestApp\n\nA simple console or desktop application used for manual testing, performance evaluation, or as a reference implementation. It references both `Handlebars` and optionally `Handlebars.Compat`.\n\n## Build and Dependencies\n\n- All projects target .NET (version specified in individual `.csproj` files – not shown here).\n- `Handlebars.Test`, `Handlebars.Compat`, and `Handlebars.TestApp` all depend on `Handlebars`.\n- No external dependencies are visible from the solution structure; any NuGet packages are defined per project.\n- The solution can be built with `dotnet build Handlebars.slnx` or via any IDE that supports `.slnx` format.\n\n## Connections to the Codebase\n\nWithin the larger repository, the **Other — src** module is one of several solution-level groupings. It isolates the Handlebars library and its immediate support projects from other modules (e.g., documentation, benchmarks, or samples). The solution file is the standard way to package these four projects together for development and CI.\n\n## Usage\n\nTo develop or contribute to the Handlebars library:\n\n1. Clone the repository.\n2. Open `src/Handlebars.slnx` in your IDE or run `dotnet restore`.\n3. Modify the core library, tests, or compatibility layer as needed.\n4. Run tests via `dotnet test Handlebars.Test`.\n\nThe `Handlebars.TestApp` can be launched directly to verify functionality interactively.\n\n---\n\n*No diagram is necessary; the module’s structure is linear and fully described by the project table above.*","other-tasks":"# Other — tasks\n\n# Other — Tasks Module\n\nThis module contains automated tasks for the Handlebars.js project: version bumping, releasing to AWS S3, and associated test infrastructure. The tasks are implemented as Node.js scripts in the `tasks/` directory and are invoked either directly or as part of a CI pipeline.\n\n## Overview\n\nThe module consists of four primary components:\n\n- **`version.js`** – increments the project version, updates metadata files, and triggers a build.\n- **`publish-to-aws.js`** – uploads compiled distribution files to an S3 bucket with versioned suffixes.\n- **`util/git.js`** – wraps common `git` operations (commit, add, rev-parse, tag, branch, remote) for use by the tasks.\n- **`tests/`** – test suites for the CLI, git utilities, S3 publishing, and a fake S3 server for integration testing.\n\n## File Details\n\n### `version.js` – Version Bump\n\n**Purpose**: Update the project version from the command line and synchronize it across package manifests and source code.\n\n**Execution**: \n`node tasks/version.js <semver>` \n\n**Process**:\n1. Validates the provided version string with `semver.valid()`.\n2. Reads `package.json`, updates the `version` field, writes it back, and stages the change via `git add`.\n3. For each file listed in `replaceSpec` (`lib/handlebars/base.js`, `components/bower.json`, `components/package.json`, `components/handlebars.js.nuspec`), it replaces the version pattern with the new version and stages the file.\n4. Runs `npm run build` to regenerate the compiled output.\n\n**Key internal call**: `replaceAndAdd(filePath, regex, value)` – reads a file, applies a regex replacement, writes it, and calls `git.add`.\n\n```mermaid\nflowchart TD\n A[node version.js <version>] --> B{version valid?}\n B -- no --> C[throw error]\n B -- yes --> D[update package.json]\n D --> E[git add package.json]\n E --> F[update base.js, bower.json, etc.]\n F --> G[git add each file]\n G --> H[npm run build]\n```\n\n### `publish-to-aws.js` – S3 Upload\n\n**Purpose**: Upload the four canonical distribution files (`handlebars.js`, `handlebars.min.js`, `handlebars.runtime.js`, `handlebars.runtime.min.js`) to an S3 bucket with naming suffixes that indicate the release channel.\n\n**Execution**: \n`node tasks/publish-to-aws.js` (typically as part of a CI step after a successful build)\n\n**Behavior**:\n- Calls `git.remotes()`, `git.branches()`, and `git.commitInfo()` to determine the Git context.\n- `buildSuffixes(commitInfo)` returns an array of suffixes:\n - `-latest` and `-<short-sha>` when on the master branch.\n - `-<tag>` when the current commit has a semver‑valid tag (prefers tags starting with `v`).\n- If the suffix list is non‑empty, validates that the required S3 environment variables are set (`S3_BUCKET_NAME`, `S3_REGION`, `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`).\n- For each suffix, `publishSuffix` iterates over `PUBLISHED_FILES`, renames the file (e.g., `handlebars.js` → `handlebars-latest.js`), reads it from `dist/`, and uploads it to S3.\n\n**Key internal call**: `uploadToBucket(file, key, overrides)` – uses `@aws-sdk/client-s3` to `PutObject`.\n\n**Testing**: The test file `publish-to-aws.test.js` uses a fake S3 server (`fake-s3.js`) to verify uploads without external dependencies.\n\n```mermaid\nflowchart TD\n A[node publish-to-aws.js] --> B[get commitInfo]\n B --> C{has suffixes?}\n C -- no --> D[exit]\n C -- yes --> E[validate S3 env vars]\n E --> F[for each suffix]\n F --> G[for each file in PUBLISHED_FILES]\n G --> H[rename file with suffix]\n H --> I[read from dist/]\n I --> J[upload to S3]\n```\n\n### `util/git.js` – Git Utility\n\n**Purpose**: Provide an abstraction layer over the `git` CLI for use by the tasks. All functions return a `Promise<string>` (stdout).\n\n**Exported functions**:\n- `remotes()` – `git remote -v`\n- `branches()` – `git branch -a`\n- `commitInfo()` – returns `{ headSha, masterSha, tagName, isMaster }` by calling:\n - `getHeadSha()` – `git rev-parse --short HEAD`\n - `getMasterSha()` – `git rev-parse --short origin/master` (returns empty string if master not checked out)\n - `getTagName()` – `git tag -l --points-at HEAD`; prefers tags starting with `v`\n- `add(path)` – `git add -f <path>`\n- `commit(message)` – `git commit --message <message>`\n- `git(...args)` – low-level `child_process.execFile('git', ...)` wrapper.\n\n### `tasks/tests/` – Test Suites\n\n- **`cli.test.js`** – Integration tests for the `bin/handlebars.js` CLI options (help, version, namespace, file output, inline templates, error handling). Uses `cli-testlab` and custom matchers.\n- **`git.test.js`** – Tests for `util/git.js` using a real git repository created in a temp directory. Verifies `remotes`, `branches`, `commitInfo` (including tag preferences and master detection).\n- **`publish-to-aws.test.js`** – Unit and integration tests for `publish-to-aws.js`. Uses a fake S3 server (`fake-s3.js`) and local `dist/` files.\n- **`fake-s3.js`** – A minimal in-memory S3‑compatible HTTP server. Supports `PUT`, `GET`, and `HEAD` requests via path‑style URLs (e.g., `/<bucket>/<key>`).\n\n## Integration Points\n\nThe module interacts with the rest of the Handlebars codebase in these ways:\n\n| Component | Uses |\n|-----------|-------|\n| `publish-to-aws.js` | Reads distribution files from `dist/` (produced by `npm run build`). |\n| `version.js` | Runs `npm run build` after updating version files. Modifies `lib/handlebars/base.js` (source constant) and `components/*.json`/`.nuspec` (package metadata). |\n| `util/git.js` | Called directly from the tasks only. Does not depend on any other module. |\n| `tests/cli.test.js` | Launches `bin/handlebars.js` (the CLI), so it exercises the compiler. |\n| `tests/publish-to-aws.test.js` | Reads actual `dist/` files to verify upload content. |\n\n## Running Tests\n\nTests are run with Mocha:\n\n```bash\nmocha tasks/tests\n```\n\nIndividual test files can be run:\n\n```bash\nmocha tasks/tests/publish-to-aws.test.js\n```\n\nThe git tests require a real git installation; they are conditionally skipped if `git -v` fails.","other-test-fixtures":"# Other — test_fixtures\n\n# Handlebars.js Test Fixtures\n\nThis directory (`test_fixtures`) provides a curated set of test templates, their expected abstract syntax trees (ASTs), and the corresponding compiled JavaScript output. These fixtures are used as a common reference dataset by the parser, compiler, and runtime test suites.\n\n## Fixture Organization\n\nEach fixture is identified by a numeric or `comp_N` prefix. For a given index `N`, up to four related files may be present:\n\n| File | Description |\n|------|-------------|\n| `N.hbs` | Handlebars template source |\n| `N.ast.json` | Expected AST (output of `Handlebars.parse()`) |\n| `comp_N.hbs` | Template used for compiled output (may duplicate `N.hbs`) |\n| `comp_N.spec.json` | Expected compiled JavaScript (output of `Handlebars.precompile()`) |\n\nNot every template has both an AST fixture and a compiled spec. For example, fixture 29 (`{{~name}}`) has only `29.hbs` and `29.ast.json`.\n\n## AST Fixtures\n\nThe `*.ast.json` files contain the full AST as produced by the Handlebars parser. The JSON structure follows the internal node types used by the parser:\n\n- **Root**: `Program` with a `body` array of statements.\n- **Statements**: `ContentStatement`, `MustacheStatement`, `BlockStatement`, `PartialStatement`, `PartialBlockStatement`, `CommentStatement`, `Decorator`, `DecoratorBlock`.\n- **Expressions**: `PathExpression`, `StringLiteral`, `NumberLiteral`, `BooleanLiteral`, `SubExpression`.\n- **Hash arguments**: `Hash` with `HashPair` entries.\n\nEach node includes `loc` (source location) and `strip` (whitespace control) metadata where applicable.\n\nThese AST fixtures are referenced by parser tests to validate that a given template string is parsed into the correct tree.\n\n## Compiled Spec Fixtures\n\nThe `comp_N.spec.json` files contain the **stringified** compiled output of the Handlebars compiler for the corresponding `comp_N.hbs` template. The compiled output is a JavaScript object with:\n\n- `compiler` version array\n- `main` function (the compiled template function)\n- Additional properties such as `useData`, `usePartial`, `useDecorators`, `useDepths`\n- For templates with blocks, `N` functions (indexed by the block ID)\n\nThese compiled outputs are used by compiler test suites to verify that templates are compiled to the expected JavaScript functions, including correct helper resolution, partial invocation, and whitespace control.\n\n## How Fixtures Are Used\n\nThe test fixtures are loaded by test files throughout the codebase. Typically, a test will:\n\n1. Read a `.hbs` file.\n2. Parse or compile it with the appropriate Handlebars API.\n3. Compare the result against the corresponding `.ast.json` or `.comp.json` file.\n\nBecause the fixtures are small and isolated, they allow testing of individual parse/compile features without complex side effects.\n\n## Relationship to the Codebase\n\n- **Parser tests** (`test/parser/` or similar) load `.hbs` and `.ast.json` pairs to verify parsing correctness.\n- **Compiler tests** (e.g., `test/compiler/`) load `.hbs` and `comp_N.spec.json` to validate generated code.\n- **Runtime tests** may use the same templates but provide their own expectations against actual rendering output.\n\nThe fixtures are versioned implicitly by their content; new fixtures are added when new syntax or features are introduced (e.g., decorators, block parameters, whitespace stripping). The `comp_` prefix distinguishes fixtures that were specifically designed to test the compiler output while the numeric ones are more general.\n\nNo direct code calls into this module — it is purely static data consumed by multiple test suites.","other-tests":"# Other — tests\n\n# Tests Module Documentation\n\nThis module contains the full test suite for Handlebars.js, including unit tests, integration tests, browser tests, and performance benchmarks. It ensures correctness, compatibility, and performance across environments.\n\n## Structure Overview\n\n```mermaid\ngraph TD\n subgraph Benchmarks\n perf.js --> report.js\n compare.js --> report.js\n size.js\n templates.js\n end\n subgraph Integration\n multi-nodejs-test\n rollup-test\n webpack-test\n run-integration-tests.sh\n end\n subgraph Browser\n playwright.config.js\n lib.spec.js\n end\n subgraph Output Verification\n rspack.test.js\n print-script.js\n end\n perf.js --> templates.js\n size.js --> templates.js\n```\n\n## Benchmarking (`tests/bench/`)\n\nPerformance benchmarks measure compile, execute, precompile, and end-to-end rendering across a suite of template scenarios. They are instrumented via [`tinybench`](https://github.com/tinylibs/tinybench) and produce both console and Markdown reports.\n\n### Key Files\n\n- **`perf.js`** – Main benchmark runner. Accepts `--label`, `--grep` (filter templates by name), and `--section` (filter benchmark sections). Runs four sections:\n - COMPILATION (compile + first render)\n - EXECUTION (template rendering, with output verification)\n - PRECOMPILATION\n - END-TO-END (compile + render)\n - COMPILE OPTIONS COMPARISON (benchmarks different compile flags)\n\n- **`templates.js`** – Exports a dictionary of template definitions, each containing `template`, `context`, and optionally `helpers` and `partials`. Covers small, medium, complex, large/stress, and mixed-feature templates.\n\n- **`report.js`** – Formatting and output utilities:\n - `formatNs()` / `formatOps()` – Human-readable units.\n - `printResults()` / `printSectionHeader()` – Console output.\n - `saveMarkdownReport()` – Writes timestamped Markdown files to `bench/results/`.\n\n- **`compare.js`** – Compares two benchmark result files (baseline vs. current). Parses the Markdown tables, computes percentage changes, and prints a comparison table. Auto-selects results or accepts explicit file paths.\n\n- **`size.js`** – Measures:\n - Distribution bundle sizes (raw and gzipped) from `dist/`.\n - Precompiled template string lengths, including savings when using `knownHelpersOnly`.\n\n### Execution Flow\n\n`perf.js` calls `runSection()` for each benchmark group. `runSection()` creates a `Bench` instance, populates it with tasks from filtered templates (via `createEnv()` which registers helpers/partials), runs the benchmark, and prints results. After execution, outputs are verified against an expected output snapshot. The final Markdown report is saved via `saveMarkdownReport()`.\n\n## Browser Tests (`tests/browser/`)\n\nRun Handlebars' existing Mocha spec suite in Chromium, Firefox, and WebKit using Playwright.\n\n- **`playwright.config.js`** – Defines three projects (chromium, firefox, webkit) with a web server serving the spec files on port 9999.\n- **`lib.spec.js`** – Navigates to the spec page and waits for `window.mochaResults.failures` to be 0.\n\nRun via `npm run test:browser` (requires Docker or local Playwright).\n\n## Integration Tests (`tests/integration/`)\n\nValidate real-world usage scenarios. Each subfolder contains a `test.sh` that installs dependencies (using the local Handlebars build via `\"file:../../..\"`) and runs its test.\n\n- **`multi-nodejs-test/`** – Tests precompile and runtime under Node.js versions 20 and 22.\n- **`rollup-test/`** – Ensures ESM bundling with Rollup works and output is correct.\n- **`webpack-test/`** – Tests multiple import styles:\n - Default ESM import\n - Runtime import (`handlebars/runtime`)\n - `handlebars-loader` for `.handlebars` files\n - Registered helper availability\n- **`run-integration-tests.sh`** – Iterates over all `*/test.sh` scripts and runs them.\n\n## Additional Tests\n\n- **`rspack.test.js`** (Vitest) – Verifies the built distribution bundles:\n - Expected files exist and are non-empty.\n - Global export (`self.Handlebars`) present.\n - License banner intact.\n - Minification reduces size by >50%.\n - No ES6+ syntax (arrow functions, `const`/`let`, template literals, classes) in the unminified browser bundles.\n - Functional correctness via ESM imports.\n\n- **`print-script.js`** – Debugging tool that precompiles a template string and prints the generated code and source map. Accepts an optional verbose flag (`-v`) to show mapping details.\n\n## Connecting to the Codebase\n\n- All benchmark tests import `Handlebars` from `../../lib/index.js` (or `handlebars` from the workspace in integration tests).\n- Integration tests reinstall the local package via `\"file:../../..\"` to ensure the currently built library is tested.\n- The `rspack.test.js` test imports directly from `../../lib/index.js` and checks `dist/` files built by the project's main build step.\n- `print-script.js` uses `require('./../lib')` and `require('source-map')` for debugging compiler output.","other-types":"# Other — types\n\n# `handlebars` — Type Definitions Module\n\nThis module provides TypeScript type definitions for the entire Handlebars.js library. It is not a runtime module — it exists purely to enable strict type checking when using Handlebars in a TypeScript project. The type tests in `handlebars.tst.ts` serve as both a specification and a validation of all exported types.\n\n## Purpose\n\n- Expose accurate type signatures for all public Handlebars APIs (`compile`, `precompile`, `registerHelper`, `SafeString`, `Exception`, etc.).\n- Define the AST node structure for the Handlebars template language.\n- Provide helper types for runtime options, helper options, known helpers, and template delegation.\n- Ensure that the `hbs` namespace (which mirrors `Handlebars`) carries the same types.\n\n## Main Exports\n\nThe module exports the following symbols from the `handlebars` package (accessible via `import { … } from 'handlebars'`):\n\n| Export | Description |\n|---|---|\n| `HandlebarsTemplatable` | Interface with a `template` field of type `HandlebarsTemplateDelegate`. |\n| `HandlebarsTemplateDelegate<T>` | A compiled template function. Accepts a context of type `T` and optional `RuntimeOptions`. Returns a string. |\n| `HandlebarsTemplates` | Record of named `HandlebarsTemplateDelegate` instances. |\n| `TemplateSpecification` | Return type of `Handlebars.precompile`. Represents a precompiled template. |\n| `KnownHelpers` | A record mapping helper names (strings) to boolean. Used in `CompileOptions.knownHelpers`. |\n| `BuiltinHelperName` | A string union of built-in helper names: `'helperMissing' \\| 'blockHelperMissing' \\| 'each' \\| 'if' \\| 'unless' \\| 'with' \\| 'log' \\| 'lookup'`. |\n| `CustomHelperName` | `string` — any user‑defined helper name. |\n| `Logger` | Interface with level constants (`DEBUG`, `INFO`, `WARN`, `ERROR`), `level` number, `methodMap`, and a `log` method. |\n| `CompilerInfo` | A tuple `[number, string]` used internally. |\n| `hbs` | Namespace containing `SafeString`, `Utils`, and `AST`. |\n\n## The `hbs` Namespace\n\nThe `hbs` namespace re‑exports types and utilities under a single umbrella:\n\n- **`hbs.SafeString`** — Alias of `Handlebars.SafeString`. Constructor takes a string. Methods `toString()` and `toHTML()` both return `string`.\n- **`hbs.Utils`** — Mirrors `typeof Handlebars.Utils`. Provides static utility methods such as `escapeExpression`, `isEmpty`, `isArray`, `isFunction`, `createFrame`, `blockParams`, `extend`, `toString`, `isMap`, `isSet`.\n- **`hbs.AST`** — Discriminated union of all AST node types (see below).\n\n## AST Node Discriminated Union\n\nAll Handlebars templates are parsed into an Abstract Syntax Tree. Each node carries a `type` string literal that narrows the node to one of the following interfaces:\n\n| `type` | Interface | Description |\n|---|---|---|\n| `'MustacheStatement'` | `hbs.AST.MustacheStatement` | `{{...}}` expression |\n| `'BlockStatement'` | `hbs.AST.BlockStatement` | `{{#...}}{{/...}}` block |\n| `'PartialStatement'` | `hbs.AST.PartialStatement` | `{{> ...}}` partial |\n| `'PartialBlockStatement'` | `hbs.AST.PartialBlockStatement` | `{{#> ...}}{{/...}}` partial block |\n| `'ContentStatement'` | `hbs.AST.ContentStatement` | Raw text content |\n| `'CommentStatement'` | `hbs.AST.CommentStatement` | `{{! ...}}` comment |\n| `'SubExpression'` | `hbs.AST.SubExpression` | `(helper ...)` inside expressions |\n| `'PathExpression'` | `hbs.AST.PathExpression` | `foo.bar` path |\n| `'StringLiteral'` | `hbs.AST.StringLiteral` | `\"...\"` literal |\n| `'BooleanLiteral'` | `hbs.AST.BooleanLiteral` | `true` / `false` |\n| `'NumberLiteral'` | `hbs.AST.NumberLiteral` | Numeric literal |\n| `'UndefinedLiteral'` | `hbs.AST.UndefinedLiteral` | `undefined` |\n| `'NullLiteral'` | `hbs.AST.NullLiteral` | `null` |\n| `'Hash'` | `hbs.AST.Hash` | `key=value` pairs |\n| `'HashPair'` | `hbs.AST.HashPair` | Single `key: value` pair |\n\nEach node interface also contains `loc` (source location) and other fields specific to the node type.\n\n## Runtime Types\n\n### `Handlebars.HelperOptions`\n\nOptions passed to helper functions. Key properties:\n\n- `fn(context) => string` — the “main” template block.\n- `inverse(context) => string` — the `else` block.\n- `hash: Record<string, any>` — named arguments from the template.\n\n### `Handlebars.ResolvePartialOptions`\n\nOptions used when resolving partials at runtime:\n\n- `name: string`\n- `helpers?: { [name: string]: Function }`\n- `partials?: { [name: string]: HandlebarsTemplateDelegate }`\n- `decorators?: { [name: string]: Function }`\n- `data?: any`\n\n### `Handlebars.RuntimeOptions`\n\nSecond argument to a template delegate:\n\n- `partial?: boolean`\n- `depths?: object[]`\n- `helpers?: { [name: string]: Function }`\n- `partials?: { [name: string]: HandlebarsTemplateDelegate }`\n- `decorators?: { [name: string]: Function }`\n- `data?: any`\n- `blockParams?: any[][]`\n- `allowCallsToHelperMissing?: boolean`\n- `allowedProtoMethods?: { [name: string]: boolean }`\n- `allowedProtoProperties?: { [name: string]: boolean }`\n- `allowProtoMethodsByDefault?: boolean`\n- `allowProtoPropertiesByDefault?: boolean`\n\n## `Handlebars.Exception`\n\nAn error class with additional properties:\n\n- `message`, `name`, `description`, `fileName` — all `string`\n- `number` — `number`\n- `lineNumber`, `endLineNumber`, `column`, `endColumn` — `any` (depending on source)\n- `stack` — `string | undefined`\n\nConstructable with a message and an optional AST node.\n\n## Integration with Compilation Methods\n\nThe type tests verify that `Handlebars.compile`, `Handlebars.precompile`, and `Handlebars.template` are correctly typed:\n\n- `Handlebars.compile<T>(template, options?)` returns `HandlebarsTemplateDelegate<T>`.\n- `Handlebars.precompile(template, options?)` returns `TemplateSpecification`.\n- `Handlebars.template(spec)` returns `HandlebarsTemplateDelegate<any>`.\n\nThe generic parameter on `compile` allows the context object to be typed, so the template delegate accepts only that shape.\n\n## Diagram: Type Flow for Template Execution\n\n```mermaid\nflowchart LR\n A[Template string] -->|Handlebars.compile| B(HandlebarsTemplateDelegate<T>)\n B -->|Call with context T| C[Rendered string]\n C --> D[SafeString?]\n D -->|Handlebars.SafeString| E[toString / toHTML]\n B -.->|Optional RuntimeOptions| F[{partial, helpers, data, ...}]\n```\n\n## Logger\n\nThe `Logger` interface provides four numeric log levels (`DEBUG`, `INFO`, `WARN`, `ERROR`), a `level` property, a `methodMap` from level to method name, and a `log(level, message)` method.\n\n## See Also\n\n- The `handlebars` runtime module.\n- The `handlebars-compiler` module for compilation internals.\n- The type test file (`handlebars.tst.ts`) for exhaustive usage examples.","other":"# Other\n\n# Other Module Overview\n\nThe **Other** module is a top‑level container for all supporting infrastructure of the Handlebars.js template engine and its .NET counterpart. It brings together:\n\n- **Distribution configuration** – files (`components`, `golden`) that describe how the library is packaged and how the parser is validated.\n- **Root project tooling** – build, test, linting, and release automation (`handlebars.js`).\n- **Test suites** – both JavaScript (`spec`, `tests`) and .NET (`Handlebars.Test`), along with shared test fixtures (`test_fixtures`) and static golden ASTs (`golden`).\n- **Type definitions** – TypeScript declarations for all public APIs (`types`).\n- **.NET library projects** – the core `Handlebars` engine, a `Handlebars.Compat` shim, a unit test project, and a command‑line test app (`Handlebars.TestApp`), all organised under `src`.\n- **Automation scripts** – version bumping, S3 deployment, and git utilities (`tasks`).\n\nThe module exists to centralise everything that is not the core JavaScript runtime or the .NET parser itself. It orchestrates the development, distribution, and cross‑platform testing of the Handlebars language.\n\n## Sub-module Relationships\n\n| Sub‑module | Role | Dependencies |\n|------------|------|--------------|\n| `components` | Package manifests (Bower, Composer, NuGet, etc.) | None (data only) |\n| `handlebars.js` | Build system, package metadata, linting, CI | Uses `tasks` for release, `spec` for tests |\n| `spec` | JavaScript test suite (Jasmine) | Depends on `handlebars.js` runtime |\n| `tasks` | Versioning, git operations, S3 publishing | Calls `util/git.js` internally |\n| `test_fixtures` | Template/AST/compiled‑output pairs for parser tests | Used by `spec` and `.NET` tests |\n| `tests` | JavaScript benchmarks, integration (webpack, Rollup), browser tests | Uses `test_fixtures`? |\n| `types` | TypeScript definitions | References `handlebars.js` API |\n| `Handlebars` | .NET Handlebars library (AOT‑compatible) | None |\n| `Handlebars.Compat` | Compatibility shim for `Handlebars` namespace | References `Handlebars` |\n| `Handlebars.Test` | .NET xUnit test suite | References `Handlebars`, `Handlebars.Compat`, `test_fixtures` |\n| `Handlebars.TestApp` | CLI template renderer (demo/tool) | References `Handlebars` |\n| `src` | .NET solution file (`Handlebars.slnx`) | Organises the three .NET projects |\n| `golden` | Static `.hbs` / `.ast.json` test pairs | Used by parser tests (both JS and .NET) |\n\n## Key Workflows\n\n### JavaScript Build, Test, and Release\n\n1. **Build** – `handlebars.js` runs Rspack to produce browser distributions. \n2. **Test** – `spec` is executed via Vitest (Node, browser, integration). `tests` adds benchmarks and cross‑bundler integration. \n3. **Lint** – ESLint and oxlint run across the codebase. \n4. **Release** – `tasks/version.js` bumps the version, updates metadata, and commits changes using `tasks/util/git.js`. Then `tasks/publish-to-aws.js` uploads compiled files to S3. \n\n### .NET Build and Test\n\n1. **Build** – `src/Handlebars.slnx` compiles `Handlebars`, `Handlebars.Compat`, and `Handlebars.Test`. \n2. **Test** – `Handlebars.Test` executes xUnit tests that verify parity with the JavaScript spec. Many test methods use shared helpers (`WithInput`, `ToCompileTo`, `Template`) defined in `Handlebars.Test/TestHelper.cs`. \n3. **Run** – `Handlebars.TestApp` can be invoked manually to render templates with JSON data.\n\n### Cross‑Community Test Parity\n\n- The `.NET` test suite (`Handlebars.Test`) is largely a port of the JavaScript `spec` module. \n- Both test suites consume the same `golden` fixtures (`.hbs` templates and their expected ASTs) to validate the parser. \n- Shared execution flows (e.g., `program → wrapProgram → executeDecorators`) are verified in both ecosystems.\n\n## Diagram\n\n```mermaid\ngraph TD\n subgraph JS_Ecosystem\n A[handlebars.js] --> B[spec]\n A --> C[tests]\n A --> D[tasks]\n D --> E[tasks/util/git.js]\n A --> F[types]\n G[test_fixtures] --> B\n G --> H[Handlebars.Test]\n end\n\n subgraph DOTNET_Ecosystem\n I[src] --> J[Handlebars]\n I --> K[Handlebars.Compat]\n I --> L[Handlebars.Test]\n I --> M[Handlebars.TestApp]\n K --> J\n L --> J\n L --> K\n L --> G\n L --> H\n end\n\n subgraph Static_Data\n N[golden] --> G\n N --> B\n N --> L\n O[components] --> A\n end\n\n B -->|port| L\n```","overview":"# Handlebars.Net — Wiki\n\n# Handlebars.Net\n\nWelcome to **Handlebars.Net** – a full port of the [Handlebars.js](https://handlebarsjs.com/) templating engine to .NET. This repository contains both the .NET implementation and the canonical JavaScript source (handlebars.js v4+) used as the reference for the port. The .NET engine uses a stack-based bytecode interpreter instead of runtime code generation, making it AOT-safe and compatible with environments that restrict dynamic IL emit.\n\n## Architecture Overview\n\nThe following diagram shows the high-level modules and their relationships. The pipeline flows from left to right: templates are parsed, compiled to an intermediate representation, and then executed.\n\n```mermaid\ngraph LR\n A[Template] --> B[JavaScript Compiler & Runtime]\n B --> C[Output]\n A --> D[.NET Parser & Interpreter]\n D --> C\n B -.->|Reference| D\n E[JS Helpers & Decorators] --> B\n F[.NET Helpers] --> D\n G[Compatibility Layer] --> D\n```\n\nThe diagram illustrates two parallel pipelines: the original JavaScript side (used for reference and precompilation) and the .NET side. The .NET engine shares the same AST structure and semantics, and is tested against the JavaScript test suite.\n\n## Key End-to-End Flows\n\n### JavaScript Pipeline\n1. **Parsing & Compilation**: The [JavaScript Handlebars Compiler](javascript-handlebars-compiler.md) transforms a template string into a sequence of opcodes (via `compiler.js` and `javascript-compiler.js`).\n2. **Execution**: The [JavaScript Handlebars Core](javascript-handlebars-core.md) provides the runtime that evaluates those opcodes against a data context. Built-in helpers from [JavaScript Handlebars Helpers & Decorators](javascript-handlebars-helpers---decorators.md) are invoked during rendering.\n3. **CLI**: The [JavaScript Handlebars CLI & Packaging](javascript-handlebars-cli---packaging.md) module allows precompiling templates offline.\n\n### .NET Pipeline\n1. **Parsing**: The [.NET Handlebars Core](.net-handlebars-core.md) parses a template string into an AST (`Parser.Parse`).\n2. **Compilation**: The same core compiles the AST into a stream of opcodes (`Compiler.Compile`), producing a `CompiledProgram`.\n3. **Interpretation**: A `BytecodeInterpreter` walks these opcodes to produce the final output, calling into [.NET Handlebars Helpers](.net-handlebars-helpers.md) for `#if`, `#each`, etc.\n4. **Compatibility**: The [.NET Handlebars Compatibility Layer](.net-handlebars-compatibility-layer.md) wraps the new engine behind the classic `HandlebarsDotNet` API, making migration seamless for existing users.\n\n### Cross‑Cutting Concerns\n- **Testing**: All modules are backed by test suites in the [Other](other.md) module (spec, tests, Handlebars.Test).\n- **Documentation**: The [Project Documentation](project-documentation.md) module contains onboarding guides (`AGENTS.md`, `ARCHITECTURE.md`) and reference documents.\n\n## Getting Started\n\nFor a quick introduction, see the [.NET Handlebars Core](.net-handlebars-core.md) page for basic usage examples, or refer to the [Compatibility Layer](.net-handlebars-compatibility-layer.md) if you are migrating from the classic Handlebars.Net library.","project-documentation-agents-md":"# Project Documentation — AGENTS.md\n\n# Project Documentation — AGENTS.md\n\n## Overview\n\n`AGENTS.md` is the primary developer-onboarding and reference document for the Handlebars.Net rewrite (branch `vnext`). It is written for both human developers and AI coding agents, and consolidates the essential information needed to understand, build, test, and contribute to the project. The file lives at the repository root and is the first file a contributor should read.\n\n## Purpose\n\nThe file serves several distinct roles:\n\n- **Onboarding guide** – Provides build commands, project layout, and architecture summary so a new developer can start contributing in minutes.\n- **Agent coordination document** – Contains a detailed `GitNexus` integration section that instructs coding agents (like Claude) on mandatory safety procedures (impact analysis, change detection) and prohibits reckless edits.\n- **Quick reference** – Lists namespace quirks, testing patterns, helper conventions, and links to all other key documentation files.\n- **Roadmap and status link** – Points to `docs/09-handover.md`, `docs/08-progress.md`, and `docs/07-tech-debt.md` for the current state and next steps.\n\n## Structure\n\nThe document is divided into the following sections:\n\n| Section | Content |\n|---------|---------|\n| **Commands** | `dotnet build` and `dotnet test` commands; filter examples for specific test classes. |\n| **Project Layout** | Directory tree of `src/Handlebars`, `src/Handlebars.Compat`, `src/Handlebars.Test`, and the solution file. |\n| **Key Architecture** | 3-stage pipeline (Template → Parser → AST → Compiler → Bytecode VM). States that the default engine is the bytecode interpreter (AOT-compatible), not IL emit. |\n| **Namespace Quirks** | Core namespace `Handlebars` vs. compat shim's `HandlebarsDotNet`; the `Core` alias to avoid collision with the static `Handlebars` class. |\n| **Testing** | Test framework (xunit), `TestHelper` pattern, golden-file tests, skipped tests as roadmap, `@data` context caveat. |\n| **Docs as Source of Truth** | Links to six key `docs/*.md` files with one-line descriptions of each. |\n| **Conventions** | Record types for model objects, helper directory and delegate signatures, custom helper registration, exception type `HandlebarsException`. |\n| **Git** | Branch (`vnext`), CI matrix ( .NET 8, 10). |\n| **GitNexus — Code Intelligence** | Mandatory safety rules for AI agents: always run impact analysis, never edit without it, never rename blindly, detect changes before commit. Also includes a table of CLI skill files. |\n\n## How It Connects to the Codebase\n\n`AGENTS.md` is the *entry point* that ties together all other project documentation and the source code. The diagram below illustrates its central role:\n\n```mermaid\nflowchart TD\n A[\"AGENTS.md\"]\n B[\"docs/01-architecture.md\"]\n C[\"docs/06-implementation-plan.md\"]\n D[\"docs/07-tech-debt.md\"]\n E[\"docs/08-progress.md\"]\n F[\"docs/09-handover.md\"]\n G[\"docs/COMPAT.md\"]\n H[\"src/Handlebars/ (core)\"]\n I[\"src/Handlebars.Compat/ (shim)\"]\n J[\"src/Handlebars.Test/ (tests)\"]\n\n A --> B\n A --> C\n A --> D\n A --> E\n A --> F\n A --> G\n A -->|build/test commands| H\n A -->|namespace quirks| I\n A -->|testing patterns| J\n B -.->|describes old codebase| H\n C -.->|phase checklist| H\n D -.->|debt tracking| H\n E -.->|pass/skip counts| J\n F -.->|WIP & next steps| H\n G -.->|compat shim details| I\n```\n\nThe file itself is not code; it is *meta-documentation* that points readers to the right place for any given concern. It also defines the conventions that must be followed when writing code (record types, exception type, helper signatures), making it a style guide as well.\n\n## Recommended Usage\n\n1. **New contributors** – Read `AGENTS.md` first.\n2. **Before editing any code** – Follow the GitNexus safety rules (impact analysis, change detection).\n3. **When updating project state** – Update the linked docs (`docs/09-handover.md` after a session, `docs/08-progress.md` when tests pass or fail, `docs/07-tech-debt.md` when debt is resolved).\n4. **When adding a new helper** – Follow the `Helpers/` directory convention and delegate signature pattern described in the Conventions section.\n\n## Maintenance\n\n`AGENTS.md` must be kept in sync with the actual project state. In particular:\n\n- If the solution file, project layout, or build commands change, update the **Commands** and **Project Layout** sections.\n- If architecture changes (e.g., IL compiler is built), update the **Key Architecture** section.\n- If namespace rules or aliases are added, update the **Namespace Quirks** section.\n- The GitNexus section should remain as-is unless the agent coordination process changes.\n\nBecause `AGENTS.md` is the single source of truth for developer setup, any discrepancy between this file and the actual project leads to confusion. Treat it as a living document.","project-documentation-architecture-md":"# Project Documentation — ARCHITECTURE.md\n\n# Project Documentation — `ARCHITECTURE.md`\n\n## Purpose\n\n`ARCHITECTURE.md` is the canonical architectural reference for the DotNetBars codebase. It serves as the single source of truth for understanding the system's design, component boundaries, data flow, and key implementation decisions. The document is directed at developers who need to contribute to or extend the library — whether they are working on the parser, compiler, bytecode interpreter, or the backward-compatibility shim.\n\n## Content Overview\n\nThe file is organized into these sections:\n\n- **Overview:** High-level description of DotNetBars as a from-scratch rewrite of Handlebars.Net, targeting .NET 10 AOT compatibility. Notes codebase metrics (files, symbols, relationships, execution flows) sourced from the GitNexus knowledge graph.\n- **Project Layout:** A tree of the source directories and files, mapping each file to its responsibility (e.g., `Parser.cs` — recursive-descent lexer/parser, `BytecodeInterpreter.cs` — stack-based VM).\n- **Pipeline:** A three-phase pipeline (Parsing → Compilation → Interpretation) with a textual flow diagram showing the staged transformation from template string to output.\n- **Functional Areas:** A table listing major functional clusters (Parser, Compiler, Bytecode Interpreter, Helpers, Runtime Utils, Compat Shim, Tests) with a brief description of each.\n- **Opcodes (21 total):** A categorized table of every opcode emitted by the compiler, grouped by purpose (Stack, Context, Resolution, Blocks, Output, Partial, Decorator, Hash).\n- **Key Execution Flows:** Five annotated flows that trace the most common code paths (template compilation, rendering, mustache statement compilation, block statement compilation, context path lookup). Each flow lists the exact sequence of method calls or opcodes.\n- **Architecture Diagram:** A Mermaid graph that visualizes the three phases, the user-facing API, backward-compatibility layer, and verification (tests and golden file comparisons). Edges represent data flow and dependencies.\n- **Data Flow for `{{#each items}}{{name}}{{/each}}`:** A concrete walkthrough showing how a specific template is parsed, compiled into opcodes, and executed by the bytecode interpreter.\n- **Call Graph & Execution Flows:** A metadata block with the internal/external call graph and execution flow counts for the module itself (none, as this is a static document).\n\n## Key Components (within the Document)\n\n1. **Pipeline Description** \n The core mental model: `Template String → Parser.Parse() → AST → Compiler.Compile() → CompiledProgram → BytecodeInterpreter.Execute() → Output`. Every developer should start here.\n\n2. **Opcodes Reference** \n The document acts as a living specification for the bytecode instruction set. Each opcode category maps directly to the `Opcodes.cs` file. Contributors adding new language features can see where opcodes are emitted and consumed.\n\n3. **Execution Flows** \n These flow lists are manually curated based on the GitNexus call graph. They are not mechanically generated, making them more readable. They serve as debugging guides and onboarding shortcuts.\n\n4. **Architecture Diagram** \n The Mermaid graph is the visual summary. It explicitly shows the separation between phases, the relationship between `Engine`, `Template`, and the interpreter, and how backward compatibility is layered on top.\n\n## How It Connects to the Codebase\n\n- `ARCHITECTURE.md` is the primary reference for anyone reading or modifying source files. It explains why `Parser.cs` is 1168 lines, why there are 21 opcodes, and how the interpreter switch-loop works.\n- The file is not generated; it is manually maintained alongside code changes. When new opcodes, helpers, or pipeline stages are added, the document must be updated to reflect those changes.\n- The call graph metadata at the bottom of the file is used by tools (e.g., GitNexus) to verify that the documentation matches the actual code structure. If the execution flows diverge, the metadata block will show a discrepancy.\n\n## Maintenance Guidelines\n\n- **Updating opcodes:** When adding a new opcode, add it to the opcodes table and update any execution flows that emit or interpret it.\n- **Updating the diagram:** Modify the Mermaid graph when adding new files, clusters, or dependencies.\n- **Adding execution flows:** Use the GitNexus call graph as a starting point, but simplify to only the most important steps (5–10 nodes). Every flow should have a descriptive name and a step count.\n- **Golden file tests:** The document references golden file comparison against handlebars.js. When new features break parity, update the golden files and note the change here.\n\nThis document is the architectural contract of the DotNetBars project. Treat it as a living artifact that evolves with the codebase.","project-documentation-claude-md":"# Project Documentation — CLAUDE.md\n\n# Project Documentation — CLAUDE.md\n\n## Overview\n\n`CLAUDE.md` is a special configuration file placed in the repository root for the **DotNetBars** project. It is read by AI coding assistants (e.g., Claude) at the start of every session to define a mandatory, safety-first workflow for navigating, understanding, and modifying the codebase. The file does not contain executable code; instead, it embeds structured instructions that the AI must follow as rules, supplemented with resource references and skill mappings.\n\n## Purpose\n\nThe primary goal of `CLAUDE.md` is to prevent accidental damage to the project by enforcing a **blast-radius-aware** editing process. It requires that every modification be preceded by impact analysis using GitNexus tools, and that no commit be made without first verifying the scope of changes. By centralizing these instructions, the file ensures consistent behavior regardless of which AI session is used and eliminates reliance on the human developer remembering to run safety checks.\n\n## Structure and Sections\n\nThe file is delimited by HTML comments (`<!-- gitnexus:start -->` … `<!-- gitnexus:end -->`) so that external parsers can identify it. Its content is organized into four main sections:\n\n1. **Always Do** – A set of mandatory actions the AI must perform before any edit or commit:\n - Run `gitnexus_impact({target: \"symbolName\", direction: \"upstream\"})` before editing any function, class, or method.\n - Report the blast radius (direct callers, affected processes, risk level) to the user.\n - Run `gitnexus_detect_changes()` before committing to verify that only expected symbols and flows are affected.\n - Warn the user if impact analysis returns HIGH or CRITICAL risk.\n - Use `gitnexus_query()` for concept-level exploration instead of grep.\n - Use `gitnexus_context()` to get full context on a specific symbol.\n\n2. **Never Do** – Prohibited actions that the AI must never perform:\n - Never edit a symbol without first running `gitnexus_impact`.\n - Never ignore HIGH or CRITICAL risk warnings.\n - Never rename symbols using find-and-replace (must use `gitnexus_rename`).\n - Never commit without running `gitnexus_detect_changes()`.\n\n3. **Resources Table** – A quick-reference mapping of GitNexus resource URLs to their intended use:\n - `gitnexus://repo/DotNetBars/context` → codebase overview and index freshness.\n - `gitnexus://repo/DotNetBars/clusters` → all functional areas.\n - `gitnexus://repo/DotNetBars/processes` → all execution flows.\n - `gitnexus://repo/DotNetBars/process/{name}` → step-by-step execution trace.\n\n4. **CLI Skill Mapping** – A table that links common developer tasks to the corresponding skill files, enabling the AI to deep-dive into the correct procedure:\n - Understanding architecture → `gitnexus-exploring/SKILL.md`\n - Blast radius analysis → `gitnexus-impact-analysis/SKILL.md`\n - Bug tracing → `gitnexus-debugging/SKILL.md`\n - Refactoring (rename, extract, split) → `gitnexus-refactoring/SKILL.md`\n - Tools and schema reference → `gitnexus-guide/SKILL.md`\n - CLI commands (index, status, clean, wiki) → `gitnexus-cli/SKILL.md`\n\n## Workflow Enforced\n\nThe instructions in `CLAUDE.md` define a linear lockdown workflow that the AI must follow for every code modification:\n\n```mermaid\nflowchart LR\n A[Start session] --> B[Read CLAUDE.md]\n B --> C[Identify symbol to edit]\n C --> D[Run gitnexus_impact]\n D --> E{Blast radius acceptable?}\n E -- No --> F[Warn user]\n F --> G[Abort or reconsider]\n E -- Yes --> H[Make edit]\n H --> I[Run gitnexus_detect_changes]\n I --> J{Changes expected?}\n J -- No --> K[Rollback / investigate]\n J -- Yes --> L[Commit]\n```\n\nThis workflow is triggered before any function, class, or method is modified. It prevents accidental ripple effects and ensures that the developer (human) is fully informed of the consequences of a change.\n\n## Relationship to the Broader Project\n\n`CLAUDE.md` is part of the **GitNexus code intelligence** integration (index name `DotNetBars`). It does not itself participate in any execution flow or internal call graph — it is a passive configuration file. However, it is the primary mechanism through which the AI assistant interacts with the GitNexus MCP tools. Without this file, the AI would lack explicit rules for safe navigation and modification, potentially leading to unintended damage.\n\nThe file references all major GitNexus subsystems: impact analysis, context retrieval, query, rename, and change detection. By centralizing these instructions, it reduces the cognitive load on the developer and enforces a uniform safety policy across all AI-assisted sessions.","project-documentation-docs":"# Project Documentation — docs\n\n# Project Documentation — `docs/` Module\n\n## Purpose\n\nThe `docs/` directory contains the planning, architecture, and technical reference documents for the Handlebars.Net rewrite project. These documents are the authoritative source for understanding the design decisions, implementation roadmap, and current state of the project. They bridge the gap between the high-level goals and the actual source code in `src/`.\n\n## Document Inventory\n\n| File | Purpose | Primary Audience |\n|------|---------|-----------------|\n| `01-architecture.md` | Describes the current Handlebars.Net codebase architecture (~27K LOC pipeline), core types, and compilation flow. | Developers understanding the legacy system |\n| `02-performance-analysis.md` | Identifies 10 critical bottlenecks and ~10 high-severity issues in the current codebase. | Contributors optimizing the rewrite |\n| `03-rewrite-vs-refactor.md` | Compares the legacy .NET port (~27K LOC) to the handlebars.js reference (~3.5K LOC). Argues for a full rewrite. | Decision-makers, new contributors |\n| `04-code-generation.md` | Clarifies compile-time (Roslyn) vs runtime (Expression trees, IL emit) code generation, given the project's runtime template compilation requirement. | Developers implementing optimization phases |\n| `05-work-plan.md` | High-level roadmap organized by concern (core pipeline, helpers, optimizations, etc.). Defines package layout and success metrics. | Project managers, contributors planning work |\n| `06-implementation-plan.md` | Detailed step-by-step execution guide organized by phase (parser → compiler → runtime → etc.). Includes test strategy and gold file pipeline. | Developers implementing each phase |\n| `07-tech-debt.md` | Living document tracking all known issues (67 total, 42 resolved as of last update). Prioritized by severity with resolution progress. | All contributors tracking blockers |\n| `08-progress.md` | Session-level progress log (last update 2026-05-07). Lists test results per spec file, features completed, and remaining bugs. | Developers continuing work from previous session |\n| `09-handover.md` | End-of-session handover document (2026-05-07). Lists remaining skipped tests (32) in 6 categories with recommended next steps. | Developers starting a new session |\n| `COMPAT.md` | Documents the `Handlebars.Compat` compatibility shim: supported legacy types, unsupported features, and differences from the original API. | Users migrating from old API |\n\n## Document Relationships\n\n```\n01-architecture.md ── describes the old codebase (context for rewrite)\n │\n02-performance-analysis.md ── why rewrite is needed\n │\n03-rewrite-vs-refactor.md ── decides to rewrite\n │\n05-work-plan.md ── high-level roadmap\n │\n06-implementation-plan.md ── detailed execution phases\n │\n ├── 04-code-generation.md ── clarifies a specific technique used in phases 4-5\n │\n ├── 07-tech-debt.md ── tracks issues discovered during implementation\n │\n ├── 08-progress.md ── logs session-by-session progress\n │\n ├── 09-handover.md ── provides continuation guide for next developer\n │\n └── COMPAT.md ── documents the compatibility layer built in phase 9\n```\n\n## How to Use These Documents\n\n### Entry Points\n\n- **New contributor**: Start with `03-rewrite-vs-refactor.md` to understand the project’s motivation, then `05-work-plan.md` for the overall structure.\n- **Implementing a specific phase**: Read the relevant section in `06-implementation-plan.md`, cross‑reference with `07-tech-debt.md` for known blockers, and check `08-progress.md` for what was already done.\n- **Resuming work after a pause**: Begin with `09-handover.md`; it lists the exact next steps and which files to change.\n\n### Integration with Source Code\n\nThe documents reference actual files in `src/Handlebars/` (e.g., `Ast.cs`, `Compiler.cs`, `BytecodeInterpreter.cs`). When a document says “Implement X in `BytecodeInterpreter.cs`”, that file lives under the `src/Handlebars/` directory. The test suite (`Handlebars.Test/`) maps directly to the test files referenced in `06-implementation-plan.md`.\n\n### Keeping Documents Up to Date\n\nThese documents are living artifacts. When you fix a bug or implement a feature:\n\n1. Update `07-tech-debt.md` – mark the issue as resolved and note the date.\n2. Update `08-progress.md` – add a new session entry with test results.\n3. Update `09-handover.md` – rewrite it at the end of your session to hand off to the next developer.\n\nOutdated documents can mislead future contributors; keep them synchronized with the actual code state.\n\n## Relationship to the Codebase\n\nThe `docs/` module is not compiled or executed. It exists to guide human contributors. Every architectural decision, optimization technique, and known issue documented here has a direct counterpart in the `src/Handlebars/` implementation. The documentation is the project’s memory and reasoning; without it, the codebase would appear as a collection of files without context.\n\nThe test golden files and oracle scripts mentioned in `06-implementation-plan.md` live in `test/golden/` and are used by the test suite to validate parser, compiler, and renderer output against handlebars.js.","project-documentation-handlebars-js-docs":"# Project Documentation — handlebars.js-docs\n\n# Project Documentation — handlebars.js-docs\n\nThis module provides formal API reference documentation for developers who need to extend, customize, or integrate with Handlebars.js at a programmatic level. It consists of two documents that describe the compiler and decorator interfaces.\n\n## Purpose\n\nThe `handlebars.js-docs` module serves as the canonical source of truth for:\n\n- The Handlebars Abstract Syntax Tree (AST) structure, parsing APIs, and visitor pattern\n- The JavaScript compiler customization points (`nameLookup`, `appendToBuffer`, etc.)\n- The decorator registration and execution API (deprecated)\n\nThese documents target tool authors, codemod maintainers, and developers building custom compiler behavior – not typical template users.\n\n## Documents\n\n### `compiler-api.md`\n\nDescribes three major subsystems:\n\n| Subsystem | Key APIs / Interfaces | Purpose |\n|-----------|-----------------------|---------|\n| AST | `Handlebars.parse`, `Handlebars.parseWithoutProcessing`, `Program`, `MustacheStatement`, `BlockStatement`, `PathExpression`, `Literal` types | Represent templates as structured data; enable static analysis, transformation, and custom compilation |\n| AST Visitor | `Handlebars.Visitor`, `accept`, `acceptKey`, `acceptArray`, mutation mode | Traverse and optionally mutate the AST for tasks like partial scanning or whitespace normalization |\n| JavaScript Compiler | `Handlebars.JavaScriptCompiler`, methods `nameLookup`, `depthedLookup`, `compilerInfo`, `appendToBuffer`, `initializeBuffer` | Customize generated JavaScript code (e.g., property resolution, buffering) by subclassing the compiler |\n\nThe document includes a full type interface definition for all AST nodes and a worked example that overrides `nameLookup` to implement case‑insensitive property lookup.\n\n### `decorators-api.md`\n\nDocuments the deprecated decorator system:\n\n- Registration via `registerDecorators` / `unregisterDecorators`\n- Template syntax: `{{* decorator}}` and `{{#* decorator}}{/decorator}}`\n- Execution arguments passed to decorator functions: `(program, props, container, context, data, blockParams, depths)`\n- The `props` object for metadata, and how returning a wrapper function modifies `program`\n\nThe decorator implementation in `lib/handlebars/decorators/inline.js` is cited as a reference example.\n\n## How the Module Works\n\nThese documents are **static reference material**. They exist alongside the Handlebars runtime library and do not contain executable code or build steps. Developers read them to:\n\n1. Understand the exact shape of AST nodes produced by the parser.\n2. Learn how to traverse or transform the AST using `Handlebars.Visitor`.\n3. Subclass `Handlebars.JavaScriptCompiler` to alter code generation.\n4. Implement custom decorators (with the understanding that the feature is deprecated).\n\n## Connection to the Codebase\n\nThe APIs documented here map directly to source modules in the Handlebars.js repository:\n\n- **Parser/AST**: `lib/handlebars/parser.js`, `lib/handlebars/ast.js`\n- **Visitor**: `lib/handlebars/visitor.js`\n- **JavaScript compiler**: `lib/handlebars/compiler/javascript-compiler.js`\n- **Decorators**: `lib/handlebars/decorators.js`, `lib/handlebars/decorators/`\n\nThe documentation serves as the bridge between the internal implementation and external developers who want to build tools on top of Handlebars without reading the raw source code.\n\n```mermaid\nflowchart LR\n subgraph handlbars.js\n Parser\n AST\n Visitor\n Compiler\n Decorators\n end\n\n subgraph docs\n Compiler_API[\"compiler-api.md\"]\n Decorators_API[\"decorators-api.md\"]\n end\n\n Parser --> Compiler_API\n AST --> Compiler_API\n Visitor --> Compiler_API\n Compiler --> Compiler_API\n Decorators --> Decorators_API\n```\n\nThe diagram shows that `compiler-api.md` covers Parser, AST, Visitor, and Compiler internals, while `decorators-api.md` is dedicated solely to decorator interfaces.","project-documentation-handlebars-js":"# Project Documentation — handlebars.js\n\n# Handlebars.js Project Documentation Module\n\n## Overview\n\nThe project documentation module comprises three Markdown files that serve as the canonical reference for contributors and users of Handlebars.js:\n\n- **README.md** — the primary entry point for the project on GitHub and npm.\n- **FAQ.md** — addresses common issues and misconceptions.\n- **release-notes.md** — a chronological changelog of every release from v1.0.0 to the current master branch.\n\nThese files are version-controlled in the repository root alongside the source code. They are not compiled or executed; they are consumed directly by GitHub, npm, and docs.handlebarsjs.com.\n\n## File Descriptions\n\n### README.md\n\nThis file is the face of the project. It includes:\n\n- **Badges** — CI status, download counts, bundle size, install size, npm version.\n- **Quick Start** — installation instructions and a complete `Handlebars.compile` example.\n- **Precompilation guidance** — links to detailed documentation.\n- **Mustache compatibility** — a list of intentional differences (nested paths, helpers, block expressions, literal values, delimited comments).\n- **Environment support** — ECMAScript 2020+ (Node.js, Chrome, Firefox, Safari, Edge); older environments should use Handlebars v4.\n- **Performance** — a summary of benchmark methodology using tinybench, plus commands for running benchmarks and comparing branches (`npm run bench`, `npm run bench:compare`).\n- **Upgrading** — a pointer to `release-notes.md` and a note about issues labeled “possibly breaking”.\n- **Known Issues** — a pointer to `FAQ.md`.\n- **Handlebars in the Wild** — a curated list of projects (Ember.js, Ghost, express-handlebars, webpack loaders, etc.) that use Handlebars.\n- **License** — MIT.\n\nKey API references in this file:\n- `Handlebars.compile(source)` — compiles a template string into a function.\n- `Handlebars.VERSION` — used to verify runtime/compiler version matching.\n- `Handlebars.create` — for sandboxed instances (mentioned in release notes).\n\n### FAQ.md\n\nAnswers seven common questions:\n\n1. **How to file a bug report** — directs to `CONTRIBUTING.md`.\n2. **Mustache template not working** — links to the README differences section.\n3. **Slow compilation** — explains parse → generate JS program; recommends precompilation.\n4. **Content Security Policy restrictions** — notes that dynamic `Function` generation is used; suggests precompilation or `unsafe-eval`.\n5. **Script tags in templates** — provides the `{{!}}` workaround for inline `<script>` blocks.\n6. **Precompiled script exceptions** — advises version matching between `handlebars --version` and `Handlebars.VERSION`; warns about 1.x vs 2.x incompatibility.\n7. **AMD loading of runtime** — mentions UMD build with `default` export.\n\n### release-notes.md\n\nA detailed changelog covering every release from v1.0.0 to v4.7.7 (Feb 2021). Each entry lists:\n\n- **Release date** and version number.\n- **Commits** — a compare link to GitHub.\n- **Features, bug fixes, chores** — with issue/PR references and contributor mentions.\n- **Compatibility notes** — highlighting breaking changes (even if only patch-level) and migration steps.\n\nNotable breaking changes documented here:\n- v4.6.0: Access to `__proto__`, `constructor`, and other prototype properties is forbidden by default (whitelist via runtime options).\n- v4.3.0: `helperMissing` and `blockHelperMissing` can no longer be called directly from templates; `allowCallsToHelperMissing` runtime option added.\n- v4.1.0: Constructor access prohibited (RCE fix).\n- v4.0.0: Decorators, inline partials, partial blocks, depthed path behavior changes, HTML escaping of `=`.\n- v3.0.0: Dynamic partials, source maps, block params, strict mode, AST as public API.\n- v2.0.0: Whitespace control, false printed, standalone partials indentation, removed `programWithDepth`.\n\n## Relationship to the Codebase\n\nThese three files are **user-facing documentation**, not executable code. They complement the source code at `lib/handlebars.js`, the CLI binary at `bin/handlebars`, and the runtime at `dist/handlebars.runtime.js`. The release notes track every change to those source files and are used by:\n\n- **Developers** — to understand what changed between versions.\n- **CI/CD** — to generate release artifacts (the release-notes.md sections are often included in GitHub Releases).\n- **Documentation site** — `handlebarsjs.com` pulls content from these files (especially README and FAQ).\n\nThere is no cross-reference within the codebase that imports or parses these markdown files; they are purely documentation assets.\n\n## Maintenance Guidelines\n\nWhen contributing to Handlebars.js, follow these practices for the documentation module:\n\n- **README.md** — Update badges, installation instructions, or compatibility lists when the project’s behavior or supported environments change. Keep the benchmark commands accurate.\n- **FAQ.md** — Add new entries only for recurring, well-understood issues. Avoid transient debugging questions.\n- **release-notes.md** — Every pull request that changes behavior (feature, fix, refactor) must add an entry under the `## Development` heading. Entries should include the commit hash, a brief description, and the issue/PR number when applicable. Before a release, the `## Development` section is renamed to the new version and a new `## Development` placeholder is added.\n\n**Version tracking**: The `COMPILER_REVISION` constant (in `lib/handlebars/compiler/javascript-compiler.js`) must be bumped whenever the compiled output format changes. This should be accompanied by a note in release-notes.md under compatibility notes, as done in v4.3.0.\n\n**Linking**: Use relative links between these files (e.g., `[release-notes.md](./release-notes.md)`). The documentation site maintainers rely on these links when converting to HTML.","project-documentation":"# Project Documentation\n\n# Project Documentation Module\n\nThe **Project Documentation** module consolidates all Markdown files and directories that serve as the canonical reference for the Handlebars.Net rewrite (branch `vnext`) and its companion Handlebars.js projects. These documents are not executable code; they are consumed by humans and AI agents to onboard, coordinate, understand architecture, and contribute safely.\n\n## Sub‑Modules\n\n- [AGENTS.md](agents.md) – Developer onboarding & agent coordination document for the Handlebars.Net rewrite.\n- [ARCHITECTURE.md](architecture.md) – Canonical architectural reference for the DotNetBars codebase (the rewrite).\n- [CLAUDE.md](claude.md) – Safety‑first workflow instructions for AI coding assistants, enforcing blast‑radius analysis.\n- [docs/](docs.md) – Planning, architecture, and technical reference documents bridging high‑level goals with actual source code.\n- [handlebars.js](handlebars-js.md) – User‑facing documentation (README, FAQ, release notes) for the JavaScript implementation.\n- [handlebars.js-docs](handlebars-js-docs.md) – Formal API reference (AST, compiler customization, decorators) for tool authors.\n\n## How the Sub‑Modules Fit Together\n\nThe documents target distinct audiences but share a common goal: enabling contributors to understand, modify, and extend the project with minimal friction.\n\n- **Onboarding & agent guidance** \n `AGENTS.md` and `CLAUDE.md` are the first files read by humans and AI agents. They define the mandatory workflow (e.g., GitNexus integration, blast‑radius analysis) and point users to deeper resources.\n\n- **Architectural & planning depth** \n `ARCHITECTURE.md` and the `docs/` directory provide the detailed design decisions, component boundaries, and implementation roadmap. They are consulted after initial orientation.\n\n- **JavaScript documentation** \n The two `handlebars.js` sub‑modules serve separate needs: the broad user documentation (`handlebars.js`) and the technical API reference for extensions (`handlebars.js-docs`). These are referenced when working on the JavaScript side of the cross‑language ecosystem.\n\nThere are no execution flows that span these sub‑modules; their relationship is purely informational.\n\n## Key Workflows\n\n1. **First‑time developer onboarding** \n → Read `AGENTS.md` for build commands and project layout. \n → Follow `CLAUDE.md` instructions when using an AI assistant. \n → Consult `ARCHITECTURE.md` and `docs/` for deep understanding.\n\n2. **AI‑assisted contribution** \n → `CLAUDE.md` enforces a blast‑radius check before any edit. \n → The agent uses `AGENTS.md` to learn the codebase structure and GitNexus tools. \n → Architectural questions are answered from `ARCHITECTURE.md`.\n\n3. **JavaScript feature extension or bug fix** \n → Start with `handlebars.js` (README) for project status and `release-notes`. \n → Use `handlebars.js-docs` for the AST and compiler APIs. \n → Cross‑reference `AGENTS.md` if the fix involves the .NET rewrite.\n\n## Relationships Overview\n\n```mermaid\ngraph TD\n subgraph \"Onboarding & Agent\"\n AGENTS[AGENTS.md]\n CLAUDE[CLAUDE.md]\n end\n subgraph \"Architecture & Planning\"\n ARCH[ARCHITECTURE.md]\n DOCS[docs/]\n end\n subgraph \"JavaScript Docs\"\n HBJS[handlebars.js]\n HBJSDOCS[handlebars.js-docs]\n end\n\n AGENTS -->|points to| ARCH\n AGENTS -->|points to| DOCS\n AGENTS -->|references| HBJS\n AGENTS -->|references| HBJSDOCS\n CLAUDE -->|mandates workflow using| AGENTS\n CLAUDE -->|enforces| ARCH\n CLAUDE -->|enforces| DOCS\n Developers -->|read first| AGENTS\n Developers -->|read first| CLAUDE\n Developers -->|consult| ARCH\n Developers -->|consult| DOCS\n Developers -->|use| HBJS\n ToolAuthors -->|use| HBJSDOCS\n```\n\nClick on any sub‑module link above for full details."};
var TREE = [{"name":"JavaScript Handlebars Core","slug":"javascript-handlebars-core","files":["handlebars.js/lib/handlebars.js","handlebars.js/lib/handlebars.runtime.js","handlebars.js/lib/handlebars/base.js","handlebars.js/lib/handlebars/runtime.js","handlebars.js/lib/handlebars/utils.js","handlebars.js/lib/handlebars/safe-string.js","handlebars.js/lib/handlebars/logger.js","handlebars.js/lib/handlebars/no-conflict.js","handlebars.js/lib/handlebars/internal/proto-access.js","handlebars.js/lib/handlebars/internal/wrapHelper.js","handlebars.js/lib/index.js","handlebars.js/runtime.js"]},{"name":"JavaScript Handlebars Compiler","slug":"javascript-handlebars-compiler","files":["handlebars.js/lib/handlebars/compiler/ast.js","handlebars.js/lib/handlebars/compiler/code-gen.js","handlebars.js/lib/handlebars/compiler/compiler.js","handlebars.js/lib/handlebars/compiler/javascript-compiler.js","handlebars.js/lib/handlebars/compiler/source-node.browser.js","handlebars.js/lib/handlebars/compiler/source-node.node.js"]},{"name":"JavaScript Handlebars Helpers & Decorators","slug":"javascript-handlebars-helpers-decorators","files":["handlebars.js/lib/handlebars/helpers.js","handlebars.js/lib/handlebars/helpers/block-helper-missing.js","handlebars.js/lib/handlebars/helpers/each.js","handlebars.js/lib/handlebars/helpers/helper-missing.js","handlebars.js/lib/handlebars/helpers/if.js","handlebars.js/lib/handlebars/helpers/log.js","handlebars.js/lib/handlebars/helpers/lookup.js","handlebars.js/lib/handlebars/helpers/with.js","handlebars.js/lib/handlebars/decorators.js","handlebars.js/lib/handlebars/decorators/inline.js"]},{"name":"JavaScript Handlebars CLI & Packaging","slug":"javascript-handlebars-cli-packaging","files":["handlebars.js/lib/precompiler.js","handlebars.js/components/lib/handlebars/source.rb"]},{"name":".NET Handlebars Core","slug":"net-handlebars-core","files":["src/Handlebars/Ast.cs","src/Handlebars/BytecodeInterpreter.cs","src/Handlebars/CompileOptions.cs","src/Handlebars/Compiler.cs","src/Handlebars/Engine.cs","src/Handlebars/HandlebarsException.cs","src/Handlebars/Opcodes.cs","src/Handlebars/Parser.cs","src/Handlebars/RuntimeUtils.cs","src/Handlebars/SafeString.cs","src/Handlebars/Template.cs"]},{"name":".NET Handlebars Helpers","slug":"net-handlebars-helpers","files":["src/Handlebars/Helpers/EachHelper.cs","src/Handlebars/Helpers/IfHelper.cs","src/Handlebars/Helpers/LogHelper.cs","src/Handlebars/Helpers/LookupHelper.cs","src/Handlebars/Helpers/WithHelper.cs"]},{"name":".NET Handlebars Compatibility Layer","slug":"net-handlebars-compatibility-layer","files":["src/Handlebars.Compat/Arguments.cs","src/Handlebars.Compat/BindingContext.cs","src/Handlebars.Compat/Context.cs","src/Handlebars.Compat/Delegates.cs","src/Handlebars.Compat/EncodedTextWriter.cs","src/Handlebars.Compat/Handlebars.cs","src/Handlebars.Compat/HandlebarsConfiguration.cs","src/Handlebars.Compat/HelperOptions.cs"]},{"name":"Project Documentation","slug":"project-documentation","files":[],"children":[{"name":"Project Documentation — AGENTS.md","slug":"project-documentation-agents-md","files":["AGENTS.md"]},{"name":"Project Documentation — ARCHITECTURE.md","slug":"project-documentation-architecture-md","files":["ARCHITECTURE.md"]},{"name":"Project Documentation — CLAUDE.md","slug":"project-documentation-claude-md","files":["CLAUDE.md"]},{"name":"Project Documentation — docs","slug":"project-documentation-docs","files":["docs/01-architecture.md","docs/02-performance-analysis.md","docs/03-rewrite-vs-refactor.md","docs/04-code-generation.md","docs/05-work-plan.md","docs/06-implementation-plan.md","docs/07-tech-debt.md","docs/08-progress.md","docs/09-handover.md","docs/COMPAT.md"]},{"name":"Project Documentation — handlebars.js","slug":"project-documentation-handlebars-js","files":["handlebars.js/FAQ.md","handlebars.js/README.md","handlebars.js/release-notes.md"]},{"name":"Project Documentation — handlebars.js-docs","slug":"project-documentation-handlebars-js-docs","files":["handlebars.js/docs/compiler-api.md","handlebars.js/docs/decorators-api.md"]}]},{"name":"Other","slug":"other","files":[],"children":[{"name":"Other — components","slug":"other-components","files":["handlebars.js/components/bower.json","handlebars.js/components/component.json","handlebars.js/components/composer.json","handlebars.js/components/handlebars-source.gemspec","handlebars.js/components/handlebars.js.nuspec","handlebars.js/components/package.json"]},{"name":"Other — handlebars.js","slug":"other-handlebars-js","files":["handlebars.js/eslint.config.js","handlebars.js/generate_golden.js","handlebars.js/package.json","handlebars.js/rspack.config.js","handlebars.js/vitest.config.js"]},{"name":"Other — spec","slug":"other-spec","files":["handlebars.js/spec/artifacts/bom.handlebars","handlebars.js/spec/artifacts/empty.handlebars","handlebars.js/spec/artifacts/example_1.handlebars","handlebars.js/spec/artifacts/example_2.hbs","handlebars.js/spec/artifacts/known.helpers.handlebars","handlebars.js/spec/artifacts/non.default.extension.hbs","handlebars.js/spec/artifacts/partial.template.handlebars","handlebars.js/spec/ast.js","handlebars.js/spec/basic.js","handlebars.js/spec/blocks.js","handlebars.js/spec/builtins.js","handlebars.js/spec/compiler.js","handlebars.js/spec/data.js","handlebars.js/spec/expected/compiled.string.txt","handlebars.js/spec/expected/empty.namespace.js","handlebars.js/spec/expected/help.menu.txt","handlebars.js/spec/helpers.js","handlebars.js/spec/index.html","handlebars.js/spec/javascript-compiler.js","handlebars.js/spec/partials.js","handlebars.js/spec/precompiler.js","handlebars.js/spec/regressions.js","handlebars.js/spec/runtime.js","handlebars.js/spec/security.js","handlebars.js/spec/source-map.js","handlebars.js/spec/spec.js","handlebars.js/spec/strict.js","handlebars.js/spec/subexpressions.js","handlebars.js/spec/utils.js","handlebars.js/spec/whitespace-control.js"]},{"name":"Other — tasks","slug":"other-tasks","files":["handlebars.js/tasks/publish-to-aws.js","handlebars.js/tasks/tests/README.md","handlebars.js/tasks/tests/cli.test.js","handlebars.js/tasks/tests/fake-s3.js","handlebars.js/tasks/tests/git.test.js","handlebars.js/tasks/tests/publish-to-aws.test.js","handlebars.js/tasks/util/git.js","handlebars.js/tasks/version.js"]},{"name":"Other — test_fixtures","slug":"other-test-fixtures","files":["handlebars.js/test_fixtures/0.ast.json","handlebars.js/test_fixtures/0.hbs","handlebars.js/test_fixtures/1.ast.json","handlebars.js/test_fixtures/1.hbs","handlebars.js/test_fixtures/10.ast.json","handlebars.js/test_fixtures/10.hbs","handlebars.js/test_fixtures/11.ast.json","handlebars.js/test_fixtures/11.hbs","handlebars.js/test_fixtures/12.ast.json","handlebars.js/test_fixtures/12.hbs","handlebars.js/test_fixtures/13.ast.json","handlebars.js/test_fixtures/13.hbs","handlebars.js/test_fixtures/14.ast.json","handlebars.js/test_fixtures/14.hbs","handlebars.js/test_fixtures/15.ast.json","handlebars.js/test_fixtures/15.hbs","handlebars.js/test_fixtures/16.ast.json","handlebars.js/test_fixtures/16.hbs","handlebars.js/test_fixtures/17.ast.json","handlebars.js/test_fixtures/17.hbs","handlebars.js/test_fixtures/18.ast.json","handlebars.js/test_fixtures/18.hbs","handlebars.js/test_fixtures/19.ast.json","handlebars.js/test_fixtures/19.hbs","handlebars.js/test_fixtures/2.ast.json","handlebars.js/test_fixtures/2.hbs","handlebars.js/test_fixtures/20.ast.json","handlebars.js/test_fixtures/20.hbs","handlebars.js/test_fixtures/21.ast.json","handlebars.js/test_fixtures/21.hbs","handlebars.js/test_fixtures/22.ast.json","handlebars.js/test_fixtures/22.hbs","handlebars.js/test_fixtures/23.ast.json","handlebars.js/test_fixtures/23.hbs","handlebars.js/test_fixtures/24.ast.json","handlebars.js/test_fixtures/24.hbs","handlebars.js/test_fixtures/25.ast.json","handlebars.js/test_fixtures/25.hbs","handlebars.js/test_fixtures/26.ast.json","handlebars.js/test_fixtures/26.hbs","handlebars.js/test_fixtures/27.ast.json","handlebars.js/test_fixtures/27.hbs","handlebars.js/test_fixtures/28.ast.json","handlebars.js/test_fixtures/28.hbs","handlebars.js/test_fixtures/29.ast.json","handlebars.js/test_fixtures/29.hbs","handlebars.js/test_fixtures/3.ast.json","handlebars.js/test_fixtures/3.hbs","handlebars.js/test_fixtures/4.ast.json","handlebars.js/test_fixtures/4.hbs","handlebars.js/test_fixtures/5.ast.json","handlebars.js/test_fixtures/5.hbs","handlebars.js/test_fixtures/6.ast.json","handlebars.js/test_fixtures/6.hbs","handlebars.js/test_fixtures/7.ast.json","handlebars.js/test_fixtures/7.hbs","handlebars.js/test_fixtures/8.ast.json","handlebars.js/test_fixtures/8.hbs","handlebars.js/test_fixtures/9.ast.json","handlebars.js/test_fixtures/9.hbs","handlebars.js/test_fixtures/comp_0.hbs","handlebars.js/test_fixtures/comp_0.spec.json","handlebars.js/test_fixtures/comp_1.hbs","handlebars.js/test_fixtures/comp_1.spec.json","handlebars.js/test_fixtures/comp_2.hbs","handlebars.js/test_fixtures/comp_2.spec.json","handlebars.js/test_fixtures/comp_3.hbs","handlebars.js/test_fixtures/comp_3.spec.json","handlebars.js/test_fixtures/comp_4.hbs","handlebars.js/test_fixtures/comp_4.spec.json","handlebars.js/test_fixtures/comp_5.hbs","handlebars.js/test_fixtures/comp_5.spec.json","handlebars.js/test_fixtures/comp_6.hbs","handlebars.js/test_fixtures/comp_6.spec.json","handlebars.js/test_fixtures/comp_7.hbs","handlebars.js/test_fixtures/comp_7.spec.json","handlebars.js/test_fixtures/comp_8.hbs","handlebars.js/test_fixtures/comp_8.spec.json","handlebars.js/test_fixtures/comp_9.hbs","handlebars.js/test_fixtures/comp_9.spec.json"]},{"name":"Other — tests","slug":"other-tests","files":["handlebars.js/tests/bench/compare.js","handlebars.js/tests/bench/perf.js","handlebars.js/tests/bench/report.js","handlebars.js/tests/bench/size.js","handlebars.js/tests/bench/templates.js","handlebars.js/tests/browser/README.md","handlebars.js/tests/browser/playwright.config.js","handlebars.js/tests/browser/tests/lib.spec.js","handlebars.js/tests/integration/README.md","handlebars.js/tests/integration/multi-nodejs-test/package.json","handlebars.js/tests/integration/multi-nodejs-test/precompile-test-template.txt.hbs","handlebars.js/tests/integration/multi-nodejs-test/run-handlebars.js","handlebars.js/tests/integration/multi-nodejs-test/test.sh","handlebars.js/tests/integration/rollup-test/package.json","handlebars.js/tests/integration/rollup-test/rollup.config.js","handlebars.js/tests/integration/rollup-test/src/index.js","handlebars.js/tests/integration/rollup-test/test.sh","handlebars.js/tests/integration/run-integration-tests.sh","handlebars.js/tests/integration/webpack-test/package.json","handlebars.js/tests/integration/webpack-test/src/handlebars-default-import-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-esm-import-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-loader-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-register-helper-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-runtime-test.js","handlebars.js/tests/integration/webpack-test/src/lib/assert.js","handlebars.js/tests/integration/webpack-test/src/test-template.handlebars","handlebars.js/tests/integration/webpack-test/test.sh","handlebars.js/tests/integration/webpack-test/webpack.config.js","handlebars.js/tests/print-script.js","handlebars.js/tests/rspack/rspack.test.js"]},{"name":"Other — types","slug":"other-types","files":["handlebars.js/types/__typetests__/handlebars.tst.ts","handlebars.js/types/tsconfig.json"]},{"name":"Other — Handlebars.Compat","slug":"other-handlebars-compat","files":["src/Handlebars.Compat/Handlebars.Compat.csproj"]},{"name":"Other — Handlebars.Test","slug":"other-handlebars-test","files":["src/Handlebars.Test/AstSerializationTests.cs","src/Handlebars.Test/BasicTests.cs","src/Handlebars.Test/BlocksTests.cs","src/Handlebars.Test/BuiltinsTests.cs","src/Handlebars.Test/CompatTests.cs","src/Handlebars.Test/CompilerTests.cs","src/Handlebars.Test/ComplexRenderTests.cs","src/Handlebars.Test/DataTests.cs","src/Handlebars.Test/GoldenAstTests.cs","src/Handlebars.Test/GoldenRenderTests.cs","src/Handlebars.Test/Handlebars.Test.csproj","src/Handlebars.Test/HelperTests.cs","src/Handlebars.Test/ParserTests.cs","src/Handlebars.Test/PartialTests.cs","src/Handlebars.Test/RegressionTests.cs","src/Handlebars.Test/RenderingTests.cs","src/Handlebars.Test/StrictTests.cs","src/Handlebars.Test/SubExpressionTests.cs","src/Handlebars.Test/TestHelper.cs","src/Handlebars.Test/WhitespaceTests.cs"]},{"name":"Other — Handlebars.TestApp","slug":"other-handlebars-testapp","files":["src/Handlebars.TestApp/Handlebars.TestApp.csproj","src/Handlebars.TestApp/Program.cs","src/Handlebars.TestApp/templates/advanced.hbs","src/Handlebars.TestApp/templates/advanced.json","src/Handlebars.TestApp/templates/hello.hbs","src/Handlebars.TestApp/templates/hello.json"]},{"name":"Other — src","slug":"other-src","files":["src/Handlebars.slnx"]},{"name":"Other — Handlebars","slug":"other-handlebars","files":["src/Handlebars/Handlebars.csproj"]},{"name":"Other — golden","slug":"other-golden","files":["test/golden/parser/0.ast.json","test/golden/parser/0.hbs","test/golden/parser/1.ast.json","test/golden/parser/1.hbs","test/golden/parser/10.ast.json","test/golden/parser/10.hbs","test/golden/parser/11.ast.json","test/golden/parser/11.hbs","test/golden/parser/12.ast.json","test/golden/parser/12.hbs","test/golden/parser/13.ast.json","test/golden/parser/13.hbs","test/golden/parser/14.ast.json","test/golden/parser/14.hbs","test/golden/parser/15.ast.json","test/golden/parser/15.hbs","test/golden/parser/16.ast.json","test/golden/parser/16.hbs","test/golden/parser/17.ast.json","test/golden/parser/17.hbs","test/golden/parser/18.ast.json","test/golden/parser/18.hbs","test/golden/parser/19.ast.json","test/golden/parser/19.hbs","test/golden/parser/2.ast.json","test/golden/parser/2.hbs","test/golden/parser/20.ast.json","test/golden/parser/20.hbs","test/golden/parser/21.ast.json","test/golden/parser/21.hbs","test/golden/parser/22.ast.json","test/golden/parser/22.hbs","test/golden/parser/23.ast.json","test/golden/parser/23.hbs","test/golden/parser/24.ast.json","test/golden/parser/24.hbs","test/golden/parser/25.ast.json","test/golden/parser/25.hbs","test/golden/parser/26.ast.json","test/golden/parser/26.hbs","test/golden/parser/27.ast.json","test/golden/parser/27.hbs","test/golden/parser/28.ast.json","test/golden/parser/28.hbs","test/golden/parser/29.ast.json","test/golden/parser/29.hbs","test/golden/parser/3.ast.json","test/golden/parser/3.hbs","test/golden/parser/4.ast.json","test/golden/parser/4.hbs","test/golden/parser/5.ast.json","test/golden/parser/5.hbs","test/golden/parser/6.ast.json","test/golden/parser/6.hbs","test/golden/parser/7.ast.json","test/golden/parser/7.hbs","test/golden/parser/8.ast.json","test/golden/parser/8.hbs","test/golden/parser/9.ast.json","test/golden/parser/9.hbs"]}]}];
var META = {"fromCommit":"ade653f8b6909834c470b3169e5f63d00bf88ad0","generatedAt":"2026-05-07T08:31:24.515Z","model":"deepseek-v4-flash","moduleFiles":{"JavaScript Handlebars Core":["handlebars.js/lib/handlebars.js","handlebars.js/lib/handlebars.runtime.js","handlebars.js/lib/handlebars/base.js","handlebars.js/lib/handlebars/runtime.js","handlebars.js/lib/handlebars/utils.js","handlebars.js/lib/handlebars/safe-string.js","handlebars.js/lib/handlebars/logger.js","handlebars.js/lib/handlebars/no-conflict.js","handlebars.js/lib/handlebars/internal/proto-access.js","handlebars.js/lib/handlebars/internal/wrapHelper.js","handlebars.js/lib/index.js","handlebars.js/runtime.js"],"JavaScript Handlebars Compiler":["handlebars.js/lib/handlebars/compiler/ast.js","handlebars.js/lib/handlebars/compiler/code-gen.js","handlebars.js/lib/handlebars/compiler/compiler.js","handlebars.js/lib/handlebars/compiler/javascript-compiler.js","handlebars.js/lib/handlebars/compiler/source-node.browser.js","handlebars.js/lib/handlebars/compiler/source-node.node.js"],"JavaScript Handlebars Helpers & Decorators":["handlebars.js/lib/handlebars/helpers.js","handlebars.js/lib/handlebars/helpers/block-helper-missing.js","handlebars.js/lib/handlebars/helpers/each.js","handlebars.js/lib/handlebars/helpers/helper-missing.js","handlebars.js/lib/handlebars/helpers/if.js","handlebars.js/lib/handlebars/helpers/log.js","handlebars.js/lib/handlebars/helpers/lookup.js","handlebars.js/lib/handlebars/helpers/with.js","handlebars.js/lib/handlebars/decorators.js","handlebars.js/lib/handlebars/decorators/inline.js"],"JavaScript Handlebars CLI & Packaging":["handlebars.js/lib/precompiler.js","handlebars.js/components/lib/handlebars/source.rb"],".NET Handlebars Core":["src/Handlebars/Ast.cs","src/Handlebars/BytecodeInterpreter.cs","src/Handlebars/CompileOptions.cs","src/Handlebars/Compiler.cs","src/Handlebars/Engine.cs","src/Handlebars/HandlebarsException.cs","src/Handlebars/Opcodes.cs","src/Handlebars/Parser.cs","src/Handlebars/RuntimeUtils.cs","src/Handlebars/SafeString.cs","src/Handlebars/Template.cs"],".NET Handlebars Helpers":["src/Handlebars/Helpers/EachHelper.cs","src/Handlebars/Helpers/IfHelper.cs","src/Handlebars/Helpers/LogHelper.cs","src/Handlebars/Helpers/LookupHelper.cs","src/Handlebars/Helpers/WithHelper.cs"],".NET Handlebars Compatibility Layer":["src/Handlebars.Compat/Arguments.cs","src/Handlebars.Compat/BindingContext.cs","src/Handlebars.Compat/Context.cs","src/Handlebars.Compat/Delegates.cs","src/Handlebars.Compat/EncodedTextWriter.cs","src/Handlebars.Compat/Handlebars.cs","src/Handlebars.Compat/HandlebarsConfiguration.cs","src/Handlebars.Compat/HelperOptions.cs"],"Project Documentation":["AGENTS.md","ARCHITECTURE.md","CLAUDE.md","docs/01-architecture.md","docs/02-performance-analysis.md","docs/03-rewrite-vs-refactor.md","docs/04-code-generation.md","docs/05-work-plan.md","docs/06-implementation-plan.md","docs/07-tech-debt.md","docs/08-progress.md","docs/09-handover.md","docs/COMPAT.md","handlebars.js/FAQ.md","handlebars.js/README.md","handlebars.js/release-notes.md","handlebars.js/docs/compiler-api.md","handlebars.js/docs/decorators-api.md"],"Project Documentation — AGENTS.md":["AGENTS.md"],"Project Documentation — ARCHITECTURE.md":["ARCHITECTURE.md"],"Project Documentation — CLAUDE.md":["CLAUDE.md"],"Project Documentation — docs":["docs/01-architecture.md","docs/02-performance-analysis.md","docs/03-rewrite-vs-refactor.md","docs/04-code-generation.md","docs/05-work-plan.md","docs/06-implementation-plan.md","docs/07-tech-debt.md","docs/08-progress.md","docs/09-handover.md","docs/COMPAT.md"],"Project Documentation — handlebars.js":["handlebars.js/FAQ.md","handlebars.js/README.md","handlebars.js/release-notes.md"],"Project Documentation — handlebars.js-docs":["handlebars.js/docs/compiler-api.md","handlebars.js/docs/decorators-api.md"],"Other":["handlebars.js/components/bower.json","handlebars.js/components/component.json","handlebars.js/components/composer.json","handlebars.js/components/handlebars-source.gemspec","handlebars.js/components/handlebars.js.nuspec","handlebars.js/components/package.json","handlebars.js/eslint.config.js","handlebars.js/generate_golden.js","handlebars.js/package.json","handlebars.js/rspack.config.js","handlebars.js/vitest.config.js","handlebars.js/spec/artifacts/bom.handlebars","handlebars.js/spec/artifacts/empty.handlebars","handlebars.js/spec/artifacts/example_1.handlebars","handlebars.js/spec/artifacts/example_2.hbs","handlebars.js/spec/artifacts/known.helpers.handlebars","handlebars.js/spec/artifacts/non.default.extension.hbs","handlebars.js/spec/artifacts/partial.template.handlebars","handlebars.js/spec/ast.js","handlebars.js/spec/basic.js","handlebars.js/spec/blocks.js","handlebars.js/spec/builtins.js","handlebars.js/spec/compiler.js","handlebars.js/spec/data.js","handlebars.js/spec/expected/compiled.string.txt","handlebars.js/spec/expected/empty.namespace.js","handlebars.js/spec/expected/help.menu.txt","handlebars.js/spec/helpers.js","handlebars.js/spec/index.html","handlebars.js/spec/javascript-compiler.js","handlebars.js/spec/partials.js","handlebars.js/spec/precompiler.js","handlebars.js/spec/regressions.js","handlebars.js/spec/runtime.js","handlebars.js/spec/security.js","handlebars.js/spec/source-map.js","handlebars.js/spec/spec.js","handlebars.js/spec/strict.js","handlebars.js/spec/subexpressions.js","handlebars.js/spec/utils.js","handlebars.js/spec/whitespace-control.js","handlebars.js/tasks/publish-to-aws.js","handlebars.js/tasks/tests/README.md","handlebars.js/tasks/tests/cli.test.js","handlebars.js/tasks/tests/fake-s3.js","handlebars.js/tasks/tests/git.test.js","handlebars.js/tasks/tests/publish-to-aws.test.js","handlebars.js/tasks/util/git.js","handlebars.js/tasks/version.js","handlebars.js/test_fixtures/0.ast.json","handlebars.js/test_fixtures/0.hbs","handlebars.js/test_fixtures/1.ast.json","handlebars.js/test_fixtures/1.hbs","handlebars.js/test_fixtures/10.ast.json","handlebars.js/test_fixtures/10.hbs","handlebars.js/test_fixtures/11.ast.json","handlebars.js/test_fixtures/11.hbs","handlebars.js/test_fixtures/12.ast.json","handlebars.js/test_fixtures/12.hbs","handlebars.js/test_fixtures/13.ast.json","handlebars.js/test_fixtures/13.hbs","handlebars.js/test_fixtures/14.ast.json","handlebars.js/test_fixtures/14.hbs","handlebars.js/test_fixtures/15.ast.json","handlebars.js/test_fixtures/15.hbs","handlebars.js/test_fixtures/16.ast.json","handlebars.js/test_fixtures/16.hbs","handlebars.js/test_fixtures/17.ast.json","handlebars.js/test_fixtures/17.hbs","handlebars.js/test_fixtures/18.ast.json","handlebars.js/test_fixtures/18.hbs","handlebars.js/test_fixtures/19.ast.json","handlebars.js/test_fixtures/19.hbs","handlebars.js/test_fixtures/2.ast.json","handlebars.js/test_fixtures/2.hbs","handlebars.js/test_fixtures/20.ast.json","handlebars.js/test_fixtures/20.hbs","handlebars.js/test_fixtures/21.ast.json","handlebars.js/test_fixtures/21.hbs","handlebars.js/test_fixtures/22.ast.json","handlebars.js/test_fixtures/22.hbs","handlebars.js/test_fixtures/23.ast.json","handlebars.js/test_fixtures/23.hbs","handlebars.js/test_fixtures/24.ast.json","handlebars.js/test_fixtures/24.hbs","handlebars.js/test_fixtures/25.ast.json","handlebars.js/test_fixtures/25.hbs","handlebars.js/test_fixtures/26.ast.json","handlebars.js/test_fixtures/26.hbs","handlebars.js/test_fixtures/27.ast.json","handlebars.js/test_fixtures/27.hbs","handlebars.js/test_fixtures/28.ast.json","handlebars.js/test_fixtures/28.hbs","handlebars.js/test_fixtures/29.ast.json","handlebars.js/test_fixtures/29.hbs","handlebars.js/test_fixtures/3.ast.json","handlebars.js/test_fixtures/3.hbs","handlebars.js/test_fixtures/4.ast.json","handlebars.js/test_fixtures/4.hbs","handlebars.js/test_fixtures/5.ast.json","handlebars.js/test_fixtures/5.hbs","handlebars.js/test_fixtures/6.ast.json","handlebars.js/test_fixtures/6.hbs","handlebars.js/test_fixtures/7.ast.json","handlebars.js/test_fixtures/7.hbs","handlebars.js/test_fixtures/8.ast.json","handlebars.js/test_fixtures/8.hbs","handlebars.js/test_fixtures/9.ast.json","handlebars.js/test_fixtures/9.hbs","handlebars.js/test_fixtures/comp_0.hbs","handlebars.js/test_fixtures/comp_0.spec.json","handlebars.js/test_fixtures/comp_1.hbs","handlebars.js/test_fixtures/comp_1.spec.json","handlebars.js/test_fixtures/comp_2.hbs","handlebars.js/test_fixtures/comp_2.spec.json","handlebars.js/test_fixtures/comp_3.hbs","handlebars.js/test_fixtures/comp_3.spec.json","handlebars.js/test_fixtures/comp_4.hbs","handlebars.js/test_fixtures/comp_4.spec.json","handlebars.js/test_fixtures/comp_5.hbs","handlebars.js/test_fixtures/comp_5.spec.json","handlebars.js/test_fixtures/comp_6.hbs","handlebars.js/test_fixtures/comp_6.spec.json","handlebars.js/test_fixtures/comp_7.hbs","handlebars.js/test_fixtures/comp_7.spec.json","handlebars.js/test_fixtures/comp_8.hbs","handlebars.js/test_fixtures/comp_8.spec.json","handlebars.js/test_fixtures/comp_9.hbs","handlebars.js/test_fixtures/comp_9.spec.json","handlebars.js/tests/bench/compare.js","handlebars.js/tests/bench/perf.js","handlebars.js/tests/bench/report.js","handlebars.js/tests/bench/size.js","handlebars.js/tests/bench/templates.js","handlebars.js/tests/browser/README.md","handlebars.js/tests/browser/playwright.config.js","handlebars.js/tests/browser/tests/lib.spec.js","handlebars.js/tests/integration/README.md","handlebars.js/tests/integration/multi-nodejs-test/package.json","handlebars.js/tests/integration/multi-nodejs-test/precompile-test-template.txt.hbs","handlebars.js/tests/integration/multi-nodejs-test/run-handlebars.js","handlebars.js/tests/integration/multi-nodejs-test/test.sh","handlebars.js/tests/integration/rollup-test/package.json","handlebars.js/tests/integration/rollup-test/rollup.config.js","handlebars.js/tests/integration/rollup-test/src/index.js","handlebars.js/tests/integration/rollup-test/test.sh","handlebars.js/tests/integration/run-integration-tests.sh","handlebars.js/tests/integration/webpack-test/package.json","handlebars.js/tests/integration/webpack-test/src/handlebars-default-import-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-esm-import-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-loader-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-register-helper-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-runtime-test.js","handlebars.js/tests/integration/webpack-test/src/lib/assert.js","handlebars.js/tests/integration/webpack-test/src/test-template.handlebars","handlebars.js/tests/integration/webpack-test/test.sh","handlebars.js/tests/integration/webpack-test/webpack.config.js","handlebars.js/tests/print-script.js","handlebars.js/tests/rspack/rspack.test.js","handlebars.js/types/__typetests__/handlebars.tst.ts","handlebars.js/types/tsconfig.json","src/Handlebars.Compat/Handlebars.Compat.csproj","src/Handlebars.Test/AstSerializationTests.cs","src/Handlebars.Test/BasicTests.cs","src/Handlebars.Test/BlocksTests.cs","src/Handlebars.Test/BuiltinsTests.cs","src/Handlebars.Test/CompatTests.cs","src/Handlebars.Test/CompilerTests.cs","src/Handlebars.Test/ComplexRenderTests.cs","src/Handlebars.Test/DataTests.cs","src/Handlebars.Test/GoldenAstTests.cs","src/Handlebars.Test/GoldenRenderTests.cs","src/Handlebars.Test/Handlebars.Test.csproj","src/Handlebars.Test/HelperTests.cs","src/Handlebars.Test/ParserTests.cs","src/Handlebars.Test/PartialTests.cs","src/Handlebars.Test/RegressionTests.cs","src/Handlebars.Test/RenderingTests.cs","src/Handlebars.Test/StrictTests.cs","src/Handlebars.Test/SubExpressionTests.cs","src/Handlebars.Test/TestHelper.cs","src/Handlebars.Test/WhitespaceTests.cs","src/Handlebars.TestApp/Handlebars.TestApp.csproj","src/Handlebars.TestApp/Program.cs","src/Handlebars.TestApp/templates/advanced.hbs","src/Handlebars.TestApp/templates/advanced.json","src/Handlebars.TestApp/templates/hello.hbs","src/Handlebars.TestApp/templates/hello.json","src/Handlebars.slnx","src/Handlebars/Handlebars.csproj","test/golden/parser/0.ast.json","test/golden/parser/0.hbs","test/golden/parser/1.ast.json","test/golden/parser/1.hbs","test/golden/parser/10.ast.json","test/golden/parser/10.hbs","test/golden/parser/11.ast.json","test/golden/parser/11.hbs","test/golden/parser/12.ast.json","test/golden/parser/12.hbs","test/golden/parser/13.ast.json","test/golden/parser/13.hbs","test/golden/parser/14.ast.json","test/golden/parser/14.hbs","test/golden/parser/15.ast.json","test/golden/parser/15.hbs","test/golden/parser/16.ast.json","test/golden/parser/16.hbs","test/golden/parser/17.ast.json","test/golden/parser/17.hbs","test/golden/parser/18.ast.json","test/golden/parser/18.hbs","test/golden/parser/19.ast.json","test/golden/parser/19.hbs","test/golden/parser/2.ast.json","test/golden/parser/2.hbs","test/golden/parser/20.ast.json","test/golden/parser/20.hbs","test/golden/parser/21.ast.json","test/golden/parser/21.hbs","test/golden/parser/22.ast.json","test/golden/parser/22.hbs","test/golden/parser/23.ast.json","test/golden/parser/23.hbs","test/golden/parser/24.ast.json","test/golden/parser/24.hbs","test/golden/parser/25.ast.json","test/golden/parser/25.hbs","test/golden/parser/26.ast.json","test/golden/parser/26.hbs","test/golden/parser/27.ast.json","test/golden/parser/27.hbs","test/golden/parser/28.ast.json","test/golden/parser/28.hbs","test/golden/parser/29.ast.json","test/golden/parser/29.hbs","test/golden/parser/3.ast.json","test/golden/parser/3.hbs","test/golden/parser/4.ast.json","test/golden/parser/4.hbs","test/golden/parser/5.ast.json","test/golden/parser/5.hbs","test/golden/parser/6.ast.json","test/golden/parser/6.hbs","test/golden/parser/7.ast.json","test/golden/parser/7.hbs","test/golden/parser/8.ast.json","test/golden/parser/8.hbs","test/golden/parser/9.ast.json","test/golden/parser/9.hbs"],"Other — components":["handlebars.js/components/bower.json","handlebars.js/components/component.json","handlebars.js/components/composer.json","handlebars.js/components/handlebars-source.gemspec","handlebars.js/components/handlebars.js.nuspec","handlebars.js/components/package.json"],"Other — handlebars.js":["handlebars.js/eslint.config.js","handlebars.js/generate_golden.js","handlebars.js/package.json","handlebars.js/rspack.config.js","handlebars.js/vitest.config.js"],"Other — spec":["handlebars.js/spec/artifacts/bom.handlebars","handlebars.js/spec/artifacts/empty.handlebars","handlebars.js/spec/artifacts/example_1.handlebars","handlebars.js/spec/artifacts/example_2.hbs","handlebars.js/spec/artifacts/known.helpers.handlebars","handlebars.js/spec/artifacts/non.default.extension.hbs","handlebars.js/spec/artifacts/partial.template.handlebars","handlebars.js/spec/ast.js","handlebars.js/spec/basic.js","handlebars.js/spec/blocks.js","handlebars.js/spec/builtins.js","handlebars.js/spec/compiler.js","handlebars.js/spec/data.js","handlebars.js/spec/expected/compiled.string.txt","handlebars.js/spec/expected/empty.namespace.js","handlebars.js/spec/expected/help.menu.txt","handlebars.js/spec/helpers.js","handlebars.js/spec/index.html","handlebars.js/spec/javascript-compiler.js","handlebars.js/spec/partials.js","handlebars.js/spec/precompiler.js","handlebars.js/spec/regressions.js","handlebars.js/spec/runtime.js","handlebars.js/spec/security.js","handlebars.js/spec/source-map.js","handlebars.js/spec/spec.js","handlebars.js/spec/strict.js","handlebars.js/spec/subexpressions.js","handlebars.js/spec/utils.js","handlebars.js/spec/whitespace-control.js"],"Other — tasks":["handlebars.js/tasks/publish-to-aws.js","handlebars.js/tasks/tests/README.md","handlebars.js/tasks/tests/cli.test.js","handlebars.js/tasks/tests/fake-s3.js","handlebars.js/tasks/tests/git.test.js","handlebars.js/tasks/tests/publish-to-aws.test.js","handlebars.js/tasks/util/git.js","handlebars.js/tasks/version.js"],"Other — test_fixtures":["handlebars.js/test_fixtures/0.ast.json","handlebars.js/test_fixtures/0.hbs","handlebars.js/test_fixtures/1.ast.json","handlebars.js/test_fixtures/1.hbs","handlebars.js/test_fixtures/10.ast.json","handlebars.js/test_fixtures/10.hbs","handlebars.js/test_fixtures/11.ast.json","handlebars.js/test_fixtures/11.hbs","handlebars.js/test_fixtures/12.ast.json","handlebars.js/test_fixtures/12.hbs","handlebars.js/test_fixtures/13.ast.json","handlebars.js/test_fixtures/13.hbs","handlebars.js/test_fixtures/14.ast.json","handlebars.js/test_fixtures/14.hbs","handlebars.js/test_fixtures/15.ast.json","handlebars.js/test_fixtures/15.hbs","handlebars.js/test_fixtures/16.ast.json","handlebars.js/test_fixtures/16.hbs","handlebars.js/test_fixtures/17.ast.json","handlebars.js/test_fixtures/17.hbs","handlebars.js/test_fixtures/18.ast.json","handlebars.js/test_fixtures/18.hbs","handlebars.js/test_fixtures/19.ast.json","handlebars.js/test_fixtures/19.hbs","handlebars.js/test_fixtures/2.ast.json","handlebars.js/test_fixtures/2.hbs","handlebars.js/test_fixtures/20.ast.json","handlebars.js/test_fixtures/20.hbs","handlebars.js/test_fixtures/21.ast.json","handlebars.js/test_fixtures/21.hbs","handlebars.js/test_fixtures/22.ast.json","handlebars.js/test_fixtures/22.hbs","handlebars.js/test_fixtures/23.ast.json","handlebars.js/test_fixtures/23.hbs","handlebars.js/test_fixtures/24.ast.json","handlebars.js/test_fixtures/24.hbs","handlebars.js/test_fixtures/25.ast.json","handlebars.js/test_fixtures/25.hbs","handlebars.js/test_fixtures/26.ast.json","handlebars.js/test_fixtures/26.hbs","handlebars.js/test_fixtures/27.ast.json","handlebars.js/test_fixtures/27.hbs","handlebars.js/test_fixtures/28.ast.json","handlebars.js/test_fixtures/28.hbs","handlebars.js/test_fixtures/29.ast.json","handlebars.js/test_fixtures/29.hbs","handlebars.js/test_fixtures/3.ast.json","handlebars.js/test_fixtures/3.hbs","handlebars.js/test_fixtures/4.ast.json","handlebars.js/test_fixtures/4.hbs","handlebars.js/test_fixtures/5.ast.json","handlebars.js/test_fixtures/5.hbs","handlebars.js/test_fixtures/6.ast.json","handlebars.js/test_fixtures/6.hbs","handlebars.js/test_fixtures/7.ast.json","handlebars.js/test_fixtures/7.hbs","handlebars.js/test_fixtures/8.ast.json","handlebars.js/test_fixtures/8.hbs","handlebars.js/test_fixtures/9.ast.json","handlebars.js/test_fixtures/9.hbs","handlebars.js/test_fixtures/comp_0.hbs","handlebars.js/test_fixtures/comp_0.spec.json","handlebars.js/test_fixtures/comp_1.hbs","handlebars.js/test_fixtures/comp_1.spec.json","handlebars.js/test_fixtures/comp_2.hbs","handlebars.js/test_fixtures/comp_2.spec.json","handlebars.js/test_fixtures/comp_3.hbs","handlebars.js/test_fixtures/comp_3.spec.json","handlebars.js/test_fixtures/comp_4.hbs","handlebars.js/test_fixtures/comp_4.spec.json","handlebars.js/test_fixtures/comp_5.hbs","handlebars.js/test_fixtures/comp_5.spec.json","handlebars.js/test_fixtures/comp_6.hbs","handlebars.js/test_fixtures/comp_6.spec.json","handlebars.js/test_fixtures/comp_7.hbs","handlebars.js/test_fixtures/comp_7.spec.json","handlebars.js/test_fixtures/comp_8.hbs","handlebars.js/test_fixtures/comp_8.spec.json","handlebars.js/test_fixtures/comp_9.hbs","handlebars.js/test_fixtures/comp_9.spec.json"],"Other — tests":["handlebars.js/tests/bench/compare.js","handlebars.js/tests/bench/perf.js","handlebars.js/tests/bench/report.js","handlebars.js/tests/bench/size.js","handlebars.js/tests/bench/templates.js","handlebars.js/tests/browser/README.md","handlebars.js/tests/browser/playwright.config.js","handlebars.js/tests/browser/tests/lib.spec.js","handlebars.js/tests/integration/README.md","handlebars.js/tests/integration/multi-nodejs-test/package.json","handlebars.js/tests/integration/multi-nodejs-test/precompile-test-template.txt.hbs","handlebars.js/tests/integration/multi-nodejs-test/run-handlebars.js","handlebars.js/tests/integration/multi-nodejs-test/test.sh","handlebars.js/tests/integration/rollup-test/package.json","handlebars.js/tests/integration/rollup-test/rollup.config.js","handlebars.js/tests/integration/rollup-test/src/index.js","handlebars.js/tests/integration/rollup-test/test.sh","handlebars.js/tests/integration/run-integration-tests.sh","handlebars.js/tests/integration/webpack-test/package.json","handlebars.js/tests/integration/webpack-test/src/handlebars-default-import-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-esm-import-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-loader-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-register-helper-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-runtime-test.js","handlebars.js/tests/integration/webpack-test/src/lib/assert.js","handlebars.js/tests/integration/webpack-test/src/test-template.handlebars","handlebars.js/tests/integration/webpack-test/test.sh","handlebars.js/tests/integration/webpack-test/webpack.config.js","handlebars.js/tests/print-script.js","handlebars.js/tests/rspack/rspack.test.js"],"Other — types":["handlebars.js/types/__typetests__/handlebars.tst.ts","handlebars.js/types/tsconfig.json"],"Other — Handlebars.Compat":["src/Handlebars.Compat/Handlebars.Compat.csproj"],"Other — Handlebars.Test":["src/Handlebars.Test/AstSerializationTests.cs","src/Handlebars.Test/BasicTests.cs","src/Handlebars.Test/BlocksTests.cs","src/Handlebars.Test/BuiltinsTests.cs","src/Handlebars.Test/CompatTests.cs","src/Handlebars.Test/CompilerTests.cs","src/Handlebars.Test/ComplexRenderTests.cs","src/Handlebars.Test/DataTests.cs","src/Handlebars.Test/GoldenAstTests.cs","src/Handlebars.Test/GoldenRenderTests.cs","src/Handlebars.Test/Handlebars.Test.csproj","src/Handlebars.Test/HelperTests.cs","src/Handlebars.Test/ParserTests.cs","src/Handlebars.Test/PartialTests.cs","src/Handlebars.Test/RegressionTests.cs","src/Handlebars.Test/RenderingTests.cs","src/Handlebars.Test/StrictTests.cs","src/Handlebars.Test/SubExpressionTests.cs","src/Handlebars.Test/TestHelper.cs","src/Handlebars.Test/WhitespaceTests.cs"],"Other — Handlebars.TestApp":["src/Handlebars.TestApp/Handlebars.TestApp.csproj","src/Handlebars.TestApp/Program.cs","src/Handlebars.TestApp/templates/advanced.hbs","src/Handlebars.TestApp/templates/advanced.json","src/Handlebars.TestApp/templates/hello.hbs","src/Handlebars.TestApp/templates/hello.json"],"Other — src":["src/Handlebars.slnx"],"Other — Handlebars":["src/Handlebars/Handlebars.csproj"],"Other — golden":["test/golden/parser/0.ast.json","test/golden/parser/0.hbs","test/golden/parser/1.ast.json","test/golden/parser/1.hbs","test/golden/parser/10.ast.json","test/golden/parser/10.hbs","test/golden/parser/11.ast.json","test/golden/parser/11.hbs","test/golden/parser/12.ast.json","test/golden/parser/12.hbs","test/golden/parser/13.ast.json","test/golden/parser/13.hbs","test/golden/parser/14.ast.json","test/golden/parser/14.hbs","test/golden/parser/15.ast.json","test/golden/parser/15.hbs","test/golden/parser/16.ast.json","test/golden/parser/16.hbs","test/golden/parser/17.ast.json","test/golden/parser/17.hbs","test/golden/parser/18.ast.json","test/golden/parser/18.hbs","test/golden/parser/19.ast.json","test/golden/parser/19.hbs","test/golden/parser/2.ast.json","test/golden/parser/2.hbs","test/golden/parser/20.ast.json","test/golden/parser/20.hbs","test/golden/parser/21.ast.json","test/golden/parser/21.hbs","test/golden/parser/22.ast.json","test/golden/parser/22.hbs","test/golden/parser/23.ast.json","test/golden/parser/23.hbs","test/golden/parser/24.ast.json","test/golden/parser/24.hbs","test/golden/parser/25.ast.json","test/golden/parser/25.hbs","test/golden/parser/26.ast.json","test/golden/parser/26.hbs","test/golden/parser/27.ast.json","test/golden/parser/27.hbs","test/golden/parser/28.ast.json","test/golden/parser/28.hbs","test/golden/parser/29.ast.json","test/golden/parser/29.hbs","test/golden/parser/3.ast.json","test/golden/parser/3.hbs","test/golden/parser/4.ast.json","test/golden/parser/4.hbs","test/golden/parser/5.ast.json","test/golden/parser/5.hbs","test/golden/parser/6.ast.json","test/golden/parser/6.hbs","test/golden/parser/7.ast.json","test/golden/parser/7.hbs","test/golden/parser/8.ast.json","test/golden/parser/8.hbs","test/golden/parser/9.ast.json","test/golden/parser/9.hbs"]},"moduleTree":[{"name":"JavaScript Handlebars Core","slug":"javascript-handlebars-core","files":["handlebars.js/lib/handlebars.js","handlebars.js/lib/handlebars.runtime.js","handlebars.js/lib/handlebars/base.js","handlebars.js/lib/handlebars/runtime.js","handlebars.js/lib/handlebars/utils.js","handlebars.js/lib/handlebars/safe-string.js","handlebars.js/lib/handlebars/logger.js","handlebars.js/lib/handlebars/no-conflict.js","handlebars.js/lib/handlebars/internal/proto-access.js","handlebars.js/lib/handlebars/internal/wrapHelper.js","handlebars.js/lib/index.js","handlebars.js/runtime.js"]},{"name":"JavaScript Handlebars Compiler","slug":"javascript-handlebars-compiler","files":["handlebars.js/lib/handlebars/compiler/ast.js","handlebars.js/lib/handlebars/compiler/code-gen.js","handlebars.js/lib/handlebars/compiler/compiler.js","handlebars.js/lib/handlebars/compiler/javascript-compiler.js","handlebars.js/lib/handlebars/compiler/source-node.browser.js","handlebars.js/lib/handlebars/compiler/source-node.node.js"]},{"name":"JavaScript Handlebars Helpers & Decorators","slug":"javascript-handlebars-helpers-decorators","files":["handlebars.js/lib/handlebars/helpers.js","handlebars.js/lib/handlebars/helpers/block-helper-missing.js","handlebars.js/lib/handlebars/helpers/each.js","handlebars.js/lib/handlebars/helpers/helper-missing.js","handlebars.js/lib/handlebars/helpers/if.js","handlebars.js/lib/handlebars/helpers/log.js","handlebars.js/lib/handlebars/helpers/lookup.js","handlebars.js/lib/handlebars/helpers/with.js","handlebars.js/lib/handlebars/decorators.js","handlebars.js/lib/handlebars/decorators/inline.js"]},{"name":"JavaScript Handlebars CLI & Packaging","slug":"javascript-handlebars-cli-packaging","files":["handlebars.js/lib/precompiler.js","handlebars.js/components/lib/handlebars/source.rb"]},{"name":".NET Handlebars Core","slug":"net-handlebars-core","files":["src/Handlebars/Ast.cs","src/Handlebars/BytecodeInterpreter.cs","src/Handlebars/CompileOptions.cs","src/Handlebars/Compiler.cs","src/Handlebars/Engine.cs","src/Handlebars/HandlebarsException.cs","src/Handlebars/Opcodes.cs","src/Handlebars/Parser.cs","src/Handlebars/RuntimeUtils.cs","src/Handlebars/SafeString.cs","src/Handlebars/Template.cs"]},{"name":".NET Handlebars Helpers","slug":"net-handlebars-helpers","files":["src/Handlebars/Helpers/EachHelper.cs","src/Handlebars/Helpers/IfHelper.cs","src/Handlebars/Helpers/LogHelper.cs","src/Handlebars/Helpers/LookupHelper.cs","src/Handlebars/Helpers/WithHelper.cs"]},{"name":".NET Handlebars Compatibility Layer","slug":"net-handlebars-compatibility-layer","files":["src/Handlebars.Compat/Arguments.cs","src/Handlebars.Compat/BindingContext.cs","src/Handlebars.Compat/Context.cs","src/Handlebars.Compat/Delegates.cs","src/Handlebars.Compat/EncodedTextWriter.cs","src/Handlebars.Compat/Handlebars.cs","src/Handlebars.Compat/HandlebarsConfiguration.cs","src/Handlebars.Compat/HelperOptions.cs"]},{"name":"Project Documentation","slug":"project-documentation","files":[],"children":[{"name":"Project Documentation — AGENTS.md","slug":"project-documentation-agents-md","files":["AGENTS.md"]},{"name":"Project Documentation — ARCHITECTURE.md","slug":"project-documentation-architecture-md","files":["ARCHITECTURE.md"]},{"name":"Project Documentation — CLAUDE.md","slug":"project-documentation-claude-md","files":["CLAUDE.md"]},{"name":"Project Documentation — docs","slug":"project-documentation-docs","files":["docs/01-architecture.md","docs/02-performance-analysis.md","docs/03-rewrite-vs-refactor.md","docs/04-code-generation.md","docs/05-work-plan.md","docs/06-implementation-plan.md","docs/07-tech-debt.md","docs/08-progress.md","docs/09-handover.md","docs/COMPAT.md"]},{"name":"Project Documentation — handlebars.js","slug":"project-documentation-handlebars-js","files":["handlebars.js/FAQ.md","handlebars.js/README.md","handlebars.js/release-notes.md"]},{"name":"Project Documentation — handlebars.js-docs","slug":"project-documentation-handlebars-js-docs","files":["handlebars.js/docs/compiler-api.md","handlebars.js/docs/decorators-api.md"]}]},{"name":"Other","slug":"other","files":[],"children":[{"name":"Other — components","slug":"other-components","files":["handlebars.js/components/bower.json","handlebars.js/components/component.json","handlebars.js/components/composer.json","handlebars.js/components/handlebars-source.gemspec","handlebars.js/components/handlebars.js.nuspec","handlebars.js/components/package.json"]},{"name":"Other — handlebars.js","slug":"other-handlebars-js","files":["handlebars.js/eslint.config.js","handlebars.js/generate_golden.js","handlebars.js/package.json","handlebars.js/rspack.config.js","handlebars.js/vitest.config.js"]},{"name":"Other — spec","slug":"other-spec","files":["handlebars.js/spec/artifacts/bom.handlebars","handlebars.js/spec/artifacts/empty.handlebars","handlebars.js/spec/artifacts/example_1.handlebars","handlebars.js/spec/artifacts/example_2.hbs","handlebars.js/spec/artifacts/known.helpers.handlebars","handlebars.js/spec/artifacts/non.default.extension.hbs","handlebars.js/spec/artifacts/partial.template.handlebars","handlebars.js/spec/ast.js","handlebars.js/spec/basic.js","handlebars.js/spec/blocks.js","handlebars.js/spec/builtins.js","handlebars.js/spec/compiler.js","handlebars.js/spec/data.js","handlebars.js/spec/expected/compiled.string.txt","handlebars.js/spec/expected/empty.namespace.js","handlebars.js/spec/expected/help.menu.txt","handlebars.js/spec/helpers.js","handlebars.js/spec/index.html","handlebars.js/spec/javascript-compiler.js","handlebars.js/spec/partials.js","handlebars.js/spec/precompiler.js","handlebars.js/spec/regressions.js","handlebars.js/spec/runtime.js","handlebars.js/spec/security.js","handlebars.js/spec/source-map.js","handlebars.js/spec/spec.js","handlebars.js/spec/strict.js","handlebars.js/spec/subexpressions.js","handlebars.js/spec/utils.js","handlebars.js/spec/whitespace-control.js"]},{"name":"Other — tasks","slug":"other-tasks","files":["handlebars.js/tasks/publish-to-aws.js","handlebars.js/tasks/tests/README.md","handlebars.js/tasks/tests/cli.test.js","handlebars.js/tasks/tests/fake-s3.js","handlebars.js/tasks/tests/git.test.js","handlebars.js/tasks/tests/publish-to-aws.test.js","handlebars.js/tasks/util/git.js","handlebars.js/tasks/version.js"]},{"name":"Other — test_fixtures","slug":"other-test-fixtures","files":["handlebars.js/test_fixtures/0.ast.json","handlebars.js/test_fixtures/0.hbs","handlebars.js/test_fixtures/1.ast.json","handlebars.js/test_fixtures/1.hbs","handlebars.js/test_fixtures/10.ast.json","handlebars.js/test_fixtures/10.hbs","handlebars.js/test_fixtures/11.ast.json","handlebars.js/test_fixtures/11.hbs","handlebars.js/test_fixtures/12.ast.json","handlebars.js/test_fixtures/12.hbs","handlebars.js/test_fixtures/13.ast.json","handlebars.js/test_fixtures/13.hbs","handlebars.js/test_fixtures/14.ast.json","handlebars.js/test_fixtures/14.hbs","handlebars.js/test_fixtures/15.ast.json","handlebars.js/test_fixtures/15.hbs","handlebars.js/test_fixtures/16.ast.json","handlebars.js/test_fixtures/16.hbs","handlebars.js/test_fixtures/17.ast.json","handlebars.js/test_fixtures/17.hbs","handlebars.js/test_fixtures/18.ast.json","handlebars.js/test_fixtures/18.hbs","handlebars.js/test_fixtures/19.ast.json","handlebars.js/test_fixtures/19.hbs","handlebars.js/test_fixtures/2.ast.json","handlebars.js/test_fixtures/2.hbs","handlebars.js/test_fixtures/20.ast.json","handlebars.js/test_fixtures/20.hbs","handlebars.js/test_fixtures/21.ast.json","handlebars.js/test_fixtures/21.hbs","handlebars.js/test_fixtures/22.ast.json","handlebars.js/test_fixtures/22.hbs","handlebars.js/test_fixtures/23.ast.json","handlebars.js/test_fixtures/23.hbs","handlebars.js/test_fixtures/24.ast.json","handlebars.js/test_fixtures/24.hbs","handlebars.js/test_fixtures/25.ast.json","handlebars.js/test_fixtures/25.hbs","handlebars.js/test_fixtures/26.ast.json","handlebars.js/test_fixtures/26.hbs","handlebars.js/test_fixtures/27.ast.json","handlebars.js/test_fixtures/27.hbs","handlebars.js/test_fixtures/28.ast.json","handlebars.js/test_fixtures/28.hbs","handlebars.js/test_fixtures/29.ast.json","handlebars.js/test_fixtures/29.hbs","handlebars.js/test_fixtures/3.ast.json","handlebars.js/test_fixtures/3.hbs","handlebars.js/test_fixtures/4.ast.json","handlebars.js/test_fixtures/4.hbs","handlebars.js/test_fixtures/5.ast.json","handlebars.js/test_fixtures/5.hbs","handlebars.js/test_fixtures/6.ast.json","handlebars.js/test_fixtures/6.hbs","handlebars.js/test_fixtures/7.ast.json","handlebars.js/test_fixtures/7.hbs","handlebars.js/test_fixtures/8.ast.json","handlebars.js/test_fixtures/8.hbs","handlebars.js/test_fixtures/9.ast.json","handlebars.js/test_fixtures/9.hbs","handlebars.js/test_fixtures/comp_0.hbs","handlebars.js/test_fixtures/comp_0.spec.json","handlebars.js/test_fixtures/comp_1.hbs","handlebars.js/test_fixtures/comp_1.spec.json","handlebars.js/test_fixtures/comp_2.hbs","handlebars.js/test_fixtures/comp_2.spec.json","handlebars.js/test_fixtures/comp_3.hbs","handlebars.js/test_fixtures/comp_3.spec.json","handlebars.js/test_fixtures/comp_4.hbs","handlebars.js/test_fixtures/comp_4.spec.json","handlebars.js/test_fixtures/comp_5.hbs","handlebars.js/test_fixtures/comp_5.spec.json","handlebars.js/test_fixtures/comp_6.hbs","handlebars.js/test_fixtures/comp_6.spec.json","handlebars.js/test_fixtures/comp_7.hbs","handlebars.js/test_fixtures/comp_7.spec.json","handlebars.js/test_fixtures/comp_8.hbs","handlebars.js/test_fixtures/comp_8.spec.json","handlebars.js/test_fixtures/comp_9.hbs","handlebars.js/test_fixtures/comp_9.spec.json"]},{"name":"Other — tests","slug":"other-tests","files":["handlebars.js/tests/bench/compare.js","handlebars.js/tests/bench/perf.js","handlebars.js/tests/bench/report.js","handlebars.js/tests/bench/size.js","handlebars.js/tests/bench/templates.js","handlebars.js/tests/browser/README.md","handlebars.js/tests/browser/playwright.config.js","handlebars.js/tests/browser/tests/lib.spec.js","handlebars.js/tests/integration/README.md","handlebars.js/tests/integration/multi-nodejs-test/package.json","handlebars.js/tests/integration/multi-nodejs-test/precompile-test-template.txt.hbs","handlebars.js/tests/integration/multi-nodejs-test/run-handlebars.js","handlebars.js/tests/integration/multi-nodejs-test/test.sh","handlebars.js/tests/integration/rollup-test/package.json","handlebars.js/tests/integration/rollup-test/rollup.config.js","handlebars.js/tests/integration/rollup-test/src/index.js","handlebars.js/tests/integration/rollup-test/test.sh","handlebars.js/tests/integration/run-integration-tests.sh","handlebars.js/tests/integration/webpack-test/package.json","handlebars.js/tests/integration/webpack-test/src/handlebars-default-import-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-esm-import-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-loader-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-register-helper-test.js","handlebars.js/tests/integration/webpack-test/src/handlebars-runtime-test.js","handlebars.js/tests/integration/webpack-test/src/lib/assert.js","handlebars.js/tests/integration/webpack-test/src/test-template.handlebars","handlebars.js/tests/integration/webpack-test/test.sh","handlebars.js/tests/integration/webpack-test/webpack.config.js","handlebars.js/tests/print-script.js","handlebars.js/tests/rspack/rspack.test.js"]},{"name":"Other — types","slug":"other-types","files":["handlebars.js/types/__typetests__/handlebars.tst.ts","handlebars.js/types/tsconfig.json"]},{"name":"Other — Handlebars.Compat","slug":"other-handlebars-compat","files":["src/Handlebars.Compat/Handlebars.Compat.csproj"]},{"name":"Other — Handlebars.Test","slug":"other-handlebars-test","files":["src/Handlebars.Test/AstSerializationTests.cs","src/Handlebars.Test/BasicTests.cs","src/Handlebars.Test/BlocksTests.cs","src/Handlebars.Test/BuiltinsTests.cs","src/Handlebars.Test/CompatTests.cs","src/Handlebars.Test/CompilerTests.cs","src/Handlebars.Test/ComplexRenderTests.cs","src/Handlebars.Test/DataTests.cs","src/Handlebars.Test/GoldenAstTests.cs","src/Handlebars.Test/GoldenRenderTests.cs","src/Handlebars.Test/Handlebars.Test.csproj","src/Handlebars.Test/HelperTests.cs","src/Handlebars.Test/ParserTests.cs","src/Handlebars.Test/PartialTests.cs","src/Handlebars.Test/RegressionTests.cs","src/Handlebars.Test/RenderingTests.cs","src/Handlebars.Test/StrictTests.cs","src/Handlebars.Test/SubExpressionTests.cs","src/Handlebars.Test/TestHelper.cs","src/Handlebars.Test/WhitespaceTests.cs"]},{"name":"Other — Handlebars.TestApp","slug":"other-handlebars-testapp","files":["src/Handlebars.TestApp/Handlebars.TestApp.csproj","src/Handlebars.TestApp/Program.cs","src/Handlebars.TestApp/templates/advanced.hbs","src/Handlebars.TestApp/templates/advanced.json","src/Handlebars.TestApp/templates/hello.hbs","src/Handlebars.TestApp/templates/hello.json"]},{"name":"Other — src","slug":"other-src","files":["src/Handlebars.slnx"]},{"name":"Other — Handlebars","slug":"other-handlebars","files":["src/Handlebars/Handlebars.csproj"]},{"name":"Other — golden","slug":"other-golden","files":["test/golden/parser/0.ast.json","test/golden/parser/0.hbs","test/golden/parser/1.ast.json","test/golden/parser/1.hbs","test/golden/parser/10.ast.json","test/golden/parser/10.hbs","test/golden/parser/11.ast.json","test/golden/parser/11.hbs","test/golden/parser/12.ast.json","test/golden/parser/12.hbs","test/golden/parser/13.ast.json","test/golden/parser/13.hbs","test/golden/parser/14.ast.json","test/golden/parser/14.hbs","test/golden/parser/15.ast.json","test/golden/parser/15.hbs","test/golden/parser/16.ast.json","test/golden/parser/16.hbs","test/golden/parser/17.ast.json","test/golden/parser/17.hbs","test/golden/parser/18.ast.json","test/golden/parser/18.hbs","test/golden/parser/19.ast.json","test/golden/parser/19.hbs","test/golden/parser/2.ast.json","test/golden/parser/2.hbs","test/golden/parser/20.ast.json","test/golden/parser/20.hbs","test/golden/parser/21.ast.json","test/golden/parser/21.hbs","test/golden/parser/22.ast.json","test/golden/parser/22.hbs","test/golden/parser/23.ast.json","test/golden/parser/23.hbs","test/golden/parser/24.ast.json","test/golden/parser/24.hbs","test/golden/parser/25.ast.json","test/golden/parser/25.hbs","test/golden/parser/26.ast.json","test/golden/parser/26.hbs","test/golden/parser/27.ast.json","test/golden/parser/27.hbs","test/golden/parser/28.ast.json","test/golden/parser/28.hbs","test/golden/parser/29.ast.json","test/golden/parser/29.hbs","test/golden/parser/3.ast.json","test/golden/parser/3.hbs","test/golden/parser/4.ast.json","test/golden/parser/4.hbs","test/golden/parser/5.ast.json","test/golden/parser/5.hbs","test/golden/parser/6.ast.json","test/golden/parser/6.hbs","test/golden/parser/7.ast.json","test/golden/parser/7.hbs","test/golden/parser/8.ast.json","test/golden/parser/8.hbs","test/golden/parser/9.ast.json","test/golden/parser/9.hbs"]}]}]};
(function() {
var activePage = 'overview';
document.addEventListener('DOMContentLoaded', function() {
mermaid.initialize({ startOnLoad: false, theme: 'neutral', securityLevel: 'loose' });
renderMeta();
renderNav();
document.getElementById('menu-toggle').addEventListener('click', function() {
document.getElementById('sidebar').classList.toggle('open');
});
if (location.hash && location.hash.length > 1) {
activePage = decodeURIComponent(location.hash.slice(1));
}
navigateTo(activePage);
});
function renderMeta() {
if (!META) return;
var el = document.getElementById('meta-info');
var parts = [];
if (META.generatedAt) {
parts.push(new Date(META.generatedAt).toLocaleDateString());
}
if (META.model) parts.push(META.model);
if (META.fromCommit) parts.push(META.fromCommit.slice(0, 8));
el.textContent = parts.join(' \u00b7 ');
}
function renderNav() {
var container = document.getElementById('nav-tree');
var html = '<div class="nav-section">';
html += '<a class="nav-item overview" data-page="overview" href="#overview">Overview</a>';
html += '</div>';
if (TREE.length > 0) {
html += '<div class="nav-group-label">Modules</div>';
html += buildNavTree(TREE);
}
container.innerHTML = html;
container.addEventListener('click', function(e) {
var target = e.target;
while (target && !target.dataset.page) { target = target.parentElement; }
if (target && target.dataset.page) {
e.preventDefault();
navigateTo(target.dataset.page);
}
});
}
function buildNavTree(nodes) {
var html = '';
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
html += '<div class="nav-section">';
html += '<a class="nav-item" data-page="' + escH(node.slug) + '" href="#' + encodeURIComponent(node.slug) + '">' + escH(node.name) + '</a>';
if (node.children && node.children.length > 0) {
html += '<div class="nav-children">' + buildNavTree(node.children) + '</div>';
}
html += '</div>';
}
return html;
}
function escH(s) {
var d = document.createElement('div');
d.textContent = s;
return d.innerHTML;
}
function navigateTo(page) {
activePage = page;
location.hash = encodeURIComponent(page);
var items = document.querySelectorAll('.nav-item');
for (var i = 0; i < items.length; i++) {
if (items[i].dataset.page === page) {
items[i].classList.add('active');
} else {
items[i].classList.remove('active');
}
}
var contentEl = document.getElementById('content');
var md = PAGES[page];
if (!md) {
contentEl.innerHTML = '<div class="empty-state"><h2>Page not found</h2><p>' + escH(page) + '.md does not exist.</p></div>';
return;
}
contentEl.innerHTML = marked.parse(md);
// Rewrite .md links to hash navigation
var links = contentEl.querySelectorAll('a[href]');
for (var i = 0; i < links.length; i++) {
var href = links[i].getAttribute('href');
if (href && href.endsWith('.md') && href.indexOf('://') === -1) {
var slug = href.replace(/\.md$/, '');
links[i].setAttribute('href', '#' + encodeURIComponent(slug));
(function(s) {
links[i].addEventListener('click', function(e) {
e.preventDefault();
navigateTo(s);
});
})(slug);
}
}
// Convert mermaid code blocks into mermaid divs
var mermaidBlocks = contentEl.querySelectorAll('pre code.language-mermaid');
for (var i = 0; i < mermaidBlocks.length; i++) {
var pre = mermaidBlocks[i].parentElement;
var div = document.createElement('div');
div.className = 'mermaid';
div.textContent = mermaidBlocks[i].textContent;
pre.parentNode.replaceChild(div, pre);
}
try { mermaid.run({ querySelector: '.mermaid' }); } catch(e) {}
window.scrollTo(0, 0);
document.getElementById('sidebar').classList.remove('open');
}
})();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment