generate-template-files-v2
v3.3.2
Published
A generator to create custom template files for your applications
Downloads
20
Maintainers
Readme
generate-template-files-v2
Forked from generate-template-files: Because author not maintain
Find this useful? Give it a :star:
Medium Article - Generate Template Files with Ease
Install
With NPM:
$ npm install generate-template-files-v2
With Yarn:
$ yarn add generate-template-files-v2
Usage
- Check out the
examples
folder or create a file calledgenerate.js
. Note that this file name is flexible. - In that file, add in the example code below.
- Run
node generate.js
within Terminal (Mac) or Powershell (Win) once you've added your template files.
const { generateTemplateFiles } = require('generate-template-files-v2');
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__' , result : (value)=> {
return value+"custom if you want"
}}],
dynamicReplacers: [
{ slot: '__version__', slotValue: config.version },
{ slot: '__customVersion__', slotValue: config.description ,
newSlot:({__version__})=>{
return __version__+ ".1.1"
}},
],
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
option
- The name of the option to choose when asked.defaultCase
- The default Case Converters to use with the Replacer Slots in the template files. Default is(noCase)
.entry.folderPath
- Path to a folder of files or a single template file.stringReplacers
- An array of Replacer Slots used to replace content in the designatedentry.folderPath
.dynamicReplacers
- (Optional) An array of IReplacer used to replace content in the designatedentry.folderPath
.output.path
- The desired output path for generated files. Case Converters and Replacer Slots can be used to make the path somewhat dynamic.output.pathAndFileNameDefaultCase
- The Case Converters to use for the file path and file name(s).output.overwrite
- (Optional) Whentrue
it will overwrite any files that are named the same.onComplete
- (Optional) Takes a callback function that is called once the file(s) have been outputted. A IResults object will be passed to the callback.
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.
output.path
- The file(s) output pathoutput.files
- List of files createdstringReplacers
- List of Replacer Slots; name and values entered during the setup process
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.
~replacerSlot~
{{something else}}
__AnythingYouWant__
IReplacerSlotQuestion
Below is an example of a IReplacerSlotQuestion
{question: 'Insert model name', slot: '__model__'}
question
- The question to ask the use what value should be used for the replacerslot
slot
- The string value for the Replacer Slots
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
- In the generator template
__replacerSlot__
is appended by the(pascalCase)
converter such as__replacerSlot__(pascalCase)
. - When the generator is ran, the string
"product reducer"
is provided for__replacerSlot__
. - As a result, the converter will produce
ProductReducer
.
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.
- :white_check_mark:
__name__(camelCase)
OR__name__CamelCase__
- :x:
__name__ (camelCase)
OR__name__ CamelCase__
Batch Usage
You can use generate-template-files-v2
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 { generateTemplateFiles } = require('generate-template-files-v2');
generateTemplateFiles([
// Angular
{
option: 'Angular Ngrx Store',
defaultCase: '(pascalCase)',
entry: {
folderPath: './tools/templates/angular/ngrx-store/',
},
stringReplacers: ['__name__', {question: 'Insert model name', slot: '__model__'}],
dynamicReplacers: [
{slot: '__version__', slotValue: config.version},
{slot: '__description__', slotValue: config.description},
],
output: {
path: './src/app/stores/__name__(lowerCase)',
pathAndFileNameDefaultCase: '(kebabCase)',
overwrite: false,
},
onComplete: async (results) => {
// console.log(`results`, results);
},
},
// Vue
{
option: 'Vue Vuex Store',
defaultCase: '(pascalCase)',
entry: {
folderPath: './tools/templates/vue/vuex-store/',
},
stringReplacers: ['__store__', '__model__'],
dynamicReplacers: [
{
slot:"__store1__custom__",
newSlot:({__store__})=>{
return `${__store__} from other string replacer`
}
},
{
slot:"__store2_from_other_custom1",
newSlot:({__store1__custom__})=>{
return __store1__custom__+ " and custom dynamic replacer"
}
}
],
output: {
path: './src/stores/__store__(kebabCase)',
pathAndFileNameDefaultCase: '(pascalCase)',
},
onComplete: async (results) => {
console.log(`results`, results);
await importVuexStore(results);
},
},
// React
{
option: 'React Redux Store',
defaultCase: '(pascalCase)',
entry: {
folderPath: './tools/templates/react/redux-store/',
},
stringReplacers: ['__store__', '__model__'],
output: {
path: './src/stores/__store__(kebabCase)',
pathAndFileNameDefaultCase: '(pascalCase)',
overwrite: true,
},
onComplete: (results) => {
console.log(`results`, results);
},
},
])
;
/*
* NOTE: there is many ways you can do this. This is just an example on how you might approach it.
*/
async function importVuexStore(results) {
const files = results.output.files;
const fullPaths = files
.map((folderPath) => folderPath.replace('src/', '')) // remove 'src' from path
.map((path) => `import ${filename(path)} from '${path}'`) // create import statement
.join('\n'); // put all imports on there own line
try {
await insertLine('src/import-test.ts').append(fullPaths);
} catch (error) {
console.log(``, error);
}
}
Command Line Usage
You can use generate-template-files-v2
with the command line to generate your template files.
// generate.js
const { generateTemplateFilesCommandLine } = require('generate-template-files-v2');
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
node ./tools/generate.js
- Runs thegenerate-template-files-v2
librarycreate-reduce-action
- The template name; It uses the same option name in the IConfigItem but converts all options names to kebab-case. For exampleoption: 'Create Reduce Action'
will be converted tocreate-reduce-action
when using the command line__store__=some-name
- Are Replacer Slots and will be converted to{ slot: "__store__", slotValue: "some-name" }
--outputpath=./src/here
- Will override theoutput.path
in the IConfigItem--overwrite
- Will overwrite files if the files already exists