Development is frozen. The published package, documentation, examples, and changelog remain available.
Permalink to InstallationInstallation
Permalink to Quick TakeQuick Take
Permalink to ExamplesExamples
- Detect Jinja namespace syntax
- Detect Java Server Pages using a JSP Standard Tag Library element
- Recognize JSP standard actions through a renamed XML namespace prefix
- Report when no supported template language is present
- Shared inline conditional syntax keeps the Nunjucks fallback
- A complete template comment provides shared-family evidence
Supported templating languages:
- Nunjucks/Jinja/Liquid family
- JSP (Java Server Pages)
A complete comment such as {# reviewer note #} supplies shared-family evidence and returns { name: "Nunjucks" }, including empty or multiline comments. Its body cannot supply Jinja or JSP evidence. A {# opener without a later #} is insufficient, so ordinary Svelte {#if ...} blocks do not qualify through that opener alone. This comment check belongs to the classifier; the generic regex helper continues to find its existing {% and {{ markers. Jinja and Nunjucks both support these comments.
Jinja refinement examines complete {% ... %} statements and {{ ... }} expressions. Namespace hints must be live set assignments; prose, quoted code-like text, template comments, and raw or verbatim bodies do not supply refinement evidence. Quoted delimiters and nested brackets are respected. Templates inside HTML attributes, scripts, and styles remain eligible.
Namespace assignments such as {% set ns = namespace (total=0) %} provide a Jinja hint. Keywords are case-sensitive, and assignment names currently support ASCII letters, digits, and underscores, beginning with a letter or underscore. Unicode assignment names remain an acknowledged false-negative boundary and use the family fallback.
A string literal followed by a live format filter provides a hint when its printf conversions are valid, for example {{ "%s: %.2f" | format(name, price) }}. Every conversion must be valid; an escaped percent pair %% alone supplies no conversion. Jinja uses Python-style printf formatting.
This is a syntax heuristic, not a template engine or validator. It does not check argument values or counts, custom delimiters, line statements, or decoded string escapes when recognizing percent characters. For example, an escaped \x25 or \045 is not treated as a literal percent sign for refinement. Runs of adjacent string literals are excluded from format refinement because their combined value is not evaluated. An explicit ~ operator keeps each operand separate. Other engines can add similarly named functions or filters.
Inline conditionals such as {{ "open" if enabled else "closed" }} use the legacy Nunjucks family fallback, with or without spaces around the expression. Nunjucks supports this syntax, so it does not identify Jinja by itself.
JSP XML evidence requires an opening element bound to the exact, case-sensitive URI http://java.sun.com/JSP/Page. Prefixes can be renamed, use Unicode, or be omitted through a default namespace; a jsp:root wrapper is optional. Namespace declarations apply to their own element and descendants, with nested rebinding and self-closing scopes respected. An unused declaration is insufficient. Jakarta Pages defines standard actions through this namespace.
detectLang('<html xmlns:j="http://java.sun.com/JSP/Page"><j:text>Hello</j:text></html>');
// { name: "JSP" }
detectLang('<c:chart xmlns:c="urn:example:charts"/>');
// { name: null }
Comments, CDATA, processing instructions, declarations and quoted attribute contents cannot invent namespace-bound elements. Namespace values support one pass of XML numeric and predefined references; general or external entities are not resolved. This bounded scan does not validate a complete XML document or compile JSP actions. Classic <% markers and ${jsp...} property hints remain lexical, including inside HTML attributes and comments. Unbound jsp:, c:, and cms: openings retain the existing permissive fragment behavior, but an explicit binding to a different URI suppresses that prefix hint in its scope. Closing-only tags and additional tag-library URI families are not new evidence.
This includes explicit JSTL bindings: <c:if/> remains a weak hint, while a c prefix bound only to a JSTL URI needs stronger JSP evidence, such as a classic <%@ taglib ... %> directive. Recognizing every tag-library URI would add collisions with other template systems and is outside this change.
Closing markers alone do not identify a template: %}, }}, and %> return { name: null }. Opening markers {%, {{, and <% remain accepted as incomplete editor hints.
When input contains hints from both supported families, the existing API gives the Nunjucks/Jinja family priority. Its single name does not distinguish ambiguous snippets from templates containing multiple languages.
API — detectLang()
The main function detectLang() is imported like this:
It’s a function which takes one input argument:
For example, returned plain object can look like:
{
name: "Nunjucks";
}
If templating language is not detected, a null is set:
{
name: null;
}
API — version
You can import version: