PrismJS / PrismJS/prism

Removing $placeholder changes how an unquoted template attribute value, attribute name, or tag name parses (13 languages)

Open
#4,119 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
13k
Forks
1.4k
Avg merge
15h 36m
Merged PRs (30d)
3

Description

#4110 removed $placeholder: template tokens no longer leave an identifier-like stand-in in the code handed to the host grammar, they simply vanish. Its description records the consequence for three fixtures; this issue is to track it, since nothing else does.

Where a template expression is an entire unquoted value, the host grammar no longer sees a value there and stops parsing the construct around it. Quoted values are unaffected.

Repro

import { createInstance } from './tests/helper/prism-loader.js';

const prism = await createInstance(['php', 'markup', 'javascript', 'clike', 'css']);

console.log(prism.highlight('<span data-x=<?= $x ?>>a</span>', 'php'));
v2   [tag [punctuation <][tag span] [attr-name data-x][attr-value [punctuation =][php …]][punctuation >]]
new  &lt;span data-x=[php …]>a…                                  ← the whole opening tag is no longer a tag

Scope, measured

All 13 markup-templating languages — django, twig, handlebars, liquid, ejs, erb, etlua, tt2, smarty, ftl, latte, soy, php — in three positions:

position example severity
unquoted attribute value <span data-x={{x}}> the whole opening tag stops being a tag
tag name <h{$level}> tag survives, name is just h
unquoted attribute name <div {{on "click"}}> tag survives, loses the attr-name wrapper

Quoted values (href="{{url}}") are identical to v2.

Of these, only the first loses a whole construct. latte and soy's fixtures changed in #4110 because their stripped text still parses; handlebars' fixture shows the tag being lost.

Not worth chasing

A template expression between JS regex delimiters — <script>var re = /{{p}}/;</script> — collapses to // and comments out the rest of that line. Same root cause, but nobody writes that: interpolating into a regex literal breaks on the first / or backslash in the value, so real code uses new RegExp('{{p}}'). Checked against a corpus of realistic template-in-script snippets (JSON blob, quoted string, bare number, condition, CSS value) — all byte-identical to v2.

Why it is a reasonable trade

Placeholders caused their own class of bugs, found in #4107: the stand-in being parsed as markdown emphasis, as a JS constant, or split in two by the host grammar. This is recorded for tracking, not to argue #4110 should be reverted.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the createInstance reproduction in tests/helper/prism-loader.js and compare the current output with v2 for the 13 templating languages and three positions listed. Inspect the changes from #4110 and the affected fixtures; the issue documents the behavior and trade-off but does not define a target fix or acceptance criteria.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
tooling
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.