moleculerjs / moleculer-cli

:herb: Command line tool for Moleculer
http://moleculer.services/docs/moleculer-cli.html
MIT License
48 stars 28 forks source link

allow templating in file name #16

Closed ngraef closed 5 years ago

ngraef commented 5 years ago

This change adds the ability for moleculer init to evaluate handlebars template expressions in file names. For example, a template could define a file services/{{serviceName}}.service.js, which could output service/my-service.service.js. This evaluation respects the skipInterpolation meta property.

icebob commented 5 years ago

Nice feature! Did you test it?

ngraef commented 5 years ago

I tested (diff -r) against the official project, nano, module, and project-typescript templates with default options to verify the generated file trees and contents were identical before and after this change.

Additionally, I tested the new functionality on my personal template that uses {{serviceName}}.service.js. More complex handlebars expressions like file{{#hasFlag}}.flag{{/hasFlag}}.js don't currently work because of the / character. We could add support for transforming {{:helper}} into {{/helper}} when passed to the renderer, but I left that out for now because I'm not aware of all the cross-platform naming restrictions.

If you have suggestions for additional tests, I'd be happy to do that.

icebob commented 5 years ago

Great!

Actually, why is / cause problem in renderer? It is used in file contents.

icebob commented 5 years ago

Released in 0.6.2

ngraef commented 5 years ago

Actually, why is / cause problem in renderer? It is used in file contents.

Short answer: the problem isn't in the renderer, it's in the file system reader. Most file systems don't allow / in file names because it is a directory separator. As far as I understand it, macOS will let you create file names with / but when that's exposed to the command line tools, it's replaced with :. For example, test/file.js appears as test:file.js.

icebob commented 5 years ago

So the problem is that metalsmith tries to load the file from filename(which is a template) earlier than handlebars renders the correct filenames.

ngraef commented 5 years ago

From my experiments, metalsmith loads the files just fine. The problem is that the filename metalsmith sees contains : instead of /, which breaks the handlebars template. Example:

  1. I have a file named file{{#hasFlag}}.flag{{/hasFlag}}.js.
  2. When metalsmith loads the list of files, it sees the name of that file as file{{#hasFlag}}.flag{{:hasFlag}}.js (notice the : substitution).
  3. Handlebars tries to render file{{#hasFlag}}.flag{{:hasFlag}}.js and fails because the : token is invalid.

I see a couple solutions:

  1. Simply replace {{: with {{/ before sending it to handlebars. Something like
    const fixed = filename.replace(/({{):/g, '$1/');
    render(fixed, metadata, function (err, res) { /**/ });
  2. Render the file name templates before the metalsmith execution. Whatever tool is used to do this would need to have some way of getting the correct file name, otherwise we're back to option 1 above.

My experiments have only been on macOS so far. More research is needed to see how other platforms handle / in file names.