plopjs / plop

Consistency Made Simple
http://plopjs.com
MIT License
7.12k stars 277 forks source link

Pass `template` as a function on the add action #362

Closed tubbo closed 1 year ago

tubbo commented 1 year ago

I'd like to make a generator that writes the output of a command to a file, but make it look and feel like a normal Plop generator, using the same UI and everything.

My use case is for something like how the Supabase CLI can generate TypeScript types based on your database schema:

  plop.setGenerator('types', {
    description: 'Generate TypeScript types from Supabase DB schema',
    prompts: [],
    actions: [
      {
        type: 'add',
        path: 'types/database.ts',
        force: true,
        template: () =>
          child_process.execSync('supabase gen types typescript --local', {
            encoding: 'utf8',
          }),
      },
    ],
  })

This of course gives us the error:

✖  ++ You must pass a string or Handlebars AST to Handlebars.compile. You passed () =>
          execSync('supabase gen types typescript --local', {
            encoding: 'utf8',
          })

A quick read of the source feels like, for my use case, one place this could occur is within getTemplate(), right before returning the template string, perhaps it could check whether the value is a function and then call it right there to get the source. Or perhaps this is a whole different option/action that I'm thinking of.

Currently, the way I am getting around this is to use a custom action:

  plop.setGenerator('types', {
    description: 'Generate TypeScript types from Supabase DB schema',
    prompts: [],
    actions: [
      () =>
        execSync('supabase gen types typescript --local > types/database.ts', {
          encoding: 'utf8',
        }),
    ],
  })

When this runs successfully, it produces no output, which is fine but I'd really like to leverage what Plop gives me here for a better experience.

Probably an ideal solution here is to introduce a new config option for the add action that allows you to set the output of the file with a function, foregoing all of the template stuff if this function is defined.

amwmedia commented 1 year ago

If you return a string value from the custom action function, that value will be shown as the "result" for the action in the plop UI. Your custom action function can also be asynchronous by returning a Promise that resolves with a string.

crutchcorn commented 1 year ago

Closing as this seems to be answered