Skip to content

Pinion

Pinion is a flexible task runner and code generator for any language. Using TypeScript, it gives you full flexibility over what you can do with type-safe tasks and templates out of the box.

Let's see how you can get started with Pinion in 30 seconds.

Install Pinion

Add Pinion as a development dependency in your project like this:

npm install @featherscloud/pinion --save-dev

Note

While generators are written in TypeScript your project can use any programming language. For projects without a package.json run npm init --yes first.

Creating a generator

A Pinion generator has two ingredients:

  • A TypeScript interface to define Context
  • A generate export that wraps the context in a promise and runs through the generator steps

The following file generates a basic readme.md from a TypeScript template string:

ts
import { PinionContext, renderTemplate, toFile } from '@featherscloud/pinion'

// A Context interface. (This one is empty)
interface Context extends PinionContext {}

// The file content as a template string
function readme() {
  return `# Hello world

This is a readme generated by Pinion

Copyright (c) ${new Date().getFullYear()}
`
}

// A `generate` export that wraps the context and renders the template
export function generate(init: Context) {
  return Promise.resolve(init).then(renderTemplate(readme, toFile('readme.md')))
}
sh
npx pinion generators/readme.tpl.ts

Once you ran the command, you can find your readme.md file in the current directory.

Asking questions

Pinion comes with a prompt utility that works with your typed context. Let's get some input from the user!

You can ask questions from the command line with the prompt task:

ts
import {
  PinionContext, renderTemplate, toFile, prompt
} from '@featherscloud/pinion'

// Setup the Context to receive user input
interface Context extends PinionContext {
  name: string
  description: string
}

// The template uses Context variables.
const readme = ({ name, description }: Context) =>
`# ${name}

> ${description}

This is a readme generated by Pinion

Copyright (c) ${new Date().getFullYear()}
`

export const generate = (init: Context) => Promise.resolve(init)
  // Ask prompts (using Inquirer)
  .then(
    prompt({
      name: {
        type: 'input',
        message: 'What is the name of your app?'
      },
      description: {
        type: 'input',
        message: 'Write a short description'
      }
    })
  )
  // Render the template
  .then(renderTemplate(readme, toFile('readme.md')))
sh
npx pinion generators/readme.tpl.ts

Pinion uses Inquirer under the hood to ask questions. The prompt task takes an array or object of Inquirer questions and returns a function that takes a context and returns a promise with the updated context. We can then use this context in the next step to render our template with the answers.

Note

If you already created the readme.md the generator will ask if you want to overwrite the existing file.

What's next?

This is everything needed to get started with writing a generator. Next you can learn more about why we created Pinion and how it can be useful for you, go more in-depth with generators or look at the complete API.