npm install pattern-managerTool for managing code patterns
pattern-manager provides a way to manage a folder of code patterns and their generators, which can be application-specific or shared among projects.
It searches for a folder named .patterns in the current working directory or one of its ancestors. The .patterns folder can contain a number of pattern folders.
A pattern folder should contain a pattern.js, which exports a function to create the pattern, and any related template files. Each pattern is responsible to creating a copy of itself, for example: get options from the command-line or user inputs; copy files and folders; and compile templates.
To simplify the scaffolding process, the pattern generator function is provided with a set of utilities: inquirer, handlebars, shell, and chalk.
This tool is inspired by plop.
Global
``bash`
npm install pattern-manager -g
Local (for use in NPM scripts)
`bash`
npm install pattern-manager -D
`bash`
pat
It searches for a .patterns folder, displays a list of patterns, and runs the selected pattern.
`bash`
pat [pattern name] [...pattern options]
If a pattern name is specified, it runs that pattern.
In the .patterns folder, there can be one or more pattern folders. These can be nested.
- Each pattern is named after its folder
- This includes the relative path, for example: react/statepattern.js
- Each pattern folder contains and any template filespattern.js
- Any folder that doesn't have will be ignored
The job of pattern.js is to create a copy of the pattern to its destination. It should export a function that receives a config object.
`js
function pattern(config) {
const { src, dest } = config
// Create new pattern here
}
pattern.description = 'Desciption of pattern'
module.exports = pattern
`
If the function has a description property, it will be displayed when selecting patterns.
#### Config object
The pattern generator function is provided with a set of properties and utility methods.
- src - Source path: the path of the pattern folderdest
- - Destination path: current working folderargv
- - Command line arguments via minimistinquirer
- - Get different types of user inputhandlebars
- - Compile templatesshell
- - Collection of shell commandschalk
- - Colorful logging
Shortcuts
- prompt - Shortcut for inquirer.promptcompile
- - Shortcut for handlebars.compilecompileFile
- - Compile a template file and write to another fileerror
- Arguments: input file path, data object, output file path
- - Display an error message and exitconfirm
- - Ask for confirmation then return true/falsecommand
- Arguments: a message and optional default value (default: true)
- - Shortcut for child_process.spawnSync with streaming output (stdio: inherit)fileExists
- Arguments: command to run, array of arguments, spawnSync options
- - Shortcut for fs.existsSyncreadFile
- - Shortcut for fs.readFileSync with utf8 encodingwriteFile
- - Shortcut for fs.writeFileSyncwriteJsonFile
- - Write object to human-readable JSON file
- Arguments: file path, data object
#### Series of promises
If the pattern generator function returns an array of functions, they will be run as a series of promises.
The following is a basic example of pattern.js.
- Get user input
- Compile a template and copy it to current folder
`js
const path = require('path')
function pattern(config) {
const { src, dest, prompt, compileFile } = config
return [
() => prompt([
{
name: 'message', default: 'Hello, world',
message: 'Message to display'
}
]),
data => {
const srcFile = path.join(src, 'example.js')
const destFile = path.join(dest, 'example.js')
compileFile(srcFile, data, destFile)
console.log(Wrote to ${destFile})
}
]
}
pattern.description = 'Basic pattern'
module.exports = pattern
`
The example.js template:
`js`
console.log('{{message}}')
The following is an advanced example of pattern.js.
- Take user input for the app name and description
- If the destination exists, display error and quit
- Copy all files in the pattern folder to its destination, using rsyncpattern.js
- Ignore itself, and everything in .gitignorepackage.json
- Replace name and description in git init
- Finally, it confirms to run and npm install
If --dry is passed in the command line, it will do a dry run without copying anything.
`js
const path = require('path')
function pattern(config) {
const {
src, dest, argv, prompt, error, chalk,
writeJsonFile, fileExists, quit
} = config
let name, destPath
return [
() => prompt([
{
name: 'name', default: 'app',
message: 'Name of app',
validate: function (value) {
if (value) return true
return 'App name is required'
}
},
{ name: 'description', default: '', message: 'Description' }
]),
data => {
name = data.name
destPath = path.join(dest, name)
const { description } = data
if (fileExists(destPath)) {
return error(Destination "${name}" already exists)
}
// ------------ Copy pattern ------------
command('rsync', [
'-vrlptz'+(argv.dry ? 'n' : ''), // -n for dry run
'--delete',
'--exclude', '.git',
'--exclude', '/pattern.js', // Exclude this file
'--filter', ':- .gitignore',
'.', // Source
destPath
], { cwd: __dirname })
if (argv.dry) quit()
// ------------ Search & replace ------------
const packagePath = path.join(destPath, 'package.json')
let packageData = require(packagePath)
packageData.name = name
packageData.description = description
writeJsonFile(packagePath, packageData)
},
// ------------ Git init ------------
() => confirm('Init .git repo?').then(confirmed => {
if (!confirmed) return
command('git', ['init'], { cwd: destPath })
}),
// ------------ npm install ------------
() => confirm('Install NPM packages?').then(confirmed => {
if (!confirmed) return
command('npm', ['install'], { cwd: destPath })
}),
() => console.log(chalk.green(Created "${name}"))
]
}
pattern.description = 'Advanced pattern'
module.exports = pattern
``