diff --git a/package-lock.json b/package-lock.json index 3ee6f318a1da75..c524b58aa951a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7802,6 +7802,7 @@ "cross-spawn": "^5.1.0", "decompress-zip": "^0.2.2", "eslint": "^6.1.0", + "fs-extra": "^8.1.0", "jest": "^24.7.1", "jest-puppeteer": "^4.3.0", "js-yaml": "^3.13.1", @@ -7810,6 +7811,7 @@ "npm-package-json-lint": "^4.0.3", "puppeteer": "^2.0.0", "read-pkg-up": "^1.0.1", + "replace-in-file": "^4.2.0", "request": "^2.88.0", "resolve-bin": "^0.4.0", "source-map-loader": "^0.2.4", @@ -7821,6 +7823,25 @@ "webpack-bundle-analyzer": "^3.3.2", "webpack-cli": "^3.1.2", "webpack-livereload-plugin": "^2.2.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + } } }, "@wordpress/server-side-render": { @@ -21675,7 +21696,7 @@ "dependencies": { "clone-deep": { "version": "0.2.4", - "resolved": "http://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", "integrity": "sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY=", "dev": true, "requires": { @@ -21709,7 +21730,7 @@ "dependencies": { "kind-of": { "version": "2.0.1", - "resolved": "http://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", "dev": true, "requires": { @@ -28333,6 +28354,160 @@ "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", "dev": true }, + "replace-in-file": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-4.2.0.tgz", + "integrity": "sha512-9PGYDbU8iQF3W5a0Ariaf4KzYjsZSkonCYiZylwMiYOu0w5Bg9IuT4DqNnibA4zGNVxH//F7Hxh1P25TofAHGw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "glob": "^7.1.4", + "yargs": "^13.3.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + } + } + } + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", diff --git a/packages/scripts/README.md b/packages/scripts/README.md index cee0e05c9daf7a..7154674975a6b6 100644 --- a/packages/scripts/README.md +++ b/packages/scripts/README.md @@ -117,6 +117,20 @@ _Flags_: - `--gpl2`: Validates against [GPLv2 license compatibility](https://www.gnu.org/licenses/license-list.en.html) - `--ignore=a,b,c`: A comma-separated set of package names to ignore for validation. This is intended to be used primarily in cases where a dependency’s `license` field is malformed. It’s assumed that any `ignored` package argument would be manually vetted for compatibility by the project owner. +### `create-block` + +Takes a new name for a block and creates a minimal plugin development environment for it in the current working directory. + +_Example:_ + +```sh +$ wp-scripts create-block "My Fancy Block" +$ cd ./my-fancy-block-plugin +$ npm install +$ npm run start # Start WordPress instance. +$ npm run dev # Build and watch files. +``` + ### `env` `env` is a family of scripts for setting up a local Docker-based development environment that plugin contributors can work in. diff --git a/packages/scripts/package.json b/packages/scripts/package.json index f06c00e125e841..bc3d490e80e5d1 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -45,6 +45,7 @@ "cross-spawn": "^5.1.0", "decompress-zip": "^0.2.2", "eslint": "^6.1.0", + "fs-extra": "^8.1.0", "jest": "^24.7.1", "jest-puppeteer": "^4.3.0", "js-yaml": "^3.13.1", @@ -53,6 +54,7 @@ "npm-package-json-lint": "^4.0.3", "puppeteer": "^2.0.0", "read-pkg-up": "^1.0.1", + "replace-in-file": "^4.2.0", "request": "^2.88.0", "resolve-bin": "^0.4.0", "source-map-loader": "^0.2.4", diff --git a/packages/scripts/scripts/create-block.js b/packages/scripts/scripts/create-block.js new file mode 100644 index 00000000000000..251902fc8cc1a5 --- /dev/null +++ b/packages/scripts/scripts/create-block.js @@ -0,0 +1,33 @@ +/** + * External dependencies + */ +const { kebabCase } = require( 'lodash' ); +const { copy } = require( 'fs-extra' ); +const replaceInFile = require( 'replace-in-file' ); + +/** + * Internal dependencies + */ +const { getArgsFromCLI, fromTemplatesRoot } = require( '../utils' ); + +const blockTitle = getArgsFromCLI()[ 0 ]; +if ( ! blockTitle ) { + process.stdout.write( 'No block name provided.' ); + process.exit( 1 ); +} +const blockName = kebabCase( blockTitle ); +const pluginName = `${ blockName }-plugin`; +const pluginPath = `./${ pluginName }` + +;( async () => { + await copy( fromTemplatesRoot( 'block-plugin' ), pluginPath ); + await replaceInFile( { + files: `${ pluginPath }/**`, + from: [ + /block-plugin-block-title/g, + /block-plugin-block-name/g, + /block(_|-)plugin\1name/g, + ], + to: [ blockTitle, blockName, pluginName.replace( /-/g, '$1' ) ], + } ); +} )(); diff --git a/packages/scripts/templates/block-plugin/.gitignore b/packages/scripts/templates/block-plugin/.gitignore new file mode 100644 index 00000000000000..ab117b60102639 --- /dev/null +++ b/packages/scripts/templates/block-plugin/.gitignore @@ -0,0 +1,5 @@ +# Dependencies +/node_modules/ + +# Build +/build/ diff --git a/packages/scripts/templates/block-plugin/package.json b/packages/scripts/templates/block-plugin/package.json new file mode 100644 index 00000000000000..a0063673def242 --- /dev/null +++ b/packages/scripts/templates/block-plugin/package.json @@ -0,0 +1,15 @@ +{ + "name": "block-plugin-name", + "version": "1.0.0", + "main": "plugin.php", + "scripts": { + "start": "wp-env start", + "dev": "wp-scripts start", + "build": "wp-scripts build" + }, + "license": "GPL-2.0-or-later", + "devDependencies": { + "@wordpress/env": "^0.1.0", + "@wordpress/scripts": "^6.0.0" + } +} diff --git a/packages/scripts/templates/block-plugin/plugin.php b/packages/scripts/templates/block-plugin/plugin.php new file mode 100644 index 00000000000000..004e3c58b1a923 --- /dev/null +++ b/packages/scripts/templates/block-plugin/plugin.php @@ -0,0 +1,45 @@ +
Editor
, + save: () =>
Front End
, +} ); diff --git a/packages/scripts/templates/block-plugin/src/style.css b/packages/scripts/templates/block-plugin/src/style.css new file mode 100644 index 00000000000000..e4a977e4b8c9fb --- /dev/null +++ b/packages/scripts/templates/block-plugin/src/style.css @@ -0,0 +1 @@ +/* Styles shared between the editor and the front end. */ diff --git a/packages/scripts/utils/file.js b/packages/scripts/utils/file.js index 7f66c5e0ade789..1bdd3a261283b7 100644 --- a/packages/scripts/utils/file.js +++ b/packages/scripts/utils/file.js @@ -18,6 +18,9 @@ const hasProjectFile = ( fileName ) => const fromConfigRoot = ( fileName ) => path.join( path.dirname( __dirname ), 'config', fileName ); +const fromTemplatesRoot = ( fileName ) => + path.join( path.dirname( __dirname ), 'templates', fileName ); + const fromScriptsRoot = ( scriptName ) => path.join( path.dirname( __dirname ), 'scripts', `${ scriptName }.js` ); @@ -26,6 +29,7 @@ const hasScriptFile = ( scriptName ) => module.exports = { fromConfigRoot, + fromTemplatesRoot, fromScriptsRoot, hasProjectFile, hasScriptFile, diff --git a/packages/scripts/utils/index.js b/packages/scripts/utils/index.js index 3d5e3bd7ac4386..217a008da682ae 100644 --- a/packages/scripts/utils/index.js +++ b/packages/scripts/utils/index.js @@ -21,6 +21,7 @@ const { } = require( './env' ); const { fromConfigRoot, + fromTemplatesRoot, hasProjectFile, } = require( './file' ); const { @@ -34,6 +35,7 @@ module.exports = { buildWordPress, camelCaseDash, fromConfigRoot, + fromTemplatesRoot, getArgFromCLI, getArgsFromCLI, getFileArgsFromCLI,