Search code examples
javascripttemplates

What is the default “tag” function for template literals?


What is the name of the native function that handles template literals?

That is, I know that when you write tag`Foo ${'bar'}.`;, that’s just syntactic sugar for tag(['Foo ', '.'], 'bar');

But what about just ​`Foo ${'bar'}.`;? I can’t just “call” (['Foo ', '.'], 'bar');. If I already have arguments in that form, what function should I pass them to?

I am only interested in the native function that implements the template literal functionality. I am quite capable of rolling my own, but the purpose of this question is to avoid that and do it “properly”—even if my implementation is a perfect match of current native functionality, the native functionality can change and I want my usage to still match. So answers to this question should take on one of the following forms:

  1. The name of the native function to use, ideally with links to and/or quotes from documentation of it.

  2. Links to and/or quotes from the spec that defines precisely what the implementation of this function is, so that if I roll my own at least I can be sure it’s up to the (current) specifications.

  3. A backed-up statement that the native implementation is unavailable and unspecified. Ideally this is backed up by, again, links to and/or quotes from documentation, but if that’s unavailable, I’ll accept other sources or argumentation that backs this claim up.


  1. Actually, the first argument needs a raw property, since it’s a TemplateStringsArray rather than a regular array, but I’m skipping that here for the sake of making the example more readable.

Motivation

I am trying to create a tag function (tag, say) that, internally, performs the default template literal concatenation on the input. That is, I am taking the TemplateStringsArray and the remaining arguments, and turning them into a single string that has already had its templating sorted out. (This is for passing the result into another tag function, otherTag perhaps, where I want the second function to treat everything as a single string literal rather than a broken up template.)

For example, tag`Something ${'cooked'}.`; would be equivalent to otherTag`Something cooked.`;.

My current approach

The definition of tag would look something like this:

function tag(textParts, ...expressions) {
  const cooked = // an array with a single string value
  const raw = // an array with a single string value
  return otherTag({ ...cooked, raw });
}

Defining the value of raw is fairly straightforward: I know that String.raw is the tag function I need to call here, so const raw = [String.raw(textParts.raw, ...expressions)];.

But I cannot find anywhere on the internet what function I would call for the cooked part of it. What I want is, if I have tag`Something ${'cooked'}.`;, I want const cooked = `Something ${cooked}.`; in my function. But I can’t find the name of whatever function accomplishes that.

The closest I’ve found was a claim that it could be implemented as

const cooked = [expressions.map((exp, i) => textParts[i] + exp).join('')];

This is wrong—textParts may be longer than expressions, since tag`Something ${'cooked'}.`; gets ['Something ', '.'] and ['cooked'] as its arguments.

Improving this expression to handle that isn’t a problem:

const cooked = [
  textParts
    .map((text, i) => (i > 0 ? expressions[i-1] : '') + text)
    .join(''),
];

But that’s not the point—I don’t want to roll my own here and risk it being inconsistent with the native implementation, particularly if that changes.


Solution

  • The name of the native function to use, ideally with links to and/or quotes from documentation of it.

    There isn't one. It is syntax, not a function.

    Links to and/or quotes from the spec that defines precisely what the implementation of this function is, so that if I roll my own at least I can be sure it’s up to the (current) specifications.

    Section 13.2.8 Template Literals of the specification explains how to process the syntax.