npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vite-hub/markdown-template

v0.0.3

Published

Deterministic Markdown templates with explicit data, conditions, fragments, and caller-resolved imports.

Downloads

453

Readme

@vite-hub/markdown-template

@vite-hub/markdown-template renders deterministic Markdown from explicit data. It combines scalar values, Markdown fragments, bounded conditional sections, and caller-resolved relative imports without evaluating JavaScript or performing implicit I/O.

import { renderMarkdownTemplate } from "@vite-hub/markdown-template"

const markdown = await renderMarkdownTemplate(template, {
  data: {
    pullRequest,
    sections: {
      files: filesMarkdown,
    },
  },
})

Use {{ pullRequest.title }} for a string, number, or boolean. Scalar values are serialized as Markdown text, so Markdown syntax in the value stays literal. Use {{{ sections.files }}} for an intentional Markdown fragment. Fragments are never evaluated again, so bindings, branches, and imports inside their content stay literal.

Scalar bindings also work inside quoted XML-style attributes. Attribute values are HTML-escaped, while template syntax inside code spans and code blocks stays literal.

Conditional sections support own-property data paths, literals, !, equality and inequality (===, !==, ==, and != use strict semantics), &&, ||, and parentheses:

::if{pullRequest.available && !pullRequest.draft}
Review {{ pullRequest.title }}.
::else
No review context is available.
::

Imports only run when you provide resolveImport. The resolver receives a relative specifier and the current canonical source ID, and it returns the imported template with its canonical ID for cycle detection:

await renderMarkdownTemplate(template, {
  sourceId: "/templates/review.md",
  resolveImport: async (specifier, importer) => {
    return { id: resolvedId, template: importedMarkdown }
  },
})

Imports resolve before conditional sections are evaluated, so the resolver must authorize every requested import even when it appears inside an unselected branch.

The renderer does not provide loops, helpers, macros, a compile phase, filesystem or URL access, HTML rendering, or public syntax-tree hooks. Markdown fragments preserve document structure, but they do not make untrusted content safe for a model; instruction and data boundaries remain the caller's responsibility.

Comark provides the Markdown parser, component syntax, syntax tree, and serializer. ViteHub owns the constrained composition policy exposed by this package.

Named templates

Markdown files under server/templates are discovered by relative name and bundled before deployment:

import { renderTemplate, type TemplateName } from "#vitehub/templates"

const markdown = await renderTemplate("review/pull-request", { pullRequest, sections })

export function renderPrompt(name: TemplateName, data: Record<string, unknown>) {
  return renderTemplate(name, data)
}

ViteHub removes the server/templates/ prefix and .md extension from each catalog name. For example, server/templates/pull-request.md becomes pull-request, while server/templates/review/pull-request.md becomes review/pull-request.

renderTemplate(name, data?) returns a Promise<string>. The generated TemplateName union autocompletes valid names and rejects typos, while the optional data record defaults to {}. A JavaScript caller that passes an unknown name receives a TypeError at runtime.

Use a .template.md file when a private prompt belongs beside its caller instead of in the application catalog:

import prompt from "./prompt.template.md"

const markdown = await prompt({ pullRequest, sections })

Relative Markdown imports work in both forms and can remain ordinary .md files.

Files ending in .template.md remain direct-import modules and do not enter the named catalog, even when they are under server/templates. The legacy ?markdown-template import query remains supported for existing applications, but new code should use the .template.md suffix.

The vitehub() preset installs the integration. Modular Vite configs can add hubMarkdownTemplate() from @vite-hub/markdown-template/vite; both forms resolve server/templates and generated files from the ViteHub project root, including projects that use a nested Vite root. They generate template names and ambient module types under .vitehub/types; include .vitehub/types/**/*.d.ts in the application's tsconfig.json so TypeScript sees them.