Handlebars.js with JavaScript template strings throws error

446 Views Asked by At

I'm using plop for code generation of some TypeScript files. This is not using HTML at all. Under the hood plop uses Handlebars for it's templating. One of my templates generates a series of new properties on a class like this:

My data looks something like this:

const data = { items: ['one', 'two', 'three'] }

In my template file:

... part of the class

{{#each items}}
import {
  Name as {{this}}Name
} from '.../{{this}}';
{{/each}}

... other stuff happening

{{#each items}}
const thing{{this}} = new Thing({
  someProperty: `${{{this}}Name}`
});
{{/each}}

... the rest of the class

The desired output would look something like this:

import {
  Name as oneName
} from '.../one';
import {
  Name as twoName
} from '.../two';
import {
  Name as threeName
} from '.../three';

const thingone = new Thing({
  someProperty: `${oneName}`
});
const thingtwo = new Thing({
  someProperty: `${twoName}`
});
const thingthree = new Thing({
  someProperty: `${threeName}`
});

The problem seems to be with the `${{{entity}}Name}` portion of the template. When attempting to compile it throws the following error:

Expecting 'CLOSE_UNESCAPED', 'OPEN_SEXPR', 'ID', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', got 'CLOSE'

I'm guessing this is because the syntax in handle bars to html escape is denoted by the {{{ syntax.

I'm curious if there is a way to escape that fist { and tell handlebars not to worry about it and treat it as a literal. I know I can split the line like this `${ {{entity}}Name }`, however, that breaks linting rules within the project and is not desirable.

I've tried looking through the handlebars documentation and searching on SO without much luck.

Any help is appreciated.

1

There are 1 best solutions below

0
stetson On

I figured this out after some more digging.I found this answer on SO. Looks like the only way to accomplish this is using a handlebar helper function. In my case, since I'm using plop, I can simply put the following in my plopfile:

plop.addHelper('curlyName', (entity) => {
  return `{${entity}Name}`;
});

then call that helper from the template like this

{{#each items}}
const thing{{this}} = new Thing({
  someProperty: `${{curlyName this}}`
});
{{/each}}

which will give me the result of

const thingone = new Thing({
  someProperty: `${oneName}`
});
const thingtwo = new Thing({
  someProperty: `${twoName}`
});
const thingthree = new Thing({
  someProperty: `${threeName}`
});

Really disappointing there isn't a simply way to just throw a / or some other character to escape within the template itself. Hopefully someone finds this helpful and waste a few hours figuring out such a simple thing, like I did.