Global interpretation of comments within tagged template literals

Description

Tagged template literals are commonly used by web components libraries. They can also include CSS code, HTML code and embedded expressions (a.k.a. substitutions).

ES provides its own:

  • semantics (//... and /* ... */) for instructing parser to ignore strings referred as comment, and
  • tagged template literals

The problem

ES parser fails to recognize and, hence, parse correctly (ie to ignore) its own comments within its own tagged template literals.

Example

I wish to de-activate a part of the code within html tagged template for testing purpose; which means I just don't want to display that part. The first thing that passes from my mind is to use the corresponding html comment semantics.

js-type-file.js

html`
  <!--
    <p>${v}</p>
    <p>Backtick(`)</p>
  -->
`

In that case, ES parser:

  • gives error when v is either defined or not, or
  • terminates the template earlier due to the first backtick (`) and parser gives an error due to the wrong syntax of the remaining code.

Therefore, ES parser gives priority to its features - expression (${v}) and backtick (`) - against HTML features (<!-- ... --> comment).

Based on that, one can very reasonably assume that adding ES comment semantics will solve the problem. Namely:

html`
  <!--
    /*
      <p>${v}</p>
      <p>Backtick(`)</p>
    */
  -->
`

Now, unfortunately, ES parser, again, ignores the comment semantics and parses the content resulting in errors.

The same problem exists with CSS syntax, although both CSS and ES use the same comment semantics (/* ... */) .

Rough ideas how to solve

  • Make ES parser to globally ignore ES comment semantics, either
    • by using the existing semantics, or
    • by adopting new ones, statically parsed, only for use within tagged templates literals (e.g. <!--/* ... */--> for HTML, /*/* ... */*/ for CSS, etc)
      Parser can do that in the same way that tracks expressions (${...}) or backtick (`)
  • Make ES parser to consider basic features of other languages (I suspect that it's very "expensive"!)

Caveat

Expressions evaluation may not take place.

html`
  /* This is what I want<br>
    <p>${v}</p>
    <p>Backtick(`)</p>
  to display */
`

ES parser will ignore the whole text between the semantics and display:

/* This is what I want
${v}
Backtick(`)
to display */

Although it is not what one can expect, the behavior is totally justified and the outcome makes sense without contradictions.

BUT, with a very small change one can solve even this minor itch. Instead of /*, one can write &sol;*. ES parser will not complain at all.

html`
  &sol;* This is what I want<br>
    <p>${v}</p>
    <p>Backtick(\`)</p>
  to display */
`

So, the outcome will be something like:

/* This is what I want
It's evaluated!
Backtick(`)
to display */

By that way, ES does not abuse any HTML or CSS feature and goes BY THE BOOK!

Consider the implications of changing template literal parsing rules, for existing programs:

As was explained in another thread, there is no parsing to be done on the string content of template literals - it's just text content.

Template literals have shipped on the web for 6+ years; there are doubtless web pages that rely on JS comment syntax inside the text position of a template literal renders as literal text, so it's not going to ever be possible to change the way those work.

You could certainly write your own template tag function that did the parsing - and I believe that was the intention of those who designed this feature.

1 Like

... so it's not going to ever be possible to change the way those work.

I appreciate that your answer is very straight.

You could certainly write your own template tag function that did the parsing - and I believe that was the intention of those who designed this feature.

Here lightmare alleges that "ES source code is first parsed, then executed. You cannot alter the parser's behaviour with a run-time function." Is your allegation totally unrelated with the above statement?

Template literal contents are not ES source code - they're literal text, with zero implied semantics or parseability. A template tag function can do whatever it wants with that text, including attempt to parse it.

So yes, it's totally unrelated.

1 Like

The clue is:

  • ES "reacts" when it meets inside tagged template literals:
    • expression semantics ${...},
    • the same string used as template start/end tags, a backtick (`) in the current case
  • for the time being, to comment out code chunks inside templates, the following workarounds are available:
    • ${''/* ... */}
    • ${''&&` ... `} (still backtick (`) gives error)
  • Any solution must be JavaScript backwards compatible
  • ES might officially adopt semantics like:
    • ${* ... *}, or
    • ${''/* ... */}

Thanks to all for your time!

Notes:

Nit: ${''/* ... */} is already a valid interpolation today, and I've used it in the wild before myself.

1 Like

Please, advise me if the official documentation of ES defines the adoption of ${''/* ... */} or any other semantics to comment out content within template literals. Is there any hint in https://developer.mozilla.org?

Tia

PS: I am sure that you have also used /* ... */ or // in the wild before yourself, but these are defined and documented in 12.4 Comments of ES Specification.

This is not some special syntax. Template literals allow any valid ES expression inside ${ ... }. Comments in expressions are treated as whitespace, and '' is a valid expression (empty string). Therefore ${'' /* ... */} evaluates to the empty string.

Oh, OK.

Semantics like ${/* ... */} make the most reasonable sense; better than ${* ... *} because it is more consistent with normal comment. At first look at 12.8.5 Regular Expression Literals, / is not allowed as a first character. Could that be changed?

If ${/* ... */} were allowed, it would be reasonable to expect that ${} was also allowed, since a comment is supposed to just remove itself. If we don't do that, we'd be adding some inconsistencies to the comment syntax.

Now, what would it mean to do ${}? It sounds like you would want that to effectively mean the same thing as ${''}, i.e. if you omit the expression between ${...}, then it defaults to an empty string. This basically makes ${/* ... */} a convenient shorthand for ${''/* ... */} which is certainly a possibility.

As for adding comments to regular expressions, there's a whole entire thread over here devoted to improving regular expressions via comment support. The discussion lead to this proposal repo - so far there aren't any champions who are wanting to push it, but that seems to be the current agreed upon solution from that thread if we wanted to solve this problem.