## File: README.md

# Plop

Micro-generator framework that makes it easy for an entire team to create files with a level of uniformity.


> [Documentation also available on plopjs.com](https://plopjs.com/documentation/)

# Getting Started

[](https://www.npmjs.com/package/plop)
&nbsp;
[](https://www.npmjs.com/package/plop)

## What is Plop?

Plop is what I like to call a "micro-generator framework." Now, I call it that because it is a small tool that gives you a simple way to generate code or any other type of flat text files in a consistent way. You see, we all create structures and patterns in our code (routes, controllers, components, helpers, etc). These patterns change and improve over time so when you need to create a NEW _insert-name-of-pattern-here_, it's not always easy to locate the files in your codebase that represent the current "best practice." That's where plop saves you. With plop, you have your "best practice" method of creating any given pattern in CODE. Code that can easily be run from the terminal by typing `plop`. Not only does this save you from hunting around in your codebase for the right files to copy, but it also turns "the right way" into "the easiest way" to make new files.

If you boil plop down to its core, it is basically glue code between [inquirer](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md) prompts and [handlebar](https://github.com/wycats/handlebars.js/) templates.

> This documentation is a work in progress. If you have great ideas, I'd love to hear them.

## Installation

### 1. Add plop to your project

```
$ npm install --save-dev plop
```

### 2. Install plop globally (optional, but recommended for easy access)

```
$ npm install plop
```

### 3. Create a plopfile.js at the root of your project

```javascript
export default function (plop) {
  // create your generators here
  plop.setGenerator("basics", {
    prompts: [], // array of inquirer prompts
    actions: [], // array of actions
  });
}
```

> `export default` is only allowed in NodeJS inside "ESM" supported files.
> To use this syntax, your `plopfile` must be either:
>
> - An ESM .js file with type: "module" in package.json
> - An ESM .mjs file with any type declared in package.json
>
> Alternatively, you can have a `plopfile` with `module.exports = function (plop)` instead.
> For _this_ syntax, your `plopfile` must be either:
>
> - A CommonJS .js file with type: "commonjs" in package.json
> - A CommonJS .cjs file with any type declared in package.json

## Your First Plopfile

A plopfile starts its life as a node module that exports a function which accepts the `plop` object as its first parameter.

```javascript
export default function (plop) {}
```

The `plop` object exposes the plop API object which contains the `setGenerator(name, config)` function. This is the function that you use to (wait for it) create a generator for this plopfile. When `plop` is run from the terminal in this directory (or any sub-directory), a list of these generators will be displayed.

Let's try setting up a basic generator to see how that looks.

```javascript
export default function (plop) {
  // controller generator
  plop.setGenerator("controller", {
    prompts: [
      {
        type: "input",
        name: "name",
        message: "controller name please",
      },
    ],
    actions: [
      {
        type: "add",
        path: "src/{{name}}.js",
        templateFile: "plop-templates/controller.hbs",
      },
    ],
  });
}
```

The _controller_ generator we created above will ask us 1 question, and create 1 file. This can be expanded to ask as many questions as needed, and create as many files as needed. There are also additional actions that can be used to alter our codebase in different ways.

## Using Prompts

Plop uses the [inquirer.js](https://github.com/SBoudrias/Inquirer.js) library to gather user data. A list of [prompt types](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md#prompt-types) can be found on the inquirer official website.

## CLI Usage

Once plop is installed, and you have created a generator, you are ready to run plop from the terminal. Running `plop` with no parameters will present you with a list of generators to pick from. You can also run `plop [generatorName]` to trigger a generator directly. If you did not install plop globally, you will need to setup an npm script to run plop for you.

```javascript
// package.json
{
    ...,
    "scripts": {
        "plop": "plop"
    },
    ...
}
```

### Bypassing Prompts

Once you get to know a project (and its generators) well, you may want to provide answers to the prompts when you run the generator. If I have (for instance) a `component` generator that has one prompt (name), I can run that generator using `plop component "some component name"` and it will immediately execute as though I had typed "some component name" into the prompt. If that same generator had a second prompt, the same input would have resulted in the user being prompted for the second value.

Prompts like `confirm` and `list` try to make sense of your input as best they can. For instance entering "y", "yes", "t", or "true" for a confirm prompt will result in a boolean `true` value. You can select items from a list using their value, index, key, or name. Checkbox prompts can accept a comma separated list of values in order to select multiples.



> If you want to provide bypass input for the second prompt but not the first, you can use an underscore "\_" to skip the bypass (ie `plop component _ "input for second prompt"`).

Plop comes with bypass logic built-in for standard inquirer prompts, but there are also ways to provide custom logic for how to handle user input for a specific prompt.

If you have published a 3rd party inquirer prompt plugin and would like to support bypass functionality for plop users out of the box, that is covered in [another section of this documentation](#3rd-party-prompt-bypass).

### Bypassing Prompts (by Name)

You can also bypass prompts by name using `--` and then providing arguments for each prompt that you'd like to bypass. Examples [below](#bypass-examples).

#### Bypass Examples

```
## Bypassing both prompt 1 and 2
$ plop component "my component" react
$ plop component -- --name "my component" --type react

## Bypassing only prompt 2 (will be prompted for name)
$ plop component _ react
$ plop component -- --type react
```

### Running a Generator Forcefully

By default Plop actions keep your files safe by failing when things look fishy. The most obvious example of this is not allowing an [`add`](#add) action to overwrite a file that already exists. Plop actions individually support the `force` property but you can also use the `--force` flag when running Plop from the terminal. Using the `--force` flag will tell every action to run forcefully. With great power...🕷

### Using TypeScript plopfiles

#### Node.js v22.18+**

Modern Node.js supports TypeScript files [out-of-the-box](https://nodejs.org/docs/latest/api/typescript.html). No extra setup or CLI flags are required to use a TypeScript plopfile. 

First, make a TypesScript plopfile using `plop --init-ts` or by hand:

```ts
// plopfile.ts
import type { NodePlopAPI } from "plop";

export default function (plop: NodePlopAPI) {
  // plop generator code
}
```

Second, add `plop` to `scripts` in `package.json`:

```json
// package.json
"scripts": {
  "plop" : "plop"
}
```

#### Older Node.js Versions**

Plop bundles TypeScript declarations and supports TypeScript plopfiles via [tsx loaders](https://github.com/privatenumber/tsx?tab=readme-ov-file#nodejs-loader), a feature of [NodeJS command line imports](https://nodejs.org/api/cli.html#--importmodule).

First, make a TypesScript plopfile using `plop --init-ts` or by hand:

```ts
// plopfile.ts
import { NodePlopAPI } from "plop";

export default function (plop: NodePlopAPI) {
  // plop generator code
}
```

Next, install [tsx](https://github.com/privatenumber/tsx) and optionally [cross-env](https://www.npmjs.com/package/cross-env):

```bash
npm i -D tsx cross-env
```

Finally, use `NODE_OPTIONS` to activate the tsx loader. Now Plop can import your `plopfile.ts`:

**Node.js v20.6 and above**

```json
// package.json
"scripts": {
  "plop" : "cross-env NODE_OPTIONS='--import tsx' plop --plopfile=plopfile.ts"
}
```

**Node.js v20.5.1 and below**

```json
// package.json
"scripts": {
  "plop": "cross-env NODE_OPTIONS='--loader tsx' plop --plopfile=plopfile.ts"
}
```

## Why Generators?

Because when you create your boilerplate separate from your code, you naturally put more time and thought into it.

Because saving your team (or yourself) 5-15 minutes when creating every route, component, controller, helper, test, view, etc... [really adds up](https://xkcd.com/1205/).

Because [context switching is expensive](https://www.petrikainulainen.net/software-development/processes/the-cost-of-context-switching/) and saving time is not the only [benefit to automating workflows](https://kentcdodds.com/blog/automation)

# Plopfile API

The plopfile api is the collection of methods that are exposed by the `plop` object. Most of the work is done by [`setGenerator`](#setgenerator) but this section documents the other methods that you may also find useful in your plopfile.

## TypeScript Support

Plop bundles TypeScript declarations. See [using TypeScript plopfiles](#using-typescript-plopfiles) for more details.

## JSDoc Support

Whether or not you write your plopfile in TypeScript, many editors will offer code assistance via JSDoc declarations.

```javascript
// plopfile.js
export default function (
  /** @type {import('plop').NodePlopAPI} */
  plop,
) {
  // plop generator code
}
```

## Main Methods

These are the methods you will commonly use when creating a plopfile. Other methods that are mostly for internal use are list in the [other methods](#other-methods) section.

| Method                                                            | Parameters                                                 | Returns                                     | Description                                                                   |
| ----------------------------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------- | ----------------------------------------------------------------------------- |
| [**setGenerator**](#setgenerator)                                 | _String, [GeneratorConfig](#interface-generatorconfig)_    | _[PlopGenerator](#interface-plopgenerator)_ | setup a generator                                                             |
| [**setHelper**](#sethelper)                                       | _String, Function_                                         |                                             | setup handlebars helper                                                       |
| [**setPartial**](#setpartial)                                     | _String, String_                                           |                                             | setup a handlebars partial                                                    |
| [**setActionType**](#setactiontype)                               | _String, [CustomAction](#functionsignature-custom-action)_ |                                             | register a custom action type                                                 |
| [**setPrompt**](#setprompt)                                       | _String, InquirerPrompt_                                   |                                             | registers a custom prompt type with inquirer                                  |
| [**load**](https://github.com/plopjs/plop/blob/main/plop-load.md) | _Array[String], Object, Object_                            |                                             | loads generators, helpers and/or partials from another plopfile or npm module |

## setHelper

`setHelper` directly corresponds to the handlebars method `registerHelper`. So if you are familiar with [handlebars helpers](https://handlebarsjs.com/guide/expressions.html#helpers), then you already know how this works.

```javascript
export default function (plop) {
  plop.setHelper("upperCase", function (text) {
    return text.toUpperCase();
  });

  // or in es6/es2015
  plop.setHelper("upperCase", (txt) => txt.toUpperCase());
}
```

## setPartial

`setPartial` directly corresponds to the handlebars method `registerPartial`. So if you are familiar with [handlebars partials](https://handlebarsjs.com/guide/partials.html), then you already know how this works.

```javascript
export default function (plop) {
  plop.setPartial("myTitlePartial", "<h1>{{titleCase name}}</h1>");
  // used in template as {{> myTitlePartial }}
}
```

## setActionType

`setActionType` allows you to create your own actions (similar to `add` or `modify`) that can be used in your plopfiles. These are basically highly reusable [custom action function](#custom-action-function)s.

### _FunctionSignature_ Custom Action

| Parameters  | Type                                      | Description                                                  |
| ----------- | ----------------------------------------- | ------------------------------------------------------------ |
| **answers** | _Object_                                  | Answers to the generator prompts                             |
| **config**  | _[ActionConfig](#interface-actionconfig)_ | The object in the "actions" array for the generator          |
| **plop**    | _[PlopfileApi](#plopfile-api)_            | The plop api for the plopfile where this action is being run |

```javascript
export default function (plop) {
  plop.setActionType("doTheThing", function (answers, config, plop) {
    // do something
    doSomething(config.configProp);
    // if something went wrong
    throw "error message";
    // otherwise
    return "success status message";
  });

  // or do async things inside of an action
  plop.setActionType("doTheAsyncThing", function (answers, config, plop) {
    // do something
    return new Promise((resolve, reject) => {
      if (success) {
        resolve("success status message");
      } else {
        reject("error message");
      }
    });
  });

  // use the custom action
  plop.setGenerator("test", {
    prompts: [],
    actions: [
      {
        type: "doTheThing",
        configProp: "available from the config param",
      },
      {
        type: "doTheAsyncThing",
        speed: "slow",
      },
    ],
  });
}
```

## setPrompt

[Inquirer](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md) provides many types of prompts out of the box, but it also allows developers to build prompt plugins. If you'd like to use a prompt plugin, you can register it with `setPrompt`. For more details see the [Inquirer documentation for registering prompts](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md#inquirerregisterpromptname-prompt). Also check out the [plop community driven list of custom prompts](https://github.com/plopjs/awesome-plop#inquirer-prompts).

```javascript
import autocompletePrompt from 'inquirer-autocomplete-prompt';
export default function (plop) {
	plop.setPrompt('autocomplete', autocompletePrompt);
	plop.setGenerator('test', {
		prompts: [{
			type: 'autocomplete',
			...
		}]
	});
};
```

## setGenerator

The config object needs to include `prompts` and `actions` (`description` is optional). The prompts array is passed to [inquirer](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md/#objects). The `actions` array is a list of actions to take (described in greater detail below)

### _Interface_ `GeneratorConfig`

| Property        | Type                                                                                                                    | Default | Description                                   |
| --------------- | ----------------------------------------------------------------------------------------------------------------------- | ------- | --------------------------------------------- |
| **description** | _[String]_                                                                                                              |         | short description of what this generator does |
| **prompts**     | _Array[[InquirerQuestion](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md/#question)]_ |         | questions to ask the user                     |
| **actions**     | _Array[[ActionConfig](#interface-actionconfig)]_                                                                        |         | actions to perform                            |

> If your list of actions needs to be dynamic, take a look at [using a dynamic actions array.](#using-a-dynamic-actions-array)

### _Interface_ `PlopGenerator`

| Property       | Type       | Default | Description                                      |
| -------------- | ---------- | ------- | ------------------------------------------------ |
| **runPrompts** | _Function_ |         | a function to run the prompts within a generator |
| **runActions** | _Function_ |         | a function to run the actions within a generator |

> This interface also contains all properties from [GeneratorConfig](#interface-generatorconfig)

### _Interface_ `ActionConfig`

The following properties are the standard properties that plop handles internally. Other properties will be required depending on the _type_ of action. Also take a look at the [built-in actions](#built-in-actions).

| Property        | Type                | Default | Description                                                                                                        |
| --------------- | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------ |
| **type**        | _String_            |         | the type of action ([`add`](#add), [`modify`](#modify), [`addMany`](#addmany), [etc](#setactiontype))              |
| **force**       | _Boolean_           | `false` | performs the action [forcefully](#running-a-generator-forcefully) (means different things depending on the action) |
| **data**        | _Object / Function_ | `{}`    | specifies data that should be mixed with user prompt answers when running this action                              |
| **abortOnFail** | _Boolean_           | `true`  | if this action fails for any reason abort all future actions                                                       |
| **skip**        | _Function_          |         | an optional function that specifies if the action should run                                                       |

> The `data` property on any `ActionConfig` can also be a `Function` that returns an `Object` or a `Function` that returns a `Promise` that resolves with an `Object`.

> The `skip` function on any `ActionConfig` is optional and should return a string if the action should be skipped. The return value is the reason to skip the action.

> Instead of an Action Object, a [function can also be used](#custom-action-function)

## Other Methods

| Method                | Parameters       | Returns                                            | Description                                                                                                                                                    |
| --------------------- | ---------------- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **getHelper**         | _String_         | _Function_                                         | get the helper function                                                                                                                                        |
| **getHelperList**     |                  | _Array[String]_                                    | get a list of helper names                                                                                                                                     |
| **getPartial**        | _String_         | _String_                                           | get a handlebars partial by name                                                                                                                               |
| **getPartialList**    |                  | _Array[String]_                                    | get a list of partial names                                                                                                                                    |
| **getActionType**     | _String_         | _[CustomAction](#functionsignature-custom-action)_ | get an actionType by name                                                                                                                                      |
| **getActionTypeList** |                  | _Array[String]_                                    | get a list of actionType names                                                                                                                                 |
| **setWelcomeMessage** | _String_         |                                                    | Customizes the displayed message that asks you to choose a generator when you run `plop`.                                                                      |
| **getGenerator**      | _String_         | _[GeneratorConfig](#interface-generatorconfig)_    | get the [PlopGenerator](#interface-plopgenerator) by name                                                                                                      |
| **getGeneratorList**  |                  | _Array[Object]_                                    | gets an array of generator names and descriptions                                                                                                              |
| **setPlopfilePath**   | _String_         |                                                    | set the `plopfilePath` value which is used internally to locate resources like template files                                                                  |
| **getPlopfilePath**   |                  | _String_                                           | returns the absolute path to the plopfile in use                                                                                                               |
| **getDestBasePath**   |                  | _String_                                           | returns the base path that is used when creating files                                                                                                         |
| **setDefaultInclude** | _Object_         | _Object_                                           | sets the default config that will be used for this plopfile if it is consumed by another plopfile using `plop.load()`                                          |
| **getDefaultInclude** | _String_         | _Object_                                           | gets the default config that will be used for this plopfile if it is consumed by another plopfile using `plop.load()`                                          |
| **renderString**      | _String, Object_ | _String_                                           | Runs the first parameter (_String_) through the handlebars template renderer using the second parameter (_Object_) as the data. Returns the rendered template. |

# Built-In Actions

There are several types of built-in actions you can use in your [GeneratorConfig](#interface-generatorconfig). You specify which `type` of action (all paths are based on the location of the plopfile), and a template to use.

> The `Add`, `AddMany` and `Modify` actions have an optional `transform` method that can be used to transform the template result before it is written to disk. The `transform` function receives the template result or file contents as a `string` and the action data as arguments. It must return a `string` or a `Promise` that resolves to a `string`.

## Add

The `add` action is used to (you guessed it) add a file to your project. The path property is a handlebars template that will be used to create the file by name. The file contents will be determined by the `template` or `templateFile` property.

| Property         | Type       | Default | Description                                                                                                                 |
| ---------------- | ---------- | ------- | --------------------------------------------------------------------------------------------------------------------------- |
| **path**         | _String_   |         | a handlebars template that (when rendered) is the path of the new file                                                      |
| **template**     | _String_   |         | a handlebars template that should be used to build the new file                                                             |
| **templateFile** | _String_   |         | a path a file containing the `template`                                                                                     |
| **skipIfExists** | _Boolean_  | `false` | skips a file if it already exists (instead of failing)                                                                      |
| **transform**    | _Function_ |         | [an optional function](#built-in-actions) that can be used to transform the template result before writing the file to disk |
| **skip**         | _Function_ |         | _inherited from [ActionConfig](#interface-actionconfig)_                                                                    |
| **force**        | _Boolean_  | `false` | _inherited from [ActionConfig](#interface-actionconfig)_ (overwrites files if they exist)                                   |
| **data**         | _Object_   | `{}`    | _inherited from [ActionConfig](#interface-actionconfig)_                                                                    |
| **abortOnFail**  | _Boolean_  | `true`  | _inherited from [ActionConfig](#interface-actionconfig)_                                                                    |

## AddMany

The `addMany` action can be used to add multiple files to your project with a single action. The `destination` property is a handlebars template that will be used to identify the folder that the generated files should go into. The `base` property can be used to alter what section of the template paths should be omitted when creating files. The paths located by the `templateFiles` glob can use handlebars syntax in their file/folder names if you'd like the added file names to be unique (example: `{{ dashCase name }}.spec.js`).

| Property            | Type                                                               | Default   | Description                                                                                                                  |
| ------------------- | ------------------------------------------------------------------ | --------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **destination**     | _String_                                                           |           | a handlebars template that (when rendered) is the destination folder for the new files                                       |
| **base**            | _String_                                                           |           | the section of the path that should be excluded when adding files to the `destination` folder                                |
| **templateFiles**   | _[Glob](https://github.com/sindresorhus/globby#globbing-patterns)_ |           | glob pattern that matches multiple template files to be added                                                                |
| **stripExtensions** | _[String]_                                                         | `['hbs']` | file extensions that should be stripped from `templateFiles` files names while being added to the `destination`              |
| **globOptions**     | _[Object](https://github.com/sindresorhus/globby#options)_         |           | glob options that change how to match to the template files to be added                                                      |
| **verbose**         | _Boolean_                                                          | `true`    | print each successfully added file path                                                                                      |
| **transform**       | _Function_                                                         |           | [an optional function](#built-in-actions) that can be used to transform the template result before writing each file to disk |
| **skip**            | _Function_                                                         |           | _inherited from [ActionConfig](#interface-actionconfig)_                                                                     |
| **skipIfExists**    | _Boolean_                                                          | `false`   | _inherited from [Add](#add)_ (skips a file if it already exists)                                                             |
| **force**           | _Boolean_                                                          | `false`   | _inherited from [ActionConfig](#interface-actionconfig)_ (overwrites files if they exist)                                    |
| **data**            | _Object_                                                           | `{}`      | _inherited from [ActionConfig](#interface-actionconfig)_                                                                     |
| **abortOnFail**     | _Boolean_                                                          | `true`    | _inherited from [ActionConfig](#interface-actionconfig)_                                                                     |

## Modify

The `modify` action can be used two ways. You can use a `pattern` property to find/replace text in the file located at the `path` specified, or you can use a `transform` function to transform the file contents. Both `pattern` and `transform` can be used at the same time (`transform` will happen last). More details on modify can be found in the example folder.

| Property         | Type       | Default                     | Description                                                                                                            |
| ---------------- | ---------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **path**         | _String_   |                             | handlebars template that (when rendered) is the path of the file to be modified                                        |
| **pattern**      | _RegExp_   | _end&#x2011;of&#x2011;file_ | regular expression used to match text that should be replaced                                                          |
| **template**     | _String_   |                             | handlebars template that should replace what was matched by the `pattern`. capture groups are available as $1, $2, etc |
| **templateFile** | _String_   |                             | path a file containing the `template`                                                                                  |
| **transform**    | _Function_ |                             | [an optional function](#built-in-actions) that can be used to transform the file before writing it to disk             |
| **skip**         | _Function_ |                             | _inherited from [ActionConfig](#interface-actionconfig)_                                                               |
| **data**         | _Object_   | `{}`                        | _inherited from [ActionConfig](#interface-actionconfig)_                                                               |
| **abortOnFail**  | _Boolean_  | `true`                      | _inherited from [ActionConfig](#interface-actionconfig)_                                                               |

## Append

The `append` action is a commonly used subset of `modify`. It is used to append data in a file at a particular location.

| Property         | Type             | Default    | Description                                                                     |
| ---------------- | ---------------- | ---------- | ------------------------------------------------------------------------------- |
| **path**         | _String_         |            | handlebars template that (when rendered) is the path of the file to be modified |
| **pattern**      | _RegExp, String_ |            | regular expression used to match text where the append should happen            |
| **unique**       | _Boolean_        | `true`     | whether identical entries should be removed                                     |
| **separator**    | _String_         | `new line` | the value that separates entries                                                |
| **template**     | _String_         |            | handlebars template to be used for the entry                                    |
| **templateFile** | _String_         |            | path a file containing the `template`                                           |
| **data**         | _Object_         | `{}`       | _inherited from [ActionConfig](#interface-actionconfig)_                        |
| **abortOnFail**  | _Boolean_        | `true`     | _inherited from [ActionConfig](#interface-actionconfig)_                        |

## Custom (Action Function)

The `Add` and `Modify` actions will take care of almost every case that plop is designed to handle. However, plop does offer custom action functions for the node/js guru. A custom action function is a function that is provided in the actions array.

- Custom action functions are executed by plop with the same [CustomAction](#functionsignature-custom-action) function signature.
- Plop will wait for the custom action to complete before executing the next action.
- The function must let plop known what’s happening through the return value. If you return a `Promise`, we won’t start other actions until the promise resolves. If you return a message (_String_), we know that the action is done and we’ll report the message in the status of the action.
- A custom action fails if the promise is rejected, or the function throws an `Exception`

_See the [example plopfile](https://github.com/plopjs/plop/blob/main/packages/plop/tests/examples/javascript/plopfile.js) for a sample synchronous custom action._

## Comments

Comment lines can be added to the actions array by adding a string in place of an action config object. Comments are printed to the screen when plop comes to them and have no functionality of their own.

# Built-In Helpers

There are a few helpers that I have found useful enough to include with plop. They are mostly case modifiers, but here is the complete list.

## Case Modifiers

- **camelCase**: changeFormatToThis
- **snakeCase**: change_format_to_this
- **dashCase/kebabCase**: change-format-to-this
- **dotCase**: change.format.to.this
- **pathCase**: change/format/to/this
- **properCase/pascalCase**: ChangeFormatToThis
- **lowerCase**: change format to this
- **sentenceCase**: Change format to this,
- **constantCase**: CHANGE_FORMAT_TO_THIS
- **titleCase**: Change Format To This

## Other Helpers

- **pkg**: look up a property from a package.json file in the same folder as the plopfile.

# Taking it Further

There is not a lot needed to get up and running on some basic generators. However, if you want to take your plop-fu further, read on young padawan.

## Using a Dynamic Actions Array

Alternatively, the `actions` property of the [GeneratorConfig](#interface-generatorconfig) can itself be a function that takes the answers data as a parameter and returns the actions array.

This allows you to adapt the actions array based on provided answers:

```javascript
export default function (plop) {
  plop.setGenerator("test", {
    prompts: [
      {
        type: "confirm",
        name: "wantTacos",
        message: "Do you want tacos?",
      },
    ],
    actions: function (data) {
      var actions = [];

      if (data.wantTacos) {
        actions.push({
          type: "add",
          path: "folder/{{dashCase name}}.txt",
          templateFile: "templates/tacos.txt",
        });
      } else {
        actions.push({
          type: "add",
          path: "folder/{{dashCase name}}.txt",
          templateFile: "templates/burritos.txt",
        });
      }

      return actions;
    },
  });
}
```

## 3rd Party Prompt Bypass

If you have written an inquirer prompt plugin and want to support plop's bypass functionality, the process is pretty simple. The plugin object that your prompt exports should have a `bypass` function. This `bypass` function will be run by plop with the user's input as the first parameter and the prompt config object as the second parameter. The value that this function returns will be added to the answer data object for that prompt.

```javascript
// My confirmation inquirer plugin
export default MyConfirmPluginConstructor;
function MyConfirmPluginConstructor() {
  // ...your main plugin code
  this.bypass = (rawValue, promptConfig) => {
    const lowerVal = rawValue.toString().toLowerCase();
    const trueValues = ["t", "true", "y", "yes"];
    const falseValues = ["f", "false", "n", "no"];
    if (trueValues.includes(lowerVal)) return true;
    if (falseValues.includes(lowerVal)) return false;
    throw Error(`"${rawValue}" is not a valid ${promptConfig.type} value`);
  };
  return this;
}
```

> For the above example, the bypass function takes the user's text input and turns it into a `Boolean` value that will be used as the prompt answer data.

### Adding Bypass Support to Your Plopfile

If the 3rd party prompt plugin you are using does not support bypass by default, you can add the `bypass` function above to your prompt's config object and plop will use it for handling bypass data for that prompt.

## Wrapping Plop

Plop provides a lot of powerful functionality "for free". This utility is so powerful, in fact, that you can even wrap `plop`
into your own CLI project. To do so, you only need a `plopfile.js`, a `package.json`, and a template to reference.

Your `index.js` file should look like the following:

```javascript
#!/usr/bin/env node
import path from "node:path";
import minimist from "minimist";
import { Plop, run } from "plop";

const args = process.argv.slice(2);
const argv = minimist(args);

import { dirname } from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = dirname(fileURLToPath(import.meta.url));

Plop.prepare(
  {
    cwd: argv.cwd,
    configPath: path.join(__dirname, "plopfile.js"),
    preload: argv.preload || [],
    completion: argv.completion,
  },
  (env) => Plop.execute(env, run),
);
```

And your `package.json` should look like the following:

```json
{
  "name": "create-your-name-app",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "plop"
  },
  "bin": {
    "create-your-name-app": "./index.js"
  },
  "preferGlobal": true,
  "dependencies": {
    "plop": "^3.0.0"
  }
}
```

### Setting the base destination path for the wrapper

When wrapping plop, you might want to have the destination path to be based on the cwd when running the wrapper. You can configure the `dest` base path like this:

```javascript
Plop.prepare(
  {
    // config like above
  },
  (env) =>
    Plop.execute(env, (env) => {
      const options = {
        ...env,
        dest: process.cwd(), // this will make the destination path to be based on the cwd when calling the wrapper
      };
      return run(options, undefined, true);
    }),
);
```

### Adding General CLI Actions

Many CLI utilities handle some actions for you, such as running `git init` or `npm install` once the template is generated.

While we'd like to provide these actions, we also want to keep the core actions limited in scope. As such, we maintain a collection of libraries built to add these actions to Plop in [our Awesome Plop list](https://github.com/plopjs/awesome-plop). There, you'll be able to find options for those actions, or even build your own and add it to the list!

### Further Customization

While `plop` provides a great level of customization for CLI utility wrappers, there may be usecases where you simply
want more control over the CLI experience while also utilizing the template generation code.

Luckily, [`node-plop`](https://github.com/plopjs/node-plop/) may be for you! It's what the `plop` CLI itself is built
upon and can be easily extended for other usage in the CLI. However, be warned, documentation is not quite as fleshed out
for integration with `node-plop`. That is to say `Thar be dragons`.

> We note lackluster documentation on `node-plop` integration not as a point of pride, but rather a word of warning.
> If you'd like to contribute documentation to the project, please do so! We always welcome and encourage contributions!

---

## File: packages/plop/README.md

# Plop

Micro-generator framework that makes it easy for an entire team to create files with a level of uniformity.


> [Documentation also available on plopjs.com](https://plopjs.com/documentation/)

# Getting Started

[](https://www.npmjs.com/package/plop)
&nbsp;
[](https://www.npmjs.com/package/plop)

## What is Plop?

Plop is what I like to call a "micro-generator framework." Now, I call it that because it is a small tool that gives you a simple way to generate code or any other type of flat text files in a consistent way. You see, we all create structures and patterns in our code (routes, controllers, components, helpers, etc). These patterns change and improve over time so when you need to create a NEW _insert-name-of-pattern-here_, it's not always easy to locate the files in your codebase that represent the current "best practice." That's where plop saves you. With plop, you have your "best practice" method of creating any given pattern in CODE. Code that can easily be run from the terminal by typing `plop`. Not only does this save you from hunting around in your codebase for the right files to copy, but it also turns "the right way" into "the easiest way" to make new files.

If you boil plop down to its core, it is basically glue code between [inquirer](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md) prompts and [handlebar](https://github.com/wycats/handlebars.js/) templates.

> This documentation is a work in progress. If you have great ideas, I'd love to hear them.

## Installation

### 1. Add plop to your project

```
$ npm install --save-dev plop
```

### 2. Install plop globally (optional, but recommended for easy access)

```
$ npm install plop
```

### 3. Create a plopfile.js at the root of your project

```javascript
export default function (plop) {
  // create your generators here
  plop.setGenerator("basics", {
    prompts: [], // array of inquirer prompts
    actions: [], // array of actions
  });
}
```

> `export default` is only allowed in NodeJS inside "ESM" supported files.
> To use this syntax, your `plopfile` must be either:
>
> - An ESM .js file with type: "module" in package.json
> - An ESM .mjs file with any type declared in package.json
>
> Alternatively, you can have a `plopfile` with `module.exports = function (plop)` instead.
> For _this_ syntax, your `plopfile` must be either:
>
> - A CommonJS .js file with type: "commonjs" in package.json
> - A CommonJS .cjs file with any type declared in package.json

## Your First Plopfile

A plopfile starts its life as a node module that exports a function which accepts the `plop` object as its first parameter.

```javascript
export default function (plop) {}
```

The `plop` object exposes the plop API object which contains the `setGenerator(name, config)` function. This is the function that you use to (wait for it) create a generator for this plopfile. When `plop` is run from the terminal in this directory (or any sub-directory), a list of these generators will be displayed.

Let's try setting up a basic generator to see how that looks.

```javascript
export default function (plop) {
  // controller generator
  plop.setGenerator("controller", {
    prompts: [
      {
        type: "input",
        name: "name",
        message: "controller name please",
      },
    ],
    actions: [
      {
        type: "add",
        path: "src/{{name}}.js",
        templateFile: "plop-templates/controller.hbs",
      },
    ],
  });
}
```

The _controller_ generator we created above will ask us 1 question, and create 1 file. This can be expanded to ask as many questions as needed, and create as many files as needed. There are also additional actions that can be used to alter our codebase in different ways.

## Using Prompts

Plop uses the [inquirer.js](https://github.com/SBoudrias/Inquirer.js) library to gather user data. A list of [prompt types](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md#prompt-types) can be found on the inquirer official website.

## CLI Usage

Once plop is installed, and you have created a generator, you are ready to run plop from the terminal. Running `plop` with no parameters will present you with a list of generators to pick from. You can also run `plop [generatorName]` to trigger a generator directly. If you did not install plop globally, you will need to setup an npm script to run plop for you.

```javascript
// package.json
{
    ...,
    "scripts": {
        "plop": "plop"
    },
    ...
}
```

### Bypassing Prompts

Once you get to know a project (and its generators) well, you may want to provide answers to the prompts when you run the generator. If I have (for instance) a `component` generator that has one prompt (name), I can run that generator using `plop component "some component name"` and it will immediately execute as though I had typed "some component name" into the prompt. If that same generator had a second prompt, the same input would have resulted in the user being prompted for the second value.

Prompts like `confirm` and `list` try to make sense of your input as best they can. For instance entering "y", "yes", "t", or "true" for a confirm prompt will result in a boolean `true` value. You can select items from a list using their value, index, key, or name. Checkbox prompts can accept a comma separated list of values in order to select multiples.



> If you want to provide bypass input for the second prompt but not the first, you can use an underscore "\_" to skip the bypass (ie `plop component _ "input for second prompt"`).

Plop comes with bypass logic built-in for standard inquirer prompts, but there are also ways to provide custom logic for how to handle user input for a specific prompt.

If you have published a 3rd party inquirer prompt plugin and would like to support bypass functionality for plop users out of the box, that is covered in [another section of this documentation](#3rd-party-prompt-bypass).

### Bypassing Prompts (by Name)

You can also bypass prompts by name using `--` and then providing arguments for each prompt that you'd like to bypass. Examples [below](#bypass-examples).

#### Bypass Examples

```
## Bypassing both prompt 1 and 2
$ plop component "my component" react
$ plop component -- --name "my component" --type react

## Bypassing only prompt 2 (will be prompted for name)
$ plop component _ react
$ plop component -- --type react
```

### Running a Generator Forcefully

By default Plop actions keep your files safe by failing when things look fishy. The most obvious example of this is not allowing an [`add`](#add) action to overwrite a file that already exists. Plop actions individually support the `force` property but you can also use the `--force` flag when running Plop from the terminal. Using the `--force` flag will tell every action to run forcefully. With great power...🕷

### Using TypeScript plopfiles

#### Node.js v22.18+**

Modern Node.js supports TypeScript files [out-of-the-box](https://nodejs.org/docs/latest/api/typescript.html). No extra setup or CLI flags are required to use a TypeScript plopfile. 

First, make a TypesScript plopfile using `plop --init-ts` or by hand:

```ts
// plopfile.ts
import { NodePlopAPI } from "plop";

export default function (plop: NodePlopAPI) {
  // plop generator code
}
```

Second, add `plop` to `scripts` in `package.json`:

```json
// package.json
"scripts": {
  "plop" : "plop"
}
```

#### Older Node.js Versions**

Plop bundles TypeScript declarations and supports TypeScript plopfiles via [tsx loaders](https://github.com/privatenumber/tsx?tab=readme-ov-file#nodejs-loader), a feature of [NodeJS command line imports](https://nodejs.org/api/cli.html#--importmodule).

First, make a TypesScript plopfile using `plop --init-ts` or by hand:

```ts
// plopfile.ts
import { NodePlopAPI } from "plop";

export default function (plop: NodePlopAPI) {
  // plop generator code
}
```

Next, install [tsx](https://github.com/privatenumber/tsx) and optionally [cross-env](https://www.npmjs.com/package/cross-env):

```bash
npm i -D tsx cross-env
```

Finally, use `NODE_OPTIONS` to activate the tsx loader. Now Plop can import your `plopfile.ts`:

**Node.js v20.6 and above**

```json
// package.json
"scripts": {
  "plop" : "cross-env NODE_OPTIONS='--import tsx' plop --plopfile=plopfile.ts"
}
```

**Node.js v20.5.1 and below**

```json
// package.json
"scripts": {
  "plop": "cross-env NODE_OPTIONS='--loader tsx' plop --plopfile=plopfile.ts"
}
```

## Why Generators?

Because when you create your boilerplate separate from your code, you naturally put more time and thought into it.

Because saving your team (or yourself) 5-15 minutes when creating every route, component, controller, helper, test, view, etc... [really adds up](https://xkcd.com/1205/).

Because [context switching is expensive](https://www.petrikainulainen.net/software-development/processes/the-cost-of-context-switching/) and saving time is not the only [benefit to automating workflows](https://kentcdodds.com/blog/automation)

# Plopfile API

The plopfile api is the collection of methods that are exposed by the `plop` object. Most of the work is done by [`setGenerator`](#setgenerator) but this section documents the other methods that you may also find useful in your plopfile.

## TypeScript Support

Plop bundles TypeScript declarations. See [using TypeScript plopfiles](#using-typescript-plopfiles) for more details.

## JSDoc Support

Whether or not you write your plopfile in TypeScript, many editors will offer code assistance via JSDoc declarations.

```javascript
// plopfile.js
export default function (
  /** @type {import('plop').NodePlopAPI} */
  plop,
) {
  // plop generator code
}
```

## Main Methods

These are the methods you will commonly use when creating a plopfile. Other methods that are mostly for internal use are list in the [other methods](#other-methods) section.

| Method                                                            | Parameters                                                 | Returns                                     | Description                                                                   |
| ----------------------------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------- | ----------------------------------------------------------------------------- |
| [**setGenerator**](#setgenerator)                                 | _String, [GeneratorConfig](#interface-generatorconfig)_    | _[PlopGenerator](#interface-plopgenerator)_ | setup a generator                                                             |
| [**setHelper**](#sethelper)                                       | _String, Function_                                         |                                             | setup handlebars helper                                                       |
| [**setPartial**](#setpartial)                                     | _String, String_                                           |                                             | setup a handlebars partial                                                    |
| [**setActionType**](#setactiontype)                               | _String, [CustomAction](#functionsignature-custom-action)_ |                                             | register a custom action type                                                 |
| [**setPrompt**](#setprompt)                                       | _String, InquirerPrompt_                                   |                                             | registers a custom prompt type with inquirer                                  |
| [**load**](https://github.com/plopjs/plop/blob/main/plop-load.md) | _Array[String], Object, Object_                            |                                             | loads generators, helpers and/or partials from another plopfile or npm module |

## setHelper

`setHelper` directly corresponds to the handlebars method `registerHelper`. So if you are familiar with [handlebars helpers](https://handlebarsjs.com/guide/expressions.html#helpers), then you already know how this works.

```javascript
export default function (plop) {
  plop.setHelper("upperCase", function (text) {
    return text.toUpperCase();
  });

  // or in es6/es2015
  plop.setHelper("upperCase", (txt) => txt.toUpperCase());
}
```

## setPartial

`setPartial` directly corresponds to the handlebars method `registerPartial`. So if you are familiar with [handlebars partials](https://handlebarsjs.com/guide/partials.html), then you already know how this works.

```javascript
export default function (plop) {
  plop.setPartial("myTitlePartial", "<h1>{{titleCase name}}</h1>");
  // used in template as {{> myTitlePartial }}
}
```

## setActionType

`setActionType` allows you to create your own actions (similar to `add` or `modify`) that can be used in your plopfiles. These are basically highly reusable [custom action function](#custom-action-function)s.

### _FunctionSignature_ Custom Action

| Parameters  | Type                                      | Description                                                  |
| ----------- | ----------------------------------------- | ------------------------------------------------------------ |
| **answers** | _Object_                                  | Answers to the generator prompts                             |
| **config**  | _[ActionConfig](#interface-actionconfig)_ | The object in the "actions" array for the generator          |
| **plop**    | _[PlopfileApi](#plopfile-api)_            | The plop api for the plopfile where this action is being run |

```javascript
export default function (plop) {
  plop.setActionType("doTheThing", function (answers, config, plop) {
    // do something
    doSomething(config.configProp);
    // if something went wrong
    throw "error message";
    // otherwise
    return "success status message";
  });

  // or do async things inside of an action
  plop.setActionType("doTheAsyncThing", function (answers, config, plop) {
    // do something
    return new Promise((resolve, reject) => {
      if (success) {
        resolve("success status message");
      } else {
        reject("error message");
      }
    });
  });

  // use the custom action
  plop.setGenerator("test", {
    prompts: [],
    actions: [
      {
        type: "doTheThing",
        configProp: "available from the config param",
      },
      {
        type: "doTheAsyncThing",
        speed: "slow",
      },
    ],
  });
}
```

## setPrompt

[Inquirer](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md) provides many types of prompts out of the box, but it also allows developers to build prompt plugins. If you'd like to use a prompt plugin, you can register it with `setPrompt`. For more details see the [Inquirer documentation for registering prompts](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md#inquirerregisterpromptname-prompt). Also check out the [plop community driven list of custom prompts](https://github.com/plopjs/awesome-plop#inquirer-prompts).

```javascript
import autocompletePrompt from 'inquirer-autocomplete-prompt';
export default function (plop) {
	plop.setPrompt('autocomplete', autocompletePrompt);
	plop.setGenerator('test', {
		prompts: [{
			type: 'autocomplete',
			...
		}]
	});
};
```

## setGenerator

The config object needs to include `prompts` and `actions` (`description` is optional). The prompts array is passed to [inquirer](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md/#objects). The `actions` array is a list of actions to take (described in greater detail below)

### _Interface_ `GeneratorConfig`

| Property        | Type                                                                                                                    | Default | Description                                   |
| --------------- | ----------------------------------------------------------------------------------------------------------------------- | ------- | --------------------------------------------- |
| **description** | _[String]_                                                                                                              |         | short description of what this generator does |
| **prompts**     | _Array[[InquirerQuestion](https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/README.md/#question)]_ |         | questions to ask the user                     |
| **actions**     | _Array[[ActionConfig](#interface-actionconfig)]_                                                                        |         | actions to perform                            |

> If your list of actions needs to be dynamic, take a look at [using a dynamic actions array.](#using-a-dynamic-actions-array)

### _Interface_ `PlopGenerator`

| Property       | Type       | Default | Description                                      |
| -------------- | ---------- | ------- | ------------------------------------------------ |
| **runPrompts** | _Function_ |         | a function to run the prompts within a generator |
| **runActions** | _Function_ |         | a function to run the actions within a generator |

> This interface also contains all properties from [GeneratorConfig](#interface-generatorconfig)

### _Interface_ `ActionConfig`

The following properties are the standard properties that plop handles internally. Other properties will be required depending on the _type_ of action. Also take a look at the [built-in actions](#built-in-actions).

| Property        | Type                | Default | Description                                                                                                        |
| --------------- | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------ |
| **type**        | _String_            |         | the type of action ([`add`](#add), [`modify`](#modify), [`addMany`](#addmany), [etc](#setactiontype))              |
| **force**       | _Boolean_           | `false` | performs the action [forcefully](#running-a-generator-forcefully) (means different things depending on the action) |
| **data**        | _Object / Function_ | `{}`    | specifies data that should be mixed with user prompt answers when running this action                              |
| **abortOnFail** | _Boolean_           | `true`  | if this action fails for any reason abort all future actions                                                       |
| **skip**        | _Function_          |         | an optional function that specifies if the action should run                                                       |

> The `data` property on any `ActionConfig` can also be a `Function` that returns an `Object` or a `Function` that returns a `Promise` that resolves with an `Object`.

> The `skip` function on any `ActionConfig` is optional and should return a string if the action should be skipped. The return value is the reason to skip the action.

> Instead of an Action Object, a [function can also be used](#custom-action-function)

## Other Methods

| Method                | Parameters       | Returns                                            | Description                                                                                                                                                    |
| --------------------- | ---------------- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **getHelper**         | _String_         | _Function_                                         | get the helper function                                                                                                                                        |
| **getHelperList**     |                  | _Array[String]_                                    | get a list of helper names                                                                                                                                     |
| **getPartial**        | _String_         | _String_                                           | get a handlebars partial by name                                                                                                                               |
| **getPartialList**    |                  | _Array[String]_                                    | get a list of partial names                                                                                                                                    |
| **getActionType**     | _String_         | _[CustomAction](#functionsignature-custom-action)_ | get an actionType by name                                                                                                                                      |
| **getActionTypeList** |                  | _Array[String]_                                    | get a list of actionType names                                                                                                                                 |
| **setWelcomeMessage** | _String_         |                                                    | Customizes the displayed message that asks you to choose a generator when you run `plop`.                                                                      |
| **getGenerator**      | _String_         | _[GeneratorConfig](#interface-generatorconfig)_    | get the [PlopGenerator](#interface-plopgenerator) by name                                                                                                      |
| **getGeneratorList**  |                  | _Array[Object]_                                    | gets an array of generator names and descriptions                                                                                                              |
| **setPlopfilePath**   | _String_         |                                                    | set the `plopfilePath` value which is used internally to locate resources like template files                                                                  |
| **getPlopfilePath**   |                  | _String_                                           | returns the absolute path to the plopfile in use                                                                                                               |
| **getDestBasePath**   |                  | _String_                                           | returns the base path that is used when creating files                                                                                                         |
| **setDefaultInclude** | _Object_         | _Object_                                           | sets the default config that will be used for this plopfile if it is consumed by another plopfile using `plop.load()`                                          |
| **getDefaultInclude** | _String_         | _Object_                                           | gets the default config that will be used for this plopfile if it is consumed by another plopfile using `plop.load()`                                          |
| **renderString**      | _String, Object_ | _String_                                           | Runs the first parameter (_String_) through the handlebars template renderer using the second parameter (_Object_) as the data. Returns the rendered template. |

# Built-In Actions

There are several types of built-in actions you can use in your [GeneratorConfig](#interface-generatorconfig). You specify which `type` of action (all paths are based on the location of the plopfile), and a template to use.

> The `Add`, `AddMany` and `Modify` actions have an optional `transform` method that can be used to transform the template result before it is written to disk. The `transform` function receives the template result or file contents as a `string` and the action data as arguments. It must return a `string` or a `Promise` that resolves to a `string`.

## Add

The `add` action is used to (you guessed it) add a file to your project. The path property is a handlebars template that will be used to create the file by name. The file contents will be determined by the `template` or `templateFile` property.

| Property         | Type       | Default | Description                                                                                                                 |
| ---------------- | ---------- | ------- | --------------------------------------------------------------------------------------------------------------------------- |
| **path**         | _String_   |         | a handlebars template that (when rendered) is the path of the new file                                                      |
| **template**     | _String_   |         | a handlebars template that should be used to build the new file                                                             |
| **templateFile** | _String_   |         | a path a file containing the `template`                                                                                     |
| **skipIfExists** | _Boolean_  | `false` | skips a file if it already exists (instead of failing)                                                                      |
| **transform**    | _Function_ |         | [an optional function](#built-in-actions) that can be used to transform the template result before writing the file to disk |
| **skip**         | _Function_ |         | _inherited from [ActionConfig](#interface-actionconfig)_                                                                    |
| **force**        | _Boolean_  | `false` | _inherited from [ActionConfig](#interface-actionconfig)_ (overwrites files if they exist)                                   |
| **data**         | _Object_   | `{}`    | _inherited from [ActionConfig](#interface-actionconfig)_                                                                    |
| **abortOnFail**  | _Boolean_  | `true`  | _inherited from [ActionConfig](#interface-actionconfig)_                                                                    |

## AddMany

The `addMany` action can be used to add multiple files to your project with a single action. The `destination` property is a handlebars template that will be used to identify the folder that the generated files should go into. The `base` property can be used to alter what section of the template paths should be omitted when creating files. The paths located by the `templateFiles` glob can use handlebars syntax in their file/folder names if you'd like the added file names to be unique (example: `{{ dashCase name }}.spec.js`).

| Property            | Type                                                               | Default   | Description                                                                                                                  |
| ------------------- | ------------------------------------------------------------------ | --------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **destination**     | _String_                                                           |           | a handlebars template that (when rendered) is the destination folder for the new files                                       |
| **base**            | _String_                                                           |           | the section of the path that should be excluded when adding files to the `destination` folder                                |
| **templateFiles**   | _[Glob](https://github.com/sindresorhus/globby#globbing-patterns)_ |           | glob pattern that matches multiple template files to be added                                                                |
| **stripExtensions** | _[String]_                                                         | `['hbs']` | file extensions that should be stripped from `templateFiles` files names while being added to the `destination`              |
| **globOptions**     | _[Object](https://github.com/sindresorhus/globby#options)_         |           | glob options that change how to match to the template files to be added                                                      |
| **verbose**         | _Boolean_                                                          | `true`    | print each successfully added file path                                                                                      |
| **transform**       | _Function_                                                         |           | [an optional function](#built-in-actions) that can be used to transform the template result before writing each file to disk |
| **skip**            | _Function_                                                         |           | _inherited from [ActionConfig](#interface-actionconfig)_                                                                     |
| **skipIfExists**    | _Boolean_                                                          | `false`   | _inherited from [Add](#add)_ (skips a file if it already exists)                                                             |
| **force**           | _Boolean_                                                          | `false`   | _inherited from [ActionConfig](#interface-actionconfig)_ (overwrites files if they exist)                                    |
| **data**            | _Object_                                                           | `{}`      | _inherited from [ActionConfig](#interface-actionconfig)_                                                                     |
| **abortOnFail**     | _Boolean_                                                          | `true`    | _inherited from [ActionConfig](#interface-actionconfig)_                                                                     |

## Modify

The `modify` action can be used two ways. You can use a `pattern` property to find/replace text in the file located at the `path` specified, or you can use a `transform` function to transform the file contents. Both `pattern` and `transform` can be used at the same time (`transform` will happen last). More details on modify can be found in the example folder.

| Property         | Type       | Default                     | Description                                                                                                            |
| ---------------- | ---------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **path**         | _String_   |                             | handlebars template that (when rendered) is the path of the file to be modified                                        |
| **pattern**      | _RegExp_   | _end&#x2011;of&#x2011;file_ | regular expression used to match text that should be replaced                                                          |
| **template**     | _String_   |                             | handlebars template that should replace what was matched by the `pattern`. capture groups are available as $1, $2, etc |
| **templateFile** | _String_   |                             | path a file containing the `template`                                                                                  |
| **transform**    | _Function_ |                             | [an optional function](#built-in-actions) that can be used to transform the file before writing it to disk             |
| **skip**         | _Function_ |                             | _inherited from [ActionConfig](#interface-actionconfig)_                                                               |
| **data**         | _Object_   | `{}`                        | _inherited from [ActionConfig](#interface-actionconfig)_                                                               |
| **abortOnFail**  | _Boolean_  | `true`                      | _inherited from [ActionConfig](#interface-actionconfig)_                                                               |

## Append

The `append` action is a commonly used subset of `modify`. It is used to append data in a file at a particular location.

| Property         | Type             | Default    | Description                                                                     |
| ---------------- | ---------------- | ---------- | ------------------------------------------------------------------------------- |
| **path**         | _String_         |            | handlebars template that (when rendered) is the path of the file to be modified |
| **pattern**      | _RegExp, String_ |            | regular expression used to match text where the append should happen            |
| **unique**       | _Boolean_        | `true`     | whether identical entries should be removed                                     |
| **separator**    | _String_         | `new line` | the value that separates entries                                                |
| **template**     | _String_         |            | handlebars template to be used for the entry                                    |
| **templateFile** | _String_         |            | path a file containing the `template`                                           |
| **data**         | _Object_         | `{}`       | _inherited from [ActionConfig](#interface-actionconfig)_                        |
| **abortOnFail**  | _Boolean_        | `true`     | _inherited from [ActionConfig](#interface-actionconfig)_                        |

## Custom (Action Function)

The `Add` and `Modify` actions will take care of almost every case that plop is designed to handle. However, plop does offer custom action functions for the node/js guru. A custom action function is a function that is provided in the actions array.

- Custom action functions are executed by plop with the same [CustomAction](#functionsignature-custom-action) function signature.
- Plop will wait for the custom action to complete before executing the next action.
- The function must let plop known what’s happening through the return value. If you return a `Promise`, we won’t start other actions until the promise resolves. If you return a message (_String_), we know that the action is done and we’ll report the message in the status of the action.
- A custom action fails if the promise is rejected, or the function throws an `Exception`

_See the [example plopfile](https://github.com/plopjs/plop/blob/main/packages/plop/tests/examples/javascript/plopfile.js) for a sample synchronous custom action._

## Comments

Comment lines can be added to the actions array by adding a string in place of an action config object. Comments are printed to the screen when plop comes to them and have no functionality of their own.

# Built-In Helpers

There are a few helpers that I have found useful enough to include with plop. They are mostly case modifiers, but here is the complete list.

## Case Modifiers

- **camelCase**: changeFormatToThis
- **snakeCase**: change_format_to_this
- **dashCase/kebabCase**: change-format-to-this
- **dotCase**: change.format.to.this
- **pathCase**: change/format/to/this
- **properCase/pascalCase**: ChangeFormatToThis
- **lowerCase**: change format to this
- **sentenceCase**: Change format to this,
- **constantCase**: CHANGE_FORMAT_TO_THIS
- **titleCase**: Change Format To This

## Other Helpers

- **pkg**: look up a property from a package.json file in the same folder as the plopfile.

# Taking it Further

There is not a lot needed to get up and running on some basic generators. However, if you want to take your plop-fu further, read on young padawan.

## Using a Dynamic Actions Array

Alternatively, the `actions` property of the [GeneratorConfig](#interface-generatorconfig) can itself be a function that takes the answers data as a parameter and returns the actions array.

This allows you to adapt the actions array based on provided answers:

```javascript
export default function (plop) {
  plop.setGenerator("test", {
    prompts: [
      {
        type: "confirm",
        name: "wantTacos",
        message: "Do you want tacos?",
      },
    ],
    actions: function (data) {
      var actions = [];

      if (data.wantTacos) {
        actions.push({
          type: "add",
          path: "folder/{{dashCase name}}.txt",
          templateFile: "templates/tacos.txt",
        });
      } else {
        actions.push({
          type: "add",
          path: "folder/{{dashCase name}}.txt",
          templateFile: "templates/burritos.txt",
        });
      }

      return actions;
    },
  });
}
```

## 3rd Party Prompt Bypass

If you have written an inquirer prompt plugin and want to support plop's bypass functionality, the process is pretty simple. The plugin object that your prompt exports should have a `bypass` function. This `bypass` function will be run by plop with the user's input as the first parameter and the prompt config object as the second parameter. The value that this function returns will be added to the answer data object for that prompt.

```javascript
// My confirmation inquirer plugin
export default MyConfirmPluginConstructor;
function MyConfirmPluginConstructor() {
  // ...your main plugin code
  this.bypass = (rawValue, promptConfig) => {
    const lowerVal = rawValue.toString().toLowerCase();
    const trueValues = ["t", "true", "y", "yes"];
    const falseValues = ["f", "false", "n", "no"];
    if (trueValues.includes(lowerVal)) return true;
    if (falseValues.includes(lowerVal)) return false;
    throw Error(`"${rawValue}" is not a valid ${promptConfig.type} value`);
  };
  return this;
}
```

> For the above example, the bypass function takes the user's text input and turns it into a `Boolean` value that will be used as the prompt answer data.

### Adding Bypass Support to Your Plopfile

If the 3rd party prompt plugin you are using does not support bypass by default, you can add the `bypass` function above to your prompt's config object and plop will use it for handling bypass data for that prompt.

## Wrapping Plop

Plop provides a lot of powerful functionality "for free". This utility is so powerful, in fact, that you can even wrap `plop`
into your own CLI project. To do so, you only need a `plopfile.js`, a `package.json`, and a template to reference.

Your `index.js` file should look like the following:

```javascript
#!/usr/bin/env node
import path from "node:path";
import minimist from "minimist";
import { Plop, run } from "plop";

const args = process.argv.slice(2);
const argv = minimist(args);

import { dirname } from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = dirname(fileURLToPath(import.meta.url));

Plop.prepare(
  {
    cwd: argv.cwd,
    configPath: path.join(__dirname, "plopfile.js"),
    preload: argv.preload || [],
    completion: argv.completion,
  },
  (env) => Plop.execute(env, run),
);
```

And your `package.json` should look like the following:

```json
{
  "name": "create-your-name-app",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "plop"
  },
  "bin": {
    "create-your-name-app": "./index.js"
  },
  "preferGlobal": true,
  "dependencies": {
    "plop": "^3.0.0"
  }
}
```

### Setting the base destination path for the wrapper

When wrapping plop, you might want to have the destination path to be based on the cwd when running the wrapper. You can configure the `dest` base path like this:

```javascript
Plop.prepare(
  {
    // config like above
  },
  (env) =>
    Plop.execute(env, (env) => {
      const options = {
        ...env,
        dest: process.cwd(), // this will make the destination path to be based on the cwd when calling the wrapper
      };
      return run(options, undefined, true);
    }),
);
```

### Adding General CLI Actions

Many CLI utilities handle some actions for you, such as running `git init` or `npm install` once the template is generated.

While we'd like to provide these actions, we also want to keep the core actions limited in scope. As such, we maintain a collection of libraries built to add these actions to Plop in [our Awesome Plop list](https://github.com/plopjs/awesome-plop). There, you'll be able to find options for those actions, or even build your own and add it to the list!

### Further Customization

While `plop` provides a great level of customization for CLI utility wrappers, there may be usecases where you simply
want more control over the CLI experience while also utilizing the template generation code.

Luckily, [`node-plop`](https://github.com/plopjs/node-plop/) may be for you! It's what the `plop` CLI itself is built
upon and can be easily extended for other usage in the CLI. However, be warned, documentation is not quite as fleshed out
for integration with `node-plop`. That is to say `Thar be dragons`.

> We note lackluster documentation on `node-plop` integration not as a point of pride, but rather a word of warning.
> If you'd like to contribute documentation to the project, please do so! We always welcome and encourage contributions!

---

## File: packages/node-plop/README.md

# Node-Plop

[](https://www.npmjs.com/package/node-plop)
[](https://github.com/plopjs/node-plop/actions/workflows/test.yml)

This is an early publication of the plop core logic being removed from the CLI tool. Main purpose for this is to make it easier for others to automate code generation through processes and tools OTHER than the command line. This also makes it easier to test the code functionality of PLOP without needing to test via the CLI interface.

This is the backend code that drives the plop CLI tool using node-plop.

```javascript
import nodePlop from "node-plop";
// load an instance of plop from a plopfile
const plop = await nodePlop(`./path/to/plopfile.js`);
// get a generator by name
const basicAdd = plop.getGenerator("basic-add");

// run all the generator actions using the data specified
basicAdd.runActions({ name: "this is a test" }).then(function (results) {
  // do something after the actions have run
});
```

---

## File: README.zh.md

# 快速上手

[](https://www.npmjs.com/package/plop)
&nbsp;
[](https://www.npmjs.com/package/plop)

文档版本：plop@3.1.0 - [plop@3.1.0](https://github.com/plopjs/plop/releases/tag/plop%403.1.0)

## 什么是 Plop？

Plop是一个“微生成器框架”——之所以这样定义它，是因为Plop是一个用于生成代码文件或其他纯文本文件的小工具。并且简单、高效、同时保证一致性。在开发中我们的代码往往基于“框架”和“关键字”的组合（路由、控制器、模板、等等）。这些组合往往随着时间的推移和开发的进行不断的会被完善和调整。当你需要创建一个同类型的文件时，你往往很难在浩如烟海的代码仓库中找到当初的那个“最佳实践”。而Plop专为解决此类问题而生，通过使用Plop，你只需要在控制台输入`Plop`命令，即可创建任何格式的、已经提前编写好的“最佳实现”代码。这不仅节约了你在搜寻合适代码来复制粘贴的时间，同时它也提供给你一种最“正确”也最“方便”的创建新文件的方法。

Plop的核心其实主要是[inquirer](https://github.com/SBoudrias/Inquirer.js/)命令行工具和[handlebar](https://github.com/wycats/handlebars.js/)模板引擎的整合。

> 此文档还在编写中，如果你有什么好想法请联系我们。

## 安装

### 1. 将plop添加到项目

```
$ npm install --save-dev plop
```

### 2. 全局安装plop (可选项，推荐)

```
$ npm install plop
```

### 3. 在项目的根目录创建plopfile.js

```javascript
module.exports = function (plop) {
  // 创建生成器
  plop.setGenerator("basics", {
    prompts: [], // 确认问题数组
    actions: [], // 操作列表
  });
};
```

> `export default` 只可以被用在NodeJS下的支持“ESM”标准的文件中。如果你希望使用这种语法，请确保你的使用环境属于以下两种之一：
>
> - 文件后缀名为.js，package.json的“type”字段中定义为“module”
> - 文件后缀名为.mjs，此情况不限制package.json的“type”字段
>
> 与此同时，你也可以创建一个内容为`module.exports = function (plop)`的`plopfile`。如果使用这种方式引入，需要你的使用环境属于以下两种之一：
>
> - 文件后缀名为.js，package.json的“type”字段中定义为“commonjs”
> - 文件后缀名为.js，此情况不限制package.json的“type”字段

## 编写Plopfile

Plopfile是一个简单的Node module，并导出一个函数，它接受一个`plop`对象作为第一个传入参数。

```javascript
module.exports = function (plop) {};
```

`plop`对象暴露了一些plop的api，其中包括`setGenerator(name, config)`方法，使用此方法可以创建Plop生成器。当在工作目录（或工作目录的子目录）命令行中输入`plop`命令时，所有的生成器会以列表形式输出。

一个最简单的起始生成器例子可能类似这样：

```javascript
module.exports = function (plop) {
  // controller generator
  plop.setGenerator("controller", {
    prompts: [
      {
        type: "input",
        name: "name",
        message: "controller name please",
      },
    ],
    actions: [
      {
        type: "add",
        path: "src/{{name}}.js",
        templateFile: "plop-templates/controller.hbs",
      },
    ],
  });
};
```

我们创建的 _controller_ 生成器会询问我们一个问题，并创建一个文件。这一操作可以进一步扩展，比如询问更多的问题，创建更多的文件。也有一些附加的`action`可以通过其他的方式操作我们的代码仓库。

## 使用Prompts

Plop使用[inquirer.js](https://github.com/SBoudrias/Inquirer.js) 库来接受用户输入。更多关于[问题类型](https://github.com/SBoudrias/Inquirer.js/#prompt-types)的信息可以查看inquirer官方文档.

## 通过CLI调用

Plop成功安装并且创建了`generator`之后，你就可以使用命令行运行plop了。直接调用`plop`命令将会输出所有可用的生成器。你呀可以直接使用`plop [生成器名称]`来直接调用某一生成器。如果你没有全局安装plop，则需要编写一个npm脚本来帮助运行plop。

```javascript
// package.json
{
    ...,
    "scripts": {
        "plop": "plop"
    },
    ...
}
```

### 直接传入参数

如果你对一个项目（以及它的生成器）十分了解，你就可能希望在调用生成器时直接传递回答参数了。例如项目中有一个名为`component`的生成器，其接受一个名为`name`的参数，可以直接通过`plop component "名字"`直接传入参数。如果生成器接受更多参数，只要按照这种规则依次传入即可。

例如`confirm`和`list`类型的问题会最大程度尝试理解你的输入。比如为`confirm`类型问题传入参数"y"，"yes"，"t"，或者"true"都会被解析成布尔值`true`。同时你可以使用选项的确切值，数组下标，键名，或者名称等等表示从列表中选中某选项。多选问题允许你传入以逗号分隔的值的列表，来表示多选项。

#### 操作示例



> 如果你想直接传入参数的问题是第二个问题，第一个仍需手动填写或选择，可以使用“\_“来跳过某个参数(例如 `plop component _ "input for second prompt"`).

Plop已经内置常规问题的直接传入参数逻辑了，不过你也可以自定义一些特殊问题解析用户输入的逻辑。如果你发布了inquirer的第三方插件并想支持plop的直接传入参数逻辑，可以查看[本文档的相关内容](#3rd-party-prompt-bypass).

### 通过属性名直接传入参数

你也可以直接传入参数 `--` 然后提供每个问题的参数来直接传入参数，例子[如下](#直接传入参数示例).

#### 直接传入参数示例

```
## 直接传入问题1和2的参数
$ plop component "my component" react
$ plop component -- --name "my component" --type react

## 直接传入问题2的参数 (name 属性依然会正常询问)
$ plop component _ react
$ plop component -- --type react
```

### 强制执行生成器

通常情况下Plop的`action`在发现执行可以操作时会执行失败，以此来尽可能确保文件安全。最常见的情况可能是不允许[`add`](#add) 操作覆盖一个已存在文件。但是Plop支持特殊的`force`属性，你也可以在命令行输入的指令后加上`--force`选项来开启强制模式，在这一模式下所有操作均会强制完成。不惜一切代价...🕷

## 为什么是“生成器”机制

这一机制可以使得你可以专注于编写模板，而不必同时考虑代码逻辑问题。这一机制可以为你和你的团队在面对重复逻辑时（路由，组件，辅助函数，测试，界面层，等等）节省大量的时间，[这真的很重要](https://xkcd.com/1205/)！

与此同时，对于程序猿来说在不同任务之间反复横跳真的[很浪费时间](https://www.petrikainulainen.net/software-development/processes/the-cost-of-context-switching/)，很有可能还没等你进入编写新逻辑的状态你就忍不住去摸鱼了...所以一次专注一件事真的可以大大提高工作效率！而且[工程化运作](https://kentcdodds.com/blog/automation)的优势远不止于此！

# Plopfile API

Plopfile api是一系列`plop`对象暴露出的方法，其实[`setGenerator`](#setgenerator)可以解决大部分的问题。但是在这部分文档中你可能会找到一些其他的有用信息以充实和完善你的plopfile。

## 使用TypeScript

`plop`内置了Typescript类型定义，无论你是否需要使用Typescript编写plopfile，这一特定都可以方便大部分的代码编辑器提供代码提示。

```javascript
// plopfile.ts

import { NodePlopAPI } from 'plop';



export default function (plop: NodePlopAPI) {

  // plop generator code

};
```

```javascript
// plopfile.js

module.exports = function (
  /** @type {import('plop').NodePlopAPI} */

  plop,
) {
  // plop generator code
};
```

## 常用方法

这些是创建plopfile时常用的方法。其他主要供内部使用的方法在[其他方法](#其他方法)部分列出。

| 方法名                                                                | 入参                                                       | 返回值                                          | 描述                                                              |
| --------------------------------------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------- | ----------------------------------------------------------------- |
| [**setGenerator**](#setgenerator)                                     | String, [GeneratorConfig](#interface-generatorconfig)      | _[GeneratorConfig](#interface-generatorconfig)_ | 创建一个生成器                                                    |
| [**setHelper**](#sethelper)                                           | _String, Function_                                         |                                                 | 创建一个helper                                                    |
| [**setPartial**](#setpartial)                                         | _String, String_                                           |                                                 | 创建一个Partial                                                   |
| [**setActionType**](#setactiontype)                                   | _String, [CustomAction](#functionsignature-custom-action)_ |                                                 | 创建一个Action类型                                                |
| [**setPrompt**](#setprompt)                                           | _String, InquirerPrompt_                                   |                                                 | 使用inquirer注册自定义问题类型                                    |
| [**load**](https://github.com/amwmedia/plop/blob/master/plop-load.md) | _Array[String], Object, Object_                            |                                                 | 从另一plopfile或者 npm module中载入生成器，helper，和/或 partials |

## setHelper

`setHelper` 等同于 handlebars 的方法 `registerHelper`。 如果你熟悉 [handlebars helpers](https://handlebarsjs.com/guide/expressions.html#helpers)，那你就已经对此很熟悉了。

```javascript
export default function (plop) {
  plop.setHelper("upperCase", function (text) {
    return text.toUpperCase();
  });

  // or in es6/es2015
  plop.setHelper("upperCase", (txt) => txt.toUpperCase());
}
```

## setPartial

`setPartial` 等同于 handlebars 的方法 `registerPartial`。如果你熟悉 [handlebars partials](https://handlebarsjs.com/guide/partials.html)，那你就已经对此很熟悉了。

```javascript
export default function (plop) {
  plop.setPartial("myTitlePartial", "<h1>{{titleCase name}}</h1>");
  // used in template as {{> myTitlePartial }}
}
```

## setActionType

`setActionType`允许你创建自定义`actions` (类似 `add` 或 `modify`) 完善你的plopfile。这些方法通常都是高度可复用的的 [自定义函数](#自定义action方法)。

### _函数定义_ 自定义Action

| 参数        | 类型                                      | 描述                        |
| ----------- | ----------------------------------------- | --------------------------- |
| **answers** | _Object_                                  | 生成器问题的回答            |
| **config**  | _[ActionConfig](#interface-actionconfig)_ | 生成器“actions”数组中的对象 |
| **plop**    | _[PlopfileApi](#plopfile-api)_            | Action运作时的plop api      |

```javascript
export default function (plop) {
  plop.setActionType("doTheThing", function (answers, config, plop) {
    // do something
    doSomething(config.configProp);
    // if something went wrong
    throw "error message";
    // otherwise
    return "success status message";
  });

  // or do async things inside of an action
  plop.setActionType("doTheAsyncThing", function (answers, config, plop) {
    // do something
    return new Promise((resolve, reject) => {
      if (success) {
        resolve("success status message");
      } else {
        reject("error message");
      }
    });
  });

  // use the custom action
  plop.setGenerator("test", {
    prompts: [],
    actions: [
      {
        type: "doTheThing",
        configProp: "available from the config param",
      },
      {
        type: "doTheAsyncThing",
        speed: "slow",
      },
    ],
  });
}
```

## setPrompt

[Inquirer](https://github.com/SBoudrias/Inquirer.js) 提供了许多开箱即用的问题类型，但是其也允许开发者构建第三方插件丰富问题类型。如果你需要使用第三方问题差价插件，你可以使用`setPrompt`。更多细节可以查看[Inquirer关于注册问题的官方文档](https://github.com/SBoudrias/Inquirer.js#inquirerregisterpromptname-prompt)。 你也可以查看[plop社区提供的自定问题列表](https://github.com/amwmedia/plop/blob/master/inquirer-prompts.md).

```javascript
import autocompletePrompt from 'inquirer-autocomplete-prompt';
export default function (plop) {
    plop.setPrompt('autocomplete', autocompletePrompt);
    plop.setGenerator('test', {
        prompts: [{
            type: 'autocomplete',
            ...
        }]
    });
};

```

## setGenerator

这一部分的配置对象需要包含`prompts` 和 `actions`（`description`是可选项）。`Prompts`数组会被传递到[inquirer](https://github.com/SBoudrias/Inquirer.js/#objects)，`actions`数组是一系列将要进行的操作的数组。（详细文档参阅下文）

### _接口_ `GeneratorConfig`

| 参数            | 类型                                                                            | 默认值 | 描述                   |
| --------------- | ------------------------------------------------------------------------------- | ------ | ---------------------- |
| **description** | _[String]_                                                                      |        | 此生成器功能的简短描述 |
| **prompts**     | _Array[[InquirerQuestion](https://github.com/SBoudrias/Inquirer.js/#question)]_ |        | 需要询问用户的问题     |
| **actions**     | _Array[[ActionConfig](#interface-actionconfig)]_                                |        | 需要执行的操作         |

  >如果你的Action列表有动态需求，你可以查看[使用动态action数组](#using-a-dynamic-actions-array)部分内容。

### _接口_ `ActionConfig`

下列参数是plop内部需要使用的基本参数，其他参数的需求取决于action的*类型*，关于这部分可以查看[内置actions](#built-in-actions)。

| 参数            | 类型                | 默认值  | 描述                                                                                             |
| --------------- | ------------------- | ------- | ------------------------------------------------------------------------------------------------ |
| **type**        | _String_            |         | action的类型 ([`add`](#add), [`modify`](#modify), [`addMany`](#addmany), [等等](#setactiontype)) |
| **force**       | _Boolean_           | `false` | 强制执行[forcefully](#running-a-generator-forcefully) (在不同action下有不同表现)                 |
| **data**        | _Object / Function_ | `{}`    | 指定需要与用户输入参数进行合并的数据                                                             |
| **abortOnFail** | _Boolean_           | `true`  | 如果本操作因任何原因失败则取消后续操作                                                           |
| **skip**        | _Function_          |         | 可选项，标记这个action是否会被执行                                                               |

> `ActionConfig`的`data`属性也可以为一个返回对象的函数或者一个返回`resolve`内容为函数的`Promise`。

> `ActionConfig`的`skip`属性方法是可选项，其应该返回一个字符串，内容是逃过action执行的原因。

> `Action`除了可以使用对象写法，也可以使用[函数写法](#自定义action方法)

## 其他方法

| 方法                  | 参数             | 返回                                            | 描述                                                                                 |
| --------------------- | ---------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------ |
| **getHelper**         | _String_         | _Function_                                      | 获取helper函数                                                                       |
| **getHelperList**     |                  | _Array[String]_                                 | 获取helper函数名称列表                                                               |
| **getPartial**        | _String_         | _String_                                        | 通过名称获取handlebars partial                                                       |
| **getPartialList**    |                  | _Array[String]_                                 | 获取partial名称列表                                                                  |
| **getActionType**     | _String_         | _[CustomAction](#函数定义-自定义action)_        | 通过名称获取action 类型                                                              |
| **getActionTypeList** |                  | _Array[String]_                                 | 获取actionType名称列表                                                               |
| **setWelcomeMessage** | _String_         |                                                 | 自定义运行`plop`时提示选择generator的提示标语                                        |
| **getGenerator**      | _String_         | _[GeneratorConfig](#interface-generatorconfig)_ | 根据名称获取[GeneratorConfig](#interface-generatorconfig)                            |
| **getGeneratorList**  |                  | _Array[Object]_                                 | 获取generator名称和描述的列表                                                        |
| **setPlopfilePath**   | _String_         |                                                 | 更改内部用于定位资源和模板文件的`plopfilePath`值                                     |
| **getPlopfilePath**   |                  | _String_                                        | 返回plopfile的绝对路径                                                               |
| **getDestBasePath**   |                  | _String_                                        | 获取创建文件的基准路径                                                               |
| **setDefaultInclude** | _Object_         | _Object_                                        | 设置当被其他文件使用 `plop.load()`载入时的默认设置                                   |
| **getDefaultInclude** | _String_         | _Object_                                        | 获取当被其他文件使用 `plop.load()`载入时的默认设置                                   |
| **renderString**      | _String, Object_ | _String_                                        | 使用handlebars渲染第一个参数(_String_)的模板，第二个参数(_Object_)作为渲染模板的数据 |

# 内置actions

你可以在[GeneratorConfig](#接口-generatorconfig)中通过设置action的`type`属性以及模板名称(路径均为plopfile的相对路径)来使用内置的action。

> `Add`, `AddMany`和`Modify`actions有一个可选方法`transform`，它可以在模板渲染结果被写入文件之前对结果做出修改。`transform`方法接受字符串类型的文件内容或许安然结果作为参数，同时必须返回一个字符串或者字符串Promise。

## Add

正如其字面意思，`add`action会想你的项目中添加一个问题件。Path参数将会被传入handlebars作为渲染的目标文件名字。文件内容则取决于`template`或 `templateFile` 属性。

| 属性             | 类型       | 默认值  | 描述                                                                 |
| ---------------- | ---------- | ------- | -------------------------------------------------------------------- |
| **path**         | _String_   |         | 渲染结果的目标位置                                                   |
| **template**     | _String_   |         | 渲染使用的模板名称                                                   |
| **templateFile** | _String_   |         | 使用的模板路径                                                       |
| **skipIfExists** | _Boolean_  | `false` | 当文件已经存在的时候直接跳过（而不是失败）                           |
| **transform**    | _Function_ |         | [可选方法](#内置actions)，可以在内容被写入文件之前做出修改           |
| **skip**         | _Function_ |         | _继承自 [ActionConfig](#接口-actionconfig)_                          |
| **force**        | _Boolean_  | `false` | _继承自 [ActionConfig](#接口-actionconfig)_ (如果文件存在将直接覆盖) |
| **data**         | _Object_   | `{}`    | _继承自 [ActionConfig](#接口-actionconfig)_                          |
| **abortOnFail**  | _Boolean_  | `true`  | _继承自 [ActionConfig](#接口-actionconfig)_                          |

## AddMany

`addMany`action可以在一个action中向项目添加多个文件。`destination`属性为生成文件的目标文件夹，`base`属性可以用于更改创建文件时需要忽略的文件路径。如果你需要生成特定文件名的文件，你可以在`templateFiles`属性处使用handlebars语法，例如“`{ { dashCase name } }.spec.js`”

| 属性                | 类型                                                               | 默认值    | 描述                                                                 |
| ------------------- | ------------------------------------------------------------------ | --------- | -------------------------------------------------------------------- |
| **destination**     | _String_                                                           |           | 渲染结果文件的目标文件夹                                             |
| **base**            | _String_                                                           |           | 向destination中写入文件时排除的文件路径                              |
| **templateFiles**   | _[Glob](https://github.com/sindresorhus/globby#globbing-patterns)_ |           | 用于匹配需要添加的模板                                               |
| **stripExtensions** | _[String]_                                                         | `['hbs']` | 模板文件的后缀名                                                     |
| **globOptions**     | _[Object](https://github.com/sindresorhus/globby#options)_         |           | 改变模板文件匹配方法的glob选项                                       |
| **verbose**         | _Boolean_                                                          | `true`    | 输出成功添加的文件路径                                               |
| **transform**       | _Function_                                                         |           | [可选方法](#内置actions)，可以在内容被写入文件之前做出修改           |
| **skip**            | _Function_                                                         |           | _继承自 [ActionConfig](#接口-actionconfig)_                          |
| **skipIfExists**    | _Boolean_                                                          | `false`   | _继承自[Add](#add)_ 当文件已经存在的时候直接跳过（而不是失败）       |
| **force**           | _Boolean_                                                          | `false`   | _继承自 [ActionConfig](#接口-actionconfig)_ (如果文件存在将直接覆盖) |
| **data**            | _Object_                                                           | `{}`      | _继承自 [ActionConfig](#接口-actionconfig)_                          |
| **abortOnFail**     | _Boolean_                                                          | `true`    | _继承自 [ActionConfig](#接口-actionconfig)_                          |

## Modify

`modify`action有两种使用方法，你可以使用`pattern`属性来匹配并替换在`path`中指定的文件，同时你可以使用`transform`方法来修改文件内容。`pattern`和 `transform`可以同时使用（`transform`后执行）。更多细节可以查看官方example

| 属性             | 类型       | 默认值                      | 描述                                                          |
| ---------------- | ---------- | --------------------------- | ------------------------------------------------------------- |
| **path**         | _String_   |                             | 需要被修改的文件渲染时使用的handlebars模板                    |
| **pattern**      | _RegExp_   | _end&#x2011;of&#x2011;file_ | 用以匹配和替换的正则表达式                                    |
| **template**     | _String_   |                             | 模板中需要被匹配替换的内容，可以使用`$1`， `$2`等等作为占位符 |
| **templateFile** | _String_   |                             | 包含`template`的文件路径                                      |
| **transform**    | _Function_ |                             | [可选方法](#内置actions)，可以在内容被写入文件之前做出修改    |
| **skip**         | _Function_ |                             | _继承自 [ActionConfig](#接口-actionconfig)_                   |
| **data**         | _Object_   | `{}`                        | _继承自 [ActionConfig](#接口-actionconfig)_                   |
| **abortOnFail**  | _Boolean_  | `true`                      | _继承自 [ActionConfig](#接口-actionconfig)_                   |

## Append

`append` action 是更常用的`modify`的子集。 他可以在文件的特定位置插入内容。

| 属性             | 类型             | 默认值     | 描述                                        |
| ---------------- | ---------------- | ---------- | ------------------------------------------- |
| **path**         | _String_         |            | 需要被修改的文件渲染时使用的handlebars模板  |
| **pattern**      | _RegExp, String_ |            | 用以匹配和替换的正则表达式                  |
| **unique**       | _Boolean_        | `true`     | 相同内容是否需要被移除                      |
| **separator**    | _String_         | `new line` | 分隔条目的值                                |
| **template**     | _String_         |            | 需要被修改的文件渲染时使用的handlebars模板  |
| **templateFile** | _String_         |            | 包含`template`的文件路径                    |
| **data**         | _Object_         | `{}`       | _继承自 [ActionConfig](#接口-actionconfig)_ |
| **abortOnFail**  | _Boolean_        | `true`     | _继承自 [ActionConfig](#接口-actionconfig)_ |

> 此处文档翻译有待推敲，欢迎提出pr进行修正和补充

## Custom (Action Function)

`Add`和`Modify`几乎可以完成plop设计的所有功能，不过plop也提供了更加进阶的自定义action方法。在actions数组中填入自定义的action函数即可使用这一功能。

- 自行以action在执行时与官方action使用相同的[函数接口](#函数定义-自定义action)
- Plop会等待自定义action方法执行完毕后才会继续执行下一个action
- 函数必须返回一个Plop可以理解的确切值，如果返回了一个`promise`，那么在这个promise完成之前plop不会进行任何操作。如果函数返回了一个字符串类型的消息(_String_)， plop便可得知action已经成功执行，并将此信息输出到action的状态提示信息上。
- 当返回的promise被reject，会程序抛出了一个异常，plop会视为action执行失败

_你也可以查看官方提供的 [同步自定义action案例](https://github.com/amwmedia/plop/blob/master/example/plopfile.js)_

## Comments

通过添加一个字符串来代替 action config 对象，可以将注释行添加到 actions 数组中。当plop执行这一action时，注释就会被打印到屏幕上，这一action本身不会进行其他任何操作。

# 内置 Helper

这些Helper应该可以覆盖你使用plop的所有需要，其中大部分是格式转换器，以下是内置Helper完整列表

## 格式转换器

- **camelCase**: changeFormatToThis
- **snakeCase**: change_format_to_this
- **dashCase/kebabCase**: change-format-to-this
- **dotCase**: change.format.to.this
- **pathCase**: change/format/to/this
- **properCase/pascalCase**: ChangeFormatToThis
- **lowerCase**: change format to this
- **sentenceCase**: Change format to this
- **constantCase**: CHANGE_FORMAT_TO_THIS
- **titleCase**: Change Format To This

## 其他 Helper

- **pkg**: 在plopfile同文件夹下的packag.json中寻找某一属性

# 进阶使用

以下是一些常见的进阶用法

## 使用动态构建的actions数组

[GeneratorConfig](#接口-generatorconfig)的`actions`属性可以是一个函数，他接受answers作为传入参数并且返回actions数组，这使你可以根据输入的答案动态调整actions数组

```javascript
module.exports = function (plop) {
  plop.setGenerator("test", {
    prompts: [
      {
        type: "confirm",
        name: "wantTacos",
        message: "Do you want tacos?",
      },
    ],
    actions: function (data) {
      var actions = [];

      if (data.wantTacos) {
        actions.push({
          type: "add",
          path: "folder/{{dashCase name}}.txt",
          templateFile: "templates/tacos.txt",
        });
      } else {
        actions.push({
          type: "add",
          path: "folder/{{dashCase name}}.txt",
          templateFile: "templates/burritos.txt",
        });
      }

      return actions;
    },
  });
};
```

## 向社区第三方Prompt直接传入数据

如果你编写了一个inquirer问题插件，并想要提供plop支持，实现起来很简单。你只需要为你的问题插件导出对象添加一个`bypass`方法。这一方法会被plop执行，执行时传入的第一个参数为用户的输入，第二个参数为prompt设置对象。这个函数的返回值会被作为该问题的答案保存到data对象中。

```javascript
// My confirmation inquirer plugin
module.exports = MyConfirmPluginConstructor;
function MyConfirmPluginConstructor() {
  // ...your main plugin code
  this.bypass = (rawValue, promptConfig) => {
    const lowerVal = rawValue.toString().toLowerCase();
    const trueValues = ["t", "true", "y", "yes"];
    const falseValues = ["f", "false", "n", "no"];
    if (trueValues.includes(lowerVal)) return true;
    if (falseValues.includes(lowerVal)) return false;
    throw Error(`"${rawValue}" is not a valid ${promptConfig.type} value`);
  };
  return this;
}
```

> 在这个案例中，函数将用户输入解析为布尔值并存入data对象中

### 直接在plopfile中提供直接传入参数支持

如果你的第三方插件不支持直接传入参数，你可以直接在你的问题设置对象中加入`bypass`方法，plop会自动将其用于解析参数。

## 对Plop进行包装

Plop额外提供了很多非常强大的功能，你甚至可以基于这些功能对`plop`进行进一步的包装，将其打包成你自己的cli。你只需要一个`plopfile.js`，一个`package.json`，和一个用于参考的模板文件。

你可以这样编写你的`index.js`:

```javascript
#!/usr/bin/env node
const path = require("path");
const args = process.argv.slice(2);
const { Plop, run } = require("plop");
const argv = require("minimist")(args);

Plop.launch(
  {
    cwd: argv.cwd,
    // In order for `plop` to always pick up the `plopfile.js` despite the CWD, you must use `__dirname`
    configPath: path.join(__dirname, "plopfile.js"),
    require: argv.require,
    completion: argv.completion,
    // This will merge the `plop` argv and the generator argv.
    // This means that you don't need to use `--` anymore
  },
  (env) => run(env, undefined, true),
);
```

> 如果你选择了`env => run(env, undefined, true))`写法，你可能会在直接传入参数时
> 遇到指令执行问题
>
> 如果你想放弃使用这一特性而使用类似plop使用的方法 (需要在向generator传入参数之前加上`--`)
> 只要将箭头函数`env =>`替换成`run`即可:
>
> ```javascript
> Plop.launch({}, run);
> ```

你的 `package.json` 可能将会类似如下格式:

```json
{
  "name": "create-your-name-app",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "plop"
  },
  "bin": {
    "create-your-name-app": "./index.js"
  },
  "preferGlobal": true,
  "dependencies": {
    "plop": "^2.6.0"
  }
}
```

### 为你的自定义程序设定基准路径

当进一步打包plop时，你可能需要基于命令行执行cwd生成目标路径，你可以这样设置基准路径`dest`：

```javascript
Plop.launch(
  {
    // config like above
  },
  (env) => {
    const options = {
      ...env,
      dest: process.cwd(), // this will make the destination path to be based on the cwd when calling the wrapper
    };
    return run(options, undefined, true);
  },
);
```

### 添加自动CLI Actions

许多CLI都会自动帮你进行某些行为，比如说在项目生成完成后自动运行 `git init` 或 `npm install`

这些行为非常普遍，但是我们出于保持核心功能简洁的目的并没有默认添加它们。因此，我们维护了一个 [库集合](https://github.com/plopjs/awesome-plop)，用于将这些行为添加到[our Awesome Plop list](https://github.com/plopjs/awesome-plop)中，在那里，您可以找到这些行为，甚至可以构建自己的行为并将其添加到列表中！。

### 更加进阶的自定义

虽然`plop`已经提供了高度可自定义的CLI包装支持，但也有可能某些场景下你需要在借助模板代码生成功能的基础上更进一步的掌控CLI的工作体验。

幸运的是， [`node-plop`](https://github.com/plopjs/node-plop/) 可能更适合你! `plop` CLI本身就是基于此构建的，你可以基于此构建其他功能更加丰富的CLI。只是这部分的文档可能有待更进一步的完善，不过风险往往与机会并存 :)

> 我们注意到关于`node-plop` 集成的乏善可陈的文档可能是我们的一项短板。如果您希望为项目贡献文档，欢迎您积极参与进来！