You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[scanner] UI cheatsheet advertises {{&name}} as unescaped output, but the parser never recognizes it — the blank silently renders empty #332
The Builder UI's Mustache cheatsheet (src/ui.html:609-610) lists {{{name}}} as "Unescaped output" and {{&name}} as "Unescaped (alt syntax) — Same as {{{name}}}". The triple form works, but the & form is not a blank promptargs recognizes: it is never listed, cannot be filled, and silently renders as an empty string.
Evidence
src/parser.ts:33 — VAR_PATTERN = /\{\{\s*([\w-]+)(?:=([^}]*?))?\s*\}\}/g. In {{{name}}} the inner {{name}} matches, so the triple form is parsed as the blank name and expand() keeps Mustache's triple tag (escaping is already disabled, so output is the same). In {{&name}} / {{& name}} the tag starts with &, which is not [\w-], so nothing matches.
src/parser.ts:94-112 — expand() only seeds the view with names from parseVars; Mustache then renders {{&name}} from a view that has no name, i.e. as "". This is exactly the "blank silently vanished" failure the comment at src/parser.ts:25-32 gives as the reason padded tags were made to match.
src/ui.html:663,756,821-822 — the UI's variable table and the red/yellow highlighting both come from parseVars / VAR_PATTERN, so a {{&name}} row never appears in the builder and the preview just drops the text.
CLI: assertKnownFlags (src/flags.ts) only accepts --flag for parsed blanks, so promptargs "Say {{&word}}" --word=hi --no-interactive is rejected as an unknown flag rather than filled — there is no way to supply the value.
src/parser.test.ts:156 covers {{{x}}} but there is no test for the & form anywhere in src/*.test.ts.
Reproduce
promptargs "A: {{&word}} B: {{{word}}}" --word=hi --no-interactive
# expected (per cheatsheet): "A: hi B: hi"# actual: usage error — or, with the flag omitted, "A: B: {{word}}"
Suggested fix
Pick the simplest option and keep both surfaces (CLI + UI) on the same VAR_PATTERN:
Recognize {{&name}} / {{& name}} (and the =default extension on it) in VAR_PATTERN so it is parsed, filled and highlighted like {{{name}}}; expand()'s normalization must keep the & so Mustache still treats it as an unescaped tag (harmless, since escaping is disabled). Extend DOTTED_PATTERN the same way so {{&repo.owner}} is rejected like {{repo.owner}}.
Alternatively, if the & form is deliberately unsupported, remove the cheatsheet row (or mark it unsupported like sections/partials in README "Mustache sections and partials").
Add a parser test for {{&name}}, {{& name }}, {{&name=dflt}} alongside the existing {{{x}}} case, plus a changelog.d/fixed-*.md fragment.
Severity: low (P3) — silent data loss in the expanded prompt only for templates written against the cheatsheet's & row.
Activity