codeBelt / generate-template-files

A simple generator to create custom template files for any application
https://medium.com/@robertsavian/generate-template-files-with-ease-19b320615359
MIT License
209 stars 31 forks source link
boilerplate-template case-converters generated-code javascript scaffold-template skeleton-template templates templating typescript

generate-template-files

NPM version Downloads

A simple generator that is independent of any language. Create custom boilerplate, scaffolding, skeleton, and templating code files that you need to create over and over again. All you need is NodeJS installed to get started.

Find this useful? Give it a :star:

gif image created with licecap

Medium Article - Generate Template Files with Ease

Install

With NPM:

$ npm install generate-template-files

With Yarn:

$ yarn add generate-template-files

Usage

  1. Check out the examples folder or create a file called generate.js. Note that this file name is flexible.
  2. In that file, add in the example code below.
  3. Run node generate.js within Terminal (Mac) or Powershell (Win) once you've added your template files.
const { generateTemplateFiles } = require('generate-template-files');

const config = require('../package.json');

generateTemplateFiles([
  {
    option: 'Create Redux Store',
    defaultCase: '(pascalCase)',
    entry: {
      folderPath: './tools/templates/react/redux-store/',
    },
    stringReplacers: ['__store__', { question: 'Insert model name', slot: '__model__' }],
    output: {
      path: './src/stores/__store__(lowerCase)',
      pathAndFileNameDefaultCase: '(kebabCase)',
      overwrite: true,
    },
  },
  {
    option: 'Create Reduce Action',
    defaultCase: '(pascalCase)',
    entry: {
      folderPath: './tools/templates/react/redux-store/__store__Action.ts',
    },
    stringReplacers: ['__store__', '__model__'],
    dynamicReplacers: [
      { slot: '__version__', slotValue: config.version },
      { slot: '__description__', slotValue: config.description },
    ],
    output: {
      path: './src/stores/__store__/__store__(lowerCase)/__store__(pascalCase)Action.ts',
      pathAndFileNameDefaultCase: '(kebabCase)',
    },
    onComplete: (results) => {
      console.log(`results`, results);
    },
  },
]);

As outlined in the examples folder, I prefer to create a tools folder and place generate.js w/ templates files in there. Additionally, I'll add a script task ("generate": "node ./tools/generate.js") to my package.json file for convienent running of the generator using npm run generate or yarn generate.

┣━ package.json
┣━ src
┗━ tools/
   ┣━ generate.js
   ┗━ templates/
      ┣━ SomeFile.js
      ┗━ __name__(pascalCase)Action.ts

API

The generateTemplateFiles function takes an array of IConfigItem items.

IConfigItem

Example
{
    option: 'Create Redux Store',
    defaultCase: '(pascalCase)',
    entry: {
        folderPath: './tools/templates/react/redux-store/',
    },
    stringReplacers: ['__store__', { question: 'Insert model name', slot: '__model__' }],
    dynamicReplacers: [
        {slot:'__version__', slotValue: config.version},
        {slot:'__description__', slotValue: config.description}
    ],
    output: {
        path: './src/stores/__store__(lowerCase)',
        pathAndFileNameDefaultCase: '(kebabCase)',
    },
    onComplete: (results) => {
        console.log(results);
    },
},

IResults

Below is an example of what you receive from the onComplete callback. It has the output path, list of files created and the Replacer Slots with the value entered.

Example data you would get from the onComplete callback
{
    output: {
        path: './src/stores/some-thing',
        files: [
            './src/stores/some-thing/SomeThingModule.ts',
            './src/stores/some-thing/SomeThingModuleAction.ts',
            './src/stores/some-thing/SomeThingModuleGetter.ts',
            './src/stores/some-thing/SomeThingModuleMutation.ts',
            './src/stores/some-thing/SomeThingService.ts',
            './src/stores/some-thing/models/actions/ISomeThingState.ts',
            './src/stores/some-thing/models/actions/OtherThingResponseModel.ts'
        ]
    },
    stringReplacers: [
        {
            slot: '__store__',
            slotValue: 'some thing'
        },
        {
            slot: '__model__',
            slotValue: 'other thing'
        }
    ]
}

Replacer Slots or IReplacerSlotQuestion

Replacer Slots are unique string value(s) to be replaced by the generator. An array of string values and/or IReplacerSlotQuestion objects can be used.

stringReplacers: ['__store__', { question: 'Insert model name', slot: '__model__' }];

Replacer slot can be any string value you want to use. You can use something like this in your template files and/or in the file path names.

IReplacerSlotQuestion

Below is an example of a IReplacerSlotQuestion

{question: 'Insert model name', slot: '__model__'}

Dynamic Replacer Slots

If you have data that is dynamically generated, or you have hard coded values you can use the dynamicReplacers:

dynamicReplacers: [
  {slot:'__description__', slotValue: config.description}
],

Case Converters

Case Converters transform the string value entered upon use of the generator.

Example

Here is the string Lives down BY the River with each of the converters:

// If you typed in 'Lives down BY the River' for the a Replacer Slot named '__replacerSlot__' and
// used one of the optional Case Converters you would get the following:

__replacerSlot__(noCase)       // Lives down BY the River
__replacerSlot__(camelCase)    // livesDownByTheRiver
__replacerSlot__(constantCase) // LIVES_DOWN_BY_THE_RIVER
__replacerSlot__(dotCase)      // lives.down.by.the.river
__replacerSlot__(kebabCase)    // lives-down-by-the-river
__replacerSlot__(lowerCase)    // livesdownbytheriver
__replacerSlot__(pascalCase)   // LivesDownByTheRiver
__replacerSlot__(pathCase)     // lives/down/by/the/river
__replacerSlot__(sentenceCase) // Lives down by the river
__replacerSlot__(snakeCase)    // lives_down_by_the_river
__replacerSlot__(titleCase)    // Lives Down By The River

// Note: you can set a 'defaultCase' converter in IConfigItem so all
// Replacer Slots without a Case Converter will be transformed the same way.
__replacerSlot__; //                LivesDownByTheRiver

You may also specify the case using an underscores-only syntax e.g. PascalCase__:

__replacerSlot__NoCase__       // Lives down BY the River
__replacerSlot__CamelCase__    // livesDownByTheRiver
__replacerSlot__ConstantCase__ // LIVES_DOWN_BY_THE_RIVER
__replacerSlot__DotCase__      // lives.down.by.the.river
__replacerSlot__KebabCase__    // lives-down-by-the-river
__replacerSlot__LowerCase__    // livesdownbytheriver
__replacerSlot__PascalCase__   // LivesDownByTheRiver
__replacerSlot__PathCase__     // lives/down/by/the/river
__replacerSlot__SentenceCase__ // Lives down by the river
__replacerSlot__SnakeCase__    // lives_down_by_the_river
__replacerSlot__TitleCase__    // Lives Down By The River

Take your Replacer Slots __replacerSlot__, the Case Converters PascalCase__ and combine them together to make __replacerSlot__PascalCase__.

One Rule: no spaces between the Replacer Slots and Case Converters. If there is a space, Case Converters will not work.

Batch Usage

You can use generate-template-files to generate your template files programmatically, without any interactive prompts. This mode does not support stringReplacers.

The following example will generate the component, unit tests, and the SCSS module in one do.

// generateTemplateFile.js
const { generateTemplateFilesBatch } = require('generate-template-files');

const componentWithInterface = (componentName, componentScope = 'common') => {
  generateTemplateFilesBatch([
    {
      option: 'Component',
      defaultCase: '(pascalCase)',
      entry: {
        folderPath: './tools/templates/react/component',
      },
      dynamicReplacers: [
        { slot: '__name__', slotValue: componentName },
        { slot: '__scope__', slotValue: componentScope },
      ],
      output: {
        path: `./src/component/__scope__(camelCase)`,
        pathAndFileNameDefaultCase: '(pascalCase)',
      },
    },
    {
      option: 'Component Interface',
      defaultCase: '(pascalCase)',
      entry: {
        folderPath: './tools/templates/react/I__interface__.ts',
      },
      dynamicReplacers: [
        { slot: '__interface__', slotValue: componentName },
        { slot: '__scope__', slotValue: componentScope },
      ],
      output: {
        path: `./src/component/__scope__(camelCase)/I__interface__.ts`,
        pathAndFileNameDefaultCase: '(pascalCase)',
      },
    },
  ]).catch(() => {
    console.log('Build Error');
  });
};

Command Line Usage

You can use generate-template-files with the command line to generate your template files.

// generate.js
const { generateTemplateFilesCommandLine } = require('generate-template-files');

generateTemplateFilesCommandLine([
  {
    option: 'Create Reduce Action',
    defaultCase: '(pascalCase)',
    entry: {
      folderPath: './tools/templates/react/redux-store/__store__Action.ts',
    },
    stringReplacers: ['__store__', '__model__'],
    dynamicReplacers: [
      { slot: '__version__', slotValue: config.version },
      { slot: '__description__', slotValue: config.description },
    ],
    output: {
      path: './src/stores/__store__/__store__(lowerCase)/__store__(pascalCase)Action.ts',
      pathAndFileNameDefaultCase: '(kebabCase)',
    },
  },
]);
Minimum Options
node ./tools/generate.js create-reduce-action __store__=some-name __model__=some-other-name
All Options
node ./tools/generate.js create-reduce-action __store__=some-name __model__=some-other-name --outputpath=./src/here --overwrite

Command LIne Script Overview