Skip to content

Commit

Permalink
Merge pull request #396 from plopjs/plop-v4
Browse files Browse the repository at this point in the history
Plop v4
  • Loading branch information
crutchcorn committed Sep 5, 2023
2 parents f0742f2 + 8850f46 commit 5e21799
Show file tree
Hide file tree
Showing 68 changed files with 10,543 additions and 5,353 deletions.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const ts = {
ecmaVersion: 2018,
sourceType: "module",
project: "./tsconfig.json",
tsconfigRootDir: __dirname,
allowImportExportEverywhere: true,
},
plugins: ["@typescript-eslint"],
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
strategy:
matrix:
os: [ ubuntu-latest, windows-latest ]
node: [ 14, 16 ]
node: [ 18, 20 ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
Expand Down
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@ node_modules/
.turbo/
.eslintcache
yarn-error.log

.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
541 changes: 541 additions & 0 deletions .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs

Large diffs are not rendered by default.

874 changes: 874 additions & 0 deletions .yarn/releases/yarn-3.6.3.cjs

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
nmHoistingLimits: workspaces

nodeLinker: node-modules

plugins:
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"

yarnPath: .yarn/releases/yarn-3.6.3.cjs
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Micro-generator framework that makes it easy for an entire team to create files
## 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/) prompts and [handlebar](https://github.com/wycats/handlebars.js/) templates.
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.
Expand Down Expand Up @@ -84,7 +84,7 @@ export default function (plop) {
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/#prompt-types) can be found on the inquirer official website.
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.
Expand Down Expand Up @@ -247,7 +247,7 @@ export default function (plop) {
```

## setPrompt
[Inquirer](https://github.com/SBoudrias/Inquirer.js) 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#inquirerregisterpromptname-prompt). Also check out the [plop community driven list of custom prompts](https://github.com/plopjs/awesome-plop#inquirer-prompts).
[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';
Expand All @@ -263,13 +263,13 @@ export default function (plop) {
```

## 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/#objects). The `actions` array is a list of actions to take (described in greater detail below)
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/#question)]* | | questions to ask the user
**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)
Expand Down
29 changes: 15 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,24 @@
"homepage": "https://plopjs.com",
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
"node": ">=18"
},
"devDependencies": {
"@changesets/changelog-github": "^0.4.4",
"@changesets/cli": "^2.22.0",
"@typescript-eslint/eslint-plugin": "^5.21.0",
"@typescript-eslint/parser": "^5.21.0",
"eslint": "^8.14.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"husky": "^7.0.4",
"lint-staged": "^12.4.0",
"prettier": "^2.6.2",
"turbo": "^1.2.5",
"typescript": "^4.6.3"
"@changesets/changelog-github": "^0.4.8",
"@changesets/cli": "^2.26.2",
"@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^6.6.0",
"eslint": "^8.48.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"husky": "^8.0.3",
"lint-staged": "^14.0.1",
"prettier": "^3.0.3",
"turbo": "^1.10.13",
"typescript": "^5.2.2"
},
"lint-staged": {
"*.js": "eslint --cache --fix"
}
},
"packageManager": "yarn@3.6.3"
}
6 changes: 6 additions & 0 deletions packages/node-plop/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# node-plop

## 0.32.0

### Minor Changes

- [#396](https://github.com/plopjs/plop/pull/396) [`a22e33f`](https://github.com/plopjs/plop/commit/a22e33f416340352e83a1e9c0d470baf2aff1c4b) Thanks [@crutchcorn](https://github.com/crutchcorn)! - Drop support for Node 12, 14, & 16. Update all dependencies

## 0.31.1

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/node-plop/build-scripts/clean.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import * as del from "del";
import { deleteSync } from "del";

del.sync("./lib");
deleteSync("./lib");
26 changes: 13 additions & 13 deletions packages/node-plop/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "node-plop",
"version": "0.31.1",
"version": "0.32.0",
"description": "programmatic plopping for fun and profit",
"main": "src/index.js",
"type": "module",
Expand Down Expand Up @@ -34,25 +34,25 @@
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"devDependencies": {
"@types/inquirer-autocomplete-prompt": "^1.3.4",
"@types/node": "^17.0.27",
"@types/inquirer-autocomplete-prompt": "^3.0.0",
"@types/node": "^20.5.9",
"dtslint": "^4.2.1",
"plop-pack-fancy-comments": "^0.2.1",
"typescript": "^4.6.3",
"vitest": "^0.10.0"
"typescript": "^5.2.2",
"vitest": "^0.34.3"
},
"dependencies": {
"@types/inquirer": "^8.2.1",
"@types/inquirer": "^9.0.3",
"change-case": "^4.1.2",
"del": "^6.0.0",
"globby": "^13.1.1",
"handlebars": "^4.4.3",
"inquirer": "^8.2.2",
"isbinaryfile": "^4.0.8",
"del": "^7.1.0",
"globby": "^13.2.2",
"handlebars": "^4.7.8",
"inquirer": "^9.2.10",
"isbinaryfile": "^5.0.0",
"lodash.get": "^4.4.2",
"lower-case": "^2.0.2",
"mkdirp": "^1.0.4",
"resolve": "^1.20.0",
"mkdirp": "^3.0.1",
"resolve": "^1.22.4",
"title-case": "^3.0.3",
"upper-case": "^2.0.2"
}
Expand Down
6 changes: 3 additions & 3 deletions packages/node-plop/src/actions/_common-action-add-file.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from "path";
import del from "del";
import { deleteAsync } from "del";
import {
getRenderedTemplate,
getTransformedTemplate,
Expand All @@ -19,7 +19,7 @@ export default async function addFile(data, cfg, plop) {

// if we are forcing and the file already exists, delete the file
if (force === true && destExists) {
await del([fileDestPath], { force });
await deleteAsync([fileDestPath], { force });
destExists = false;
}

Expand All @@ -46,7 +46,7 @@ export default async function addFile(data, cfg, plop) {
const transformedTemplate = await getTransformedTemplate(
renderedTemplate,
data,
cfg
cfg,
);

await fspp.writeFile(fileDestPath, transformedTemplate);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default function (
action,
{ checkPath = true, checkAbortOnFail = true } = {}
{ checkPath = true, checkAbortOnFail = true } = {},
) {
// it's not even an object, you fail!
if (typeof action !== "object") {
Expand Down
10 changes: 5 additions & 5 deletions packages/node-plop/src/actions/_common-action-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ export const normalizePath = (path) => {
export const makeDestPath = (data, cfg, plop) => {
return path.resolve(
plop.getDestBasePath(),
plop.renderString(normalizePath(cfg.path) || "", getFullData(data, cfg))
plop.renderString(normalizePath(cfg.path) || "", getFullData(data, cfg)),
);
};

export function getRenderedTemplatePath(data, cfg, plop) {
if (cfg.templateFile) {
const absTemplatePath = path.resolve(
plop.getPlopfilePath(),
cfg.templateFile
cfg.templateFile,
);
return plop.renderString(
normalizePath(absTemplatePath),
getFullData(data, cfg)
getFullData(data, cfg),
);
}
return null;
Expand Down Expand Up @@ -68,8 +68,8 @@ export async function getTransformedTemplate(template, data, cfg) {
if (typeof result !== "string")
throw new TypeError(
`Invalid return value for transform (${JSON.stringify(
result
)} is not a string)`
result,
)} is not a string)`,
);

return result;
Expand Down
8 changes: 4 additions & 4 deletions packages/node-plop/src/actions/addMany.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default async function (data, userConfig, plop) {
cfg.templateFiles,
cfg.base,
cfg.globOptions,
plop
plop,
);

const filesAdded = [];
Expand All @@ -49,7 +49,7 @@ export default async function (data, userConfig, plop) {
const fileCfg = Object.assign({}, cfg, {
path: stripExtensions(
cfg.stripExtensions,
resolvePath(cfg.destination, templateFile, cfg.base)
resolvePath(cfg.destination, templateFile, cfg.base),
),
templateFile: absTemplatePath,
});
Expand All @@ -66,7 +66,7 @@ function resolveTemplateFiles(templateFilesGlob, basePath, globOptions, plop) {
globOptions = Object.assign({ cwd: plop.getPlopfilePath() }, globOptions);
return globbySync(
templateFilesGlob,
Object.assign({ braceExpansion: false }, globOptions)
Object.assign({ braceExpansion: false }, globOptions),
)
.filter(isUnder(basePath))
.filter(isAbsoluteOrRelativeFileTo(plop.getPlopfilePath()));
Expand All @@ -82,7 +82,7 @@ function isUnder(basePath = "") {

function resolvePath(destination, file, rootPath) {
return normalizePath(
path.join(destination, dropFileRootPath(file, rootPath))
path.join(destination, dropFileRootPath(file, rootPath)),
);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/node-plop/src/actions/append.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const doAppend = async function (data, cfg, plop, fileData) {
const lastPart = parts[parts.length - 1];
const lastPartWithoutDuplicates = lastPart.replace(
new RegExp(separator + stringToAppend, "g"),
""
"",
);
fileData = fileData.replace(lastPart, lastPartWithoutDuplicates);
}
Expand Down
27 changes: 12 additions & 15 deletions packages/node-plop/src/fs-promise-proxy.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import fs from "fs";
import mkdirp from "mkdirp";
import { promisify } from "util";

const _readFile = promisify(fs.readFile);
const _writeFile = promisify(fs.writeFile);
const _access = promisify(fs.access);
import { mkdirp } from "mkdirp";

export const makeDir = mkdirp;
export const readdir = promisify(fs.readdir);
export const stat = promisify(fs.stat);
export const chmod = promisify(fs.chmod);
export const readFile = (path) => _readFile(path, "utf8");
export const writeFile = (path, data) => _writeFile(path, data, "utf8");
export const readFileRaw = (path) => _readFile(path, null);
export const writeFileRaw = (path, data) => _writeFile(path, data, null);
export const readdir = fs.promises.readdir;
export const stat = fs.promises.stat;
export const chmod = fs.promises.chmod;
export const readFile = (path) => fs.promises.readFile(path, "utf8");
export const writeFile = (path, data) =>
fs.promises.writeFile(path, data, "utf8");
export const readFileRaw = (path) => fs.promises.readFile(path, null);
export const writeFileRaw = (path, data) =>
fs.promises.writeFile(path, data, null);
export const fileExists = (path) =>
_access(path).then(
fs.promises.access(path).then(
() => true,
() => false
() => false,
);

export const constants = fs.constants;
12 changes: 6 additions & 6 deletions packages/node-plop/src/generator-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default function (plopfileApi, flags) {
const [promptsAfterBypass, bypassAnswers] = await promptBypass(
prompts,
bypassArr,
plopfileApi
plopfileApi,
);

return await plopfileApi.inquirer
Expand All @@ -35,7 +35,7 @@ export default function (plopfileApi, flags) {
const runGeneratorActions = async function (
genObject,
data = {},
hooks = {}
hooks = {},
) {
const noop = () => {};
const {
Expand Down Expand Up @@ -114,7 +114,7 @@ export default function (plopfileApi, flags) {
const actionResult = await executeActionLogic(
actionLogic,
actionCfg,
data
data,
);
onSuccess(actionResult);
changes.push(actionResult);
Expand Down Expand Up @@ -156,7 +156,7 @@ export default function (plopfileApi, flags) {

// track keys that can be applied to the main data scope
const cfgDataKeys = Object.keys(cfgData).filter(
(k) => typeof data[k] === "undefined"
(k) => typeof data[k] === "undefined",
);
// copy config data into main data scope so it's available for templates
cfgDataKeys.forEach((k) => {
Expand All @@ -174,13 +174,13 @@ export default function (plopfileApi, flags) {
// a rejected promise is treated as a failure
(err) => {
throw { type, path: "", error: err.message || err.toString() };
}
},
)
// cleanup main data scope so config data doesn't leak
.finally(() =>
cfgDataKeys.forEach((k) => {
delete data[k];
})
}),
);
};

Expand Down
Loading

0 comments on commit 5e21799

Please sign in to comment.