From b751a298a3b661c9e9470f8f52b9c2ad001e009a Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Fri, 8 May 2020 20:04:35 +0200 Subject: [PATCH 1/5] Create Block: Use glob to find all template files --- package-lock.json | 1 + packages/create-block/lib/scaffold.js | 15 +++--- packages/create-block/lib/templates.js | 73 ++++++++++---------------- packages/create-block/package.json | 1 + 4 files changed, 35 insertions(+), 55 deletions(-) diff --git a/package-lock.json b/package-lock.json index ec8abf0122ac3c..73bb53a64eb80e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9997,6 +9997,7 @@ "check-node-version": "^3.1.1", "commander": "^4.1.0", "execa": "^4.0.0", + "fast-glob": "^2.2.7", "inquirer": "^7.1.0", "lodash": "^4.17.15", "make-dir": "^3.0.0", diff --git a/packages/create-block/lib/scaffold.js b/packages/create-block/lib/scaffold.js index be9b09588bde6c..5fc37a19b3028f 100644 --- a/packages/create-block/lib/scaffold.js +++ b/packages/create-block/lib/scaffold.js @@ -50,20 +50,17 @@ module.exports = async function( licenseURI, textdomain: namespace, }; + const outputFiles = await getOutputFiles( templateName ); await Promise.all( - getOutputFiles( templateName ).map( async ( file ) => { + outputFiles.map( async ( file ) => { const template = await readFile( - join( - __dirname, - `templates/${ templateName }/${ file }.mustache` - ), + join( __dirname, `templates/${ templateName }/${ file }` ), 'utf8' ); // Output files can have names that depend on the slug provided. - const outputFilePath = `${ slug }/${ file.replace( - /\$slug/g, - slug - ) }`; + const outputFilePath = `${ slug }/${ file + .replace( /\$slug/g, slug ) + .replace( '.mustache', '' ) }`; await makeDir( dirname( outputFilePath ) ); writeFile( outputFilePath, render( template, view ) ); } ) diff --git a/packages/create-block/lib/templates.js b/packages/create-block/lib/templates.js index 7beadd7008cfe3..aa28fb1c0c4a1d 100644 --- a/packages/create-block/lib/templates.js +++ b/packages/create-block/lib/templates.js @@ -1,67 +1,34 @@ +/** + * External dependencies + */ +const glob = require( 'fast-glob' ); +const { join } = require( 'path' ); + /** * Internal dependencies */ const CLIError = require( './cli-error' ); const prompts = require( './prompts' ); -const namespace = 'create-block'; -const dashicon = 'smiley'; -const category = 'widgets'; -const author = 'The WordPress Contributors'; -const license = 'GPL-2.0-or-later'; -const licenseURI = 'https://www.gnu.org/licenses/gpl-2.0.html'; -const version = '0.1.0'; - const templates = { es5: { defaultValues: { - namespace, slug: 'es5-example', title: 'ES5 Example', description: 'Example block written with ES5 standard and no JSX – no build step required.', - dashicon, - category, - author, - license, - licenseURI, - version, }, - outputFiles: [ - '.editorconfig', - 'editor.css', - 'index.js', - '$slug.php', - 'style.css', - 'readme.txt', - ], + templatesPath: './templates/es5', + wpScripts: false, }, esnext: { defaultValues: { - namespace, slug: 'esnext-example', title: 'ESNext Example', description: 'Example block written with ESNext standard and JSX support – build step required.', - dashicon, - category, - author, - license, - licenseURI, - version, }, - outputFiles: [ - '.editorconfig', - '.gitignore', - 'editor.css', - 'src/edit.js', - 'src/index.js', - 'src/save.js', - '$slug.php', - 'style.css', - 'readme.txt', - ], - wpScriptsEnabled: true, + templatesPath: './templates/esnext', }, }; @@ -77,11 +44,25 @@ const getTemplate = ( templateName ) => { }; const getDefaultValues = ( templateName ) => { - return getTemplate( templateName ).defaultValues; + return { + namespace: 'create-block', + dashicon: 'smiley', + category: 'widgets', + author: 'The WordPress Contributors', + license: 'GPL-2.0-or-later', + licenseURI: 'https://www.gnu.org/licenses/gpl-2.0.html', + version: '0.1.0', + ...getTemplate( templateName ).defaultValues, + }; }; -const getOutputFiles = ( templateName ) => { - return getTemplate( templateName ).outputFiles; +const getOutputFiles = async ( templateName ) => { + const templatesPath = getTemplate( templateName ).templatesPath; + + return await glob( '**/*.mustache', { + cwd: join( __dirname, templatesPath ), + dot: true, + } ); }; const getPrompts = ( templateName ) => { @@ -95,7 +76,7 @@ const getPrompts = ( templateName ) => { }; const hasWPScriptsEnabled = ( templateName ) => { - return getTemplate( templateName ).wpScriptsEnabled || false; + return ! ( getTemplate( templateName ).wpScripts === false ); }; module.exports = { diff --git a/packages/create-block/package.json b/packages/create-block/package.json index 3b949c42fcd511..329a7fcc157f40 100644 --- a/packages/create-block/package.json +++ b/packages/create-block/package.json @@ -34,6 +34,7 @@ "check-node-version": "^3.1.1", "commander": "^4.1.0", "execa": "^4.0.0", + "fast-glob": "^2.2.7", "inquirer": "^7.1.0", "lodash": "^4.17.15", "make-dir": "^3.0.0", From 7a882d805b026bb049e182f084a388c2e5ad0060 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Mon, 11 May 2020 12:37:36 +0200 Subject: [PATCH 2/5] Create block: Refactor template handling --- packages/create-block/README.md | 2 +- packages/create-block/lib/index.js | 31 ++++++++++----- packages/create-block/lib/scaffold.js | 34 ++++++++--------- packages/create-block/lib/templates.js | 53 +++++++++++++++++--------- 4 files changed, 74 insertions(+), 46 deletions(-) diff --git a/packages/create-block/README.md b/packages/create-block/README.md index bd952cb515d4d7..579511ae7b329b 100644 --- a/packages/create-block/README.md +++ b/packages/create-block/README.md @@ -38,7 +38,7 @@ $ npm init @wordpress/block [options] [slug] Options: ``` -V, --version output the version number --t, --template template type name, allowed values: "es5", "esnext" (default: "esnext") +-t, --template block template type name, allowed values: "es5", "esnext" (default: "esnext") --namespace internal namespace for the block name --title display title for the block --short-description short description for the block diff --git a/packages/create-block/lib/index.js b/packages/create-block/lib/index.js index d4156437387bf8..1a7befc359093a 100644 --- a/packages/create-block/lib/index.js +++ b/packages/create-block/lib/index.js @@ -13,7 +13,11 @@ const CLIError = require( './cli-error' ); const log = require( './log' ); const { engines, version } = require( '../package.json' ); const scaffold = require( './scaffold' ); -const { getDefaultValues, getPrompts } = require( './templates' ); +const { + getBlockTemplate, + getDefaultValues, + getPrompts, +} = require( './templates' ); const commandName = `wp-create-block`; program @@ -24,13 +28,13 @@ program 'it is used as the block slug used for its identification, the output ' + 'location for scaffolded files, and the name of the WordPress plugin.' + 'The rest of the configuration is set to all default values unless ' + - 'overriden with some of the options listed below.' + 'overridden with some of the options listed below.' ) .version( version ) .arguments( '[slug]' ) .option( '-t, --template ', - 'template type name, allowed values: "es5", "esnext"', + 'block template type name, allowed values: "es5", "esnext"', 'esnext' ) .option( '--namespace ', 'internal namespace for the block name' ) @@ -41,14 +45,21 @@ program .action( async ( slug, - { category, namespace, shortDescription, template, title } + { + category, + namespace, + shortDescription: description, + template: templateName, + title, + } ) => { await checkSystemRequirements( engines ); try { - const defaultValues = getDefaultValues( template ); + const blockTemplate = getBlockTemplate( templateName ); + const defaultValues = getDefaultValues( blockTemplate ); const optionsValues = pickBy( { category, - description: shortDescription, + description, namespace, title, } ); @@ -60,14 +71,14 @@ program title: startCase( slug ), ...optionsValues, }; - await scaffold( template, answers ); + await scaffold( blockTemplate, answers ); } else { - const propmpts = getPrompts( template ).filter( + const prompts = getPrompts( blockTemplate ).filter( ( { name } ) => ! Object.keys( optionsValues ).includes( name ) ); - const answers = await inquirer.prompt( propmpts ); - await scaffold( template, { + const answers = await inquirer.prompt( prompts ); + await scaffold( blockTemplate, { ...defaultValues, ...optionsValues, ...answers, diff --git a/packages/create-block/lib/scaffold.js b/packages/create-block/lib/scaffold.js index 5fc37a19b3028f..dbc3afbc8d8a98 100644 --- a/packages/create-block/lib/scaffold.js +++ b/packages/create-block/lib/scaffold.js @@ -1,21 +1,21 @@ /** * External dependencies */ -const { dirname, join } = require( 'path' ); +const { writeFile } = require( 'fs' ).promises; +const { snakeCase } = require( 'lodash' ); const makeDir = require( 'make-dir' ); -const { readFile, writeFile } = require( 'fs' ).promises; const { render } = require( 'mustache' ); -const { snakeCase } = require( 'lodash' ); +const { dirname } = require( 'path' ); /** * Internal dependencies */ const initWPScripts = require( './init-wp-scripts' ); const { code, info, success } = require( './log' ); -const { hasWPScriptsEnabled, getOutputFiles } = require( './templates' ); +const { hasWPScriptsEnabled, getOutputTemplates } = require( './templates' ); module.exports = async function( - templateName, + blockTemplate, { namespace, slug, @@ -50,23 +50,23 @@ module.exports = async function( licenseURI, textdomain: namespace, }; - const outputFiles = await getOutputFiles( templateName ); + const outputTemplates = await getOutputTemplates( blockTemplate ); await Promise.all( - outputFiles.map( async ( file ) => { - const template = await readFile( - join( __dirname, `templates/${ templateName }/${ file }` ), - 'utf8' - ); + Object.keys( outputTemplates ).map( async ( outputFile ) => { // Output files can have names that depend on the slug provided. - const outputFilePath = `${ slug }/${ file - .replace( /\$slug/g, slug ) - .replace( '.mustache', '' ) }`; + const outputFilePath = `${ slug }/${ outputFile.replace( + /\$slug/g, + slug + ) }`; await makeDir( dirname( outputFilePath ) ); - writeFile( outputFilePath, render( template, view ) ); + writeFile( + outputFilePath, + render( outputTemplates[ outputFile ], view ) + ); } ) ); - if ( hasWPScriptsEnabled( templateName ) ) { + if ( hasWPScriptsEnabled( blockTemplate ) ) { await initWPScripts( view ); } @@ -74,7 +74,7 @@ module.exports = async function( success( `Done: block "${ title }" bootstrapped in the "${ slug }" folder.` ); - if ( hasWPScriptsEnabled( templateName ) ) { + if ( hasWPScriptsEnabled( blockTemplate ) ) { info( '' ); info( 'Inside that directory, you can run several commands:' ); info( '' ); diff --git a/packages/create-block/lib/templates.js b/packages/create-block/lib/templates.js index aa28fb1c0c4a1d..0864c995f5e972 100644 --- a/packages/create-block/lib/templates.js +++ b/packages/create-block/lib/templates.js @@ -2,6 +2,8 @@ * External dependencies */ const glob = require( 'fast-glob' ); +const { readFile } = require( 'fs' ).promises; +const { fromPairs } = require( 'lodash' ); const { join } = require( 'path' ); /** @@ -10,7 +12,7 @@ const { join } = require( 'path' ); const CLIError = require( './cli-error' ); const prompts = require( './prompts' ); -const templates = { +const predefinedBlockTemplates = { es5: { defaultValues: { slug: 'es5-example', @@ -32,18 +34,18 @@ const templates = { }, }; -const getTemplate = ( templateName ) => { - if ( ! templates[ templateName ] ) { +const getBlockTemplate = ( templateName ) => { + if ( ! predefinedBlockTemplates[ templateName ] ) { throw new CLIError( - `Invalid template type name. Allowed values: ${ Object.keys( - templates + `Invalid block template type name. Allowed values: ${ Object.keys( + predefinedBlockTemplates ).join( ', ' ) }.` ); } - return templates[ templateName ]; + return predefinedBlockTemplates[ templateName ]; }; -const getDefaultValues = ( templateName ) => { +const getDefaultValues = ( blockTemplate ) => { return { namespace: 'create-block', dashicon: 'smiley', @@ -52,21 +54,35 @@ const getDefaultValues = ( templateName ) => { license: 'GPL-2.0-or-later', licenseURI: 'https://www.gnu.org/licenses/gpl-2.0.html', version: '0.1.0', - ...getTemplate( templateName ).defaultValues, + ...blockTemplate.defaultValues, }; }; -const getOutputFiles = async ( templateName ) => { - const templatesPath = getTemplate( templateName ).templatesPath; - - return await glob( '**/*.mustache', { - cwd: join( __dirname, templatesPath ), +const getOutputTemplates = async ( blockTemplate ) => { + const outputTemplatesPath = join( __dirname, blockTemplate.templatesPath ); + const outputTemplatesFiles = await glob( '**/*.mustache', { + cwd: outputTemplatesPath, dot: true, } ); + return fromPairs( + await Promise.all( + outputTemplatesFiles.map( async ( outputTemplateFile ) => { + const outputFile = outputTemplateFile.replace( + '.mustache', + '' + ); + const outputTemplate = await readFile( + join( outputTemplatesPath, outputTemplateFile ), + 'utf8' + ); + return [ outputFile, outputTemplate ]; + } ) + ) + ); }; -const getPrompts = ( templateName ) => { - const defaultValues = getDefaultValues( templateName ); +const getPrompts = ( blockTemplate ) => { + const defaultValues = getDefaultValues( blockTemplate ); return Object.keys( prompts ).map( ( promptName ) => { return { ...prompts[ promptName ], @@ -75,13 +91,14 @@ const getPrompts = ( templateName ) => { } ); }; -const hasWPScriptsEnabled = ( templateName ) => { - return ! ( getTemplate( templateName ).wpScripts === false ); +const hasWPScriptsEnabled = ( blockTemplate ) => { + return ! ( blockTemplate.wpScripts === false ); }; module.exports = { + getBlockTemplate, getDefaultValues, - getOutputFiles, + getOutputTemplates, getPrompts, hasWPScriptsEnabled, }; From a6906767fe4cad7aee62aa2b65963d4b254ee5e6 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Mon, 11 May 2020 13:12:25 +0200 Subject: [PATCH 3/5] Move output files templates to getBlockTemplate --- packages/create-block/lib/index.js | 2 +- packages/create-block/lib/scaffold.js | 4 +- packages/create-block/lib/templates.js | 56 +++++++++++++------------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/packages/create-block/lib/index.js b/packages/create-block/lib/index.js index 1a7befc359093a..b87f08b97b4cce 100644 --- a/packages/create-block/lib/index.js +++ b/packages/create-block/lib/index.js @@ -55,7 +55,7 @@ program ) => { await checkSystemRequirements( engines ); try { - const blockTemplate = getBlockTemplate( templateName ); + const blockTemplate = await getBlockTemplate( templateName ); const defaultValues = getDefaultValues( blockTemplate ); const optionsValues = pickBy( { category, diff --git a/packages/create-block/lib/scaffold.js b/packages/create-block/lib/scaffold.js index dbc3afbc8d8a98..7ad53a1b623c67 100644 --- a/packages/create-block/lib/scaffold.js +++ b/packages/create-block/lib/scaffold.js @@ -12,7 +12,7 @@ const { dirname } = require( 'path' ); */ const initWPScripts = require( './init-wp-scripts' ); const { code, info, success } = require( './log' ); -const { hasWPScriptsEnabled, getOutputTemplates } = require( './templates' ); +const { hasWPScriptsEnabled } = require( './templates' ); module.exports = async function( blockTemplate, @@ -35,6 +35,7 @@ module.exports = async function( info( '' ); info( `Creating a new WordPress block in "${ slug }" folder.` ); + const { outputTemplates } = blockTemplate; const view = { namespace, namespaceSnakeCase: snakeCase( namespace ), @@ -50,7 +51,6 @@ module.exports = async function( licenseURI, textdomain: namespace, }; - const outputTemplates = await getOutputTemplates( blockTemplate ); await Promise.all( Object.keys( outputTemplates ).map( async ( outputFile ) => { // Output files can have names that depend on the slug provided. diff --git a/packages/create-block/lib/templates.js b/packages/create-block/lib/templates.js index 0864c995f5e972..ecfabc5a33d5a9 100644 --- a/packages/create-block/lib/templates.js +++ b/packages/create-block/lib/templates.js @@ -20,7 +20,6 @@ const predefinedBlockTemplates = { description: 'Example block written with ES5 standard and no JSX – no build step required.', }, - templatesPath: './templates/es5', wpScripts: false, }, esnext: { @@ -30,11 +29,33 @@ const predefinedBlockTemplates = { description: 'Example block written with ESNext standard and JSX support – build step required.', }, - templatesPath: './templates/esnext', }, }; -const getBlockTemplate = ( templateName ) => { +const getOutputTemplates = async ( name ) => { + const outputTemplatesPath = join( __dirname, 'templates', name ); + const outputTemplatesFiles = await glob( '**/*.mustache', { + cwd: outputTemplatesPath, + dot: true, + } ); + return fromPairs( + await Promise.all( + outputTemplatesFiles.map( async ( outputTemplateFile ) => { + const outputFile = outputTemplateFile.replace( + '.mustache', + '' + ); + const outputTemplate = await readFile( + join( outputTemplatesPath, outputTemplateFile ), + 'utf8' + ); + return [ outputFile, outputTemplate ]; + } ) + ) + ); +}; + +const getBlockTemplate = async ( templateName ) => { if ( ! predefinedBlockTemplates[ templateName ] ) { throw new CLIError( `Invalid block template type name. Allowed values: ${ Object.keys( @@ -42,7 +63,10 @@ const getBlockTemplate = ( templateName ) => { ).join( ', ' ) }.` ); } - return predefinedBlockTemplates[ templateName ]; + return { + ...predefinedBlockTemplates[ templateName ], + outputTemplates: await getOutputTemplates( templateName ), + }; }; const getDefaultValues = ( blockTemplate ) => { @@ -58,29 +82,6 @@ const getDefaultValues = ( blockTemplate ) => { }; }; -const getOutputTemplates = async ( blockTemplate ) => { - const outputTemplatesPath = join( __dirname, blockTemplate.templatesPath ); - const outputTemplatesFiles = await glob( '**/*.mustache', { - cwd: outputTemplatesPath, - dot: true, - } ); - return fromPairs( - await Promise.all( - outputTemplatesFiles.map( async ( outputTemplateFile ) => { - const outputFile = outputTemplateFile.replace( - '.mustache', - '' - ); - const outputTemplate = await readFile( - join( outputTemplatesPath, outputTemplateFile ), - 'utf8' - ); - return [ outputFile, outputTemplate ]; - } ) - ) - ); -}; - const getPrompts = ( blockTemplate ) => { const defaultValues = getDefaultValues( blockTemplate ); return Object.keys( prompts ).map( ( promptName ) => { @@ -98,7 +99,6 @@ const hasWPScriptsEnabled = ( blockTemplate ) => { module.exports = { getBlockTemplate, getDefaultValues, - getOutputTemplates, getPrompts, hasWPScriptsEnabled, }; From 0565d1510f40d767b0201f6f541945c88502ea35 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Mon, 11 May 2020 13:17:11 +0200 Subject: [PATCH 4/5] Add CHANGELOG entry --- packages/create-block/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/create-block/CHANGELOG.md b/packages/create-block/CHANGELOG.md index 391c2822b2f5ae..d36db25ccae884 100644 --- a/packages/create-block/CHANGELOG.md +++ b/packages/create-block/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Internal + +- Refactored handling of predefined block templates [#22235](https://github.com/WordPress/gutenberg/pull/22235). + ## 0.12.0 (2020-04-30) ### New Features From 41c105fd6d0c33e26cefca6882bc47a79a2c602d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Wed, 13 May 2020 09:13:09 +0200 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Andrew Duthie --- packages/create-block/lib/templates.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/create-block/lib/templates.js b/packages/create-block/lib/templates.js index ecfabc5a33d5a9..683f9e3b3855b0 100644 --- a/packages/create-block/lib/templates.js +++ b/packages/create-block/lib/templates.js @@ -42,7 +42,7 @@ const getOutputTemplates = async ( name ) => { await Promise.all( outputTemplatesFiles.map( async ( outputTemplateFile ) => { const outputFile = outputTemplateFile.replace( - '.mustache', + /\.mustache$/, '' ); const outputTemplate = await readFile( @@ -93,7 +93,7 @@ const getPrompts = ( blockTemplate ) => { }; const hasWPScriptsEnabled = ( blockTemplate ) => { - return ! ( blockTemplate.wpScripts === false ); + return blockTemplate.wpScripts !== false; }; module.exports = {