Skip to content

feat: add VaultLoader for reusable Nunjucks templates in TEMPLATE renderer#199

Open
victoraraujo105 wants to merge 4 commits intoh-sphere:mainfrom
victor-software-house:feat/vault-template-loader-v2
Open

feat: add VaultLoader for reusable Nunjucks templates in TEMPLATE renderer#199
victoraraujo105 wants to merge 4 commits intoh-sphere:mainfrom
victor-software-house:feat/vault-template-loader-v2

Conversation

@victoraraujo105
Copy link
Copy Markdown

Summary

Add a custom Nunjucks loader (VaultLoader) that enables {% include %} and {% from ... import %} directives in the TEMPLATE renderer, allowing users to define reusable templates in .njk files within their vault.

Depends on: #198 (Handlebars → Nunjucks migration). This PR should be reviewed after #198 is merged, or reviewed together as a stacked pair.

Motivation

Even with the Nunjucks migration (#198), each TEMPLATE code block must contain its full template inline. Users who have multiple queries with similar table layouts must duplicate the entire template in every code block.

With this change, users can create .njk files in their vault and reference them:

```sqlseal
TEMPLATE
{% include "_templates/task-table.njk" %}

SELECT task_id, title, state FROM files WHERE ...
```

Or use Nunjucks macros for composable, DRY templates:

```sqlseal
TEMPLATE
{% from "_templates/macros.njk" import extLink, intLink %}
<table>
{% for row in data %}
<tr>
  <td>{{ extLink(row.url, row.id) }}</td>
  <td>{{ intLink(row.title) }}</td>
</tr>
{% endfor %}
</table>

SELECT ... FROM files WHERE ...
```

Template paths are relative to the vault root, matching the convention used by TABLE data = file(path.csv).

Changes

  • VaultLoader.ts (new): Custom Nunjucks loader that preloads all .njk files from the vault into a cache at startup. File watchers (create/modify/delete/rename) keep the cache in sync. Uses plugin.registerEvent() for proper cleanup on plugin unload.
  • TemplateRenderer.ts: Moved nunjucks.Environment from module-level into the class constructor so it can accept the VaultLoader. Custom filters (groupby, unique) extracted into a registerFilters helper. The loader parameter is optional for backwards compatibility.
  • init.ts: Creates the VaultLoader, preloads templates in onLayoutReady (before codeblock handlers are registered), and passes it to TemplateRenderer.

Testing

  • 15 unit tests covering:
    • getSource — exact path, extension inference, missing template error
    • loadAll — filters to .njk only, handles multiple files
    • Nunjucks integration — {% include %}, {% from ... import %}, extension-less includes, nested includes
    • File watchers — modify, delete, rename, create, non-njk ignored
  • All 87 tests pass (72 existing + 15 new)
  • Manual testing in Obsidian vault with real templates confirmed working

Notes

  • The internal cache property is named _templates (not cache) to avoid conflict with Nunjucks' Environment.initCache() which overwrites each loader's cache property with a plain object.
  • Added src/__mocks__/obsidian.ts and updated jest.config.js with moduleNameMapper and esModuleInterop to support testing modules that import from obsidian.

Closes #197

Swap template engine from Handlebars to Nunjucks for richer template
capabilities. Nunjucks provides native groupby filter, macros,
set/variables, and recursive calls without SQL workarounds.

Changes:
- TemplateRenderer.ts: use nunjucks.compile/render, add groupby/unique filters
- nunjucksHighlighter.ts: syntax highlighting for Nunjucks tags/expressions
- parser.ts: rename handlebarsTemplate -> nunjucksTemplate in grammar
- package.json: swap handlebars dep for nunjucks
Implement a custom Nunjucks loader that reads .njk template files from
the Obsidian vault, enabling {% include %} and {% from ... import %}
directives in TEMPLATE renderer code blocks.

- VaultLoader preloads all .njk files into a cache at startup
- File watchers keep the cache in sync on create/modify/delete/rename
- Event registration uses plugin.registerEvent for proper cleanup
- TemplateRenderer now accepts an optional VaultLoader instance
- Moved nunjucks Environment into TemplateRenderer class (was module-level)
- Added Jest obsidian mock and 15 unit tests covering loader, nunjucks
  integration (include, import, nested includes), and file watchers
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: support reusable Nunjucks templates via vault .njk files

1 participant