From bfada879f4ec072a77804299a303937ff4e6a1a8 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Thu, 19 Mar 2026 06:57:58 -0400 Subject: [PATCH 1/3] Remove old block editor package sync scripts. --- Gruntfile.js | 45 ----- package.json | 4 +- tools/gutenberg/utils.js | 55 +++++- tools/release/sync-gutenberg-packages.js | 227 ----------------------- tools/release/sync-stable-blocks.js | 144 -------------- 5 files changed, 46 insertions(+), 429 deletions(-) delete mode 100644 tools/release/sync-gutenberg-packages.js delete mode 100644 tools/release/sync-stable-blocks.js diff --git a/Gruntfile.js b/Gruntfile.js index d6b33d391e6d5..dddc595d2e29d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1564,36 +1564,6 @@ module.exports = function(grunt) { 'qunit:compiled' ] ); - grunt.registerTask( 'sync-gutenberg-packages', function() { - if ( grunt.option( 'update-browserlist' ) ) { - /* - * Updating the browserlist database is opt-in and up to the release lead. - * - * Browserlist database should be updated: - * - In each release cycle up until RC1 - * - If Webpack throws a warning about an outdated database - * - * It should not be updated: - * - After the RC1 - * - When backporting fixes to older WordPress releases. - * - * For more context, see: - * https://github.com/WordPress/wordpress-develop/pull/2621#discussion_r859840515 - * https://core.trac.wordpress.org/ticket/55559 - */ - grunt.task.run( 'browserslist:update' ); - } - - // Install the latest version of the packages already listed in package.json. - grunt.task.run( 'wp-packages:update' ); - - /* - * Install any new @wordpress packages that are now required. - * Update any non-@wordpress deps to the same version as required in the @wordpress packages (e.g. react 16 -> 17). - */ - grunt.task.run( 'wp-packages:refresh-deps' ); - } ); - // Gutenberg integration tasks. grunt.registerTask( 'gutenberg:verify', 'Verifies the installed Gutenberg version matches the expected SHA.', function() { const done = this.async(); @@ -2227,21 +2197,6 @@ module.exports = function(grunt) { } ); } ); - grunt.registerTask( 'wp-packages:refresh-deps', 'Update version of dependencies in package.json to match the ones listed in the latest WordPress packages', function() { - const distTag = grunt.option('dist-tag') || 'latest'; - grunt.log.writeln( `Updating versions of dependencies listed in package.json (--dist-tag=${distTag})` ); - spawn( 'node', [ 'tools/release/sync-gutenberg-packages.js', `--dist-tag=${distTag}` ], { - cwd: __dirname, - stdio: 'inherit', - } ); - } ); - - grunt.registerTask( 'wp-packages:sync-stable-blocks', 'Refresh the PHP files referring to stable @wordpress/block-library blocks.', function() { - grunt.log.writeln( `Syncing stable blocks from @wordpress/block-library to src/` ); - const { main } = require( './tools/release/sync-stable-blocks' ); - main(); - } ); - // Patch task. grunt.renameTask('patch_wordpress', 'patch'); diff --git a/package.json b/package.json index 3084630a2d726..5e340bd0bebb8 100644 --- a/package.json +++ b/package.json @@ -142,8 +142,6 @@ "gutenberg:copy": "node tools/gutenberg/copy.js", "gutenberg:verify": "node tools/gutenberg/utils.js", "gutenberg:download": "node tools/gutenberg/download.js && grunt build:gutenberg --dev", - "vendor:copy": "node tools/vendors/copy-vendors.js", - "sync-gutenberg-packages": "grunt sync-gutenberg-packages", - "postsync-gutenberg-packages": "grunt wp-packages:sync-stable-blocks && grunt build --dev && grunt build" + "vendor:copy": "node tools/vendors/copy-vendors.js" } } diff --git a/tools/gutenberg/utils.js b/tools/gutenberg/utils.js index dc696d5e7bfd7..398ec344315c9 100644 --- a/tools/gutenberg/utils.js +++ b/tools/gutenberg/utils.js @@ -18,6 +18,7 @@ const path = require( 'path' ); const rootDir = path.resolve( __dirname, '../..' ); const gutenbergDir = path.join( rootDir, 'gutenberg' ); const hashFilePath = path.join( gutenbergDir, '.gutenberg-hash' ); +const srcHashFilePath = path.join( rootDir, 'src/wp-includes/.gutenberg-hash' ); /** * Read Gutenberg configuration from package.json. @@ -41,21 +42,37 @@ function readGutenbergConfig() { return { sha, ghcrRepo }; } +/** + * Copy the Gutenberg build to src/ by running `grunt build:gutenberg --dev` + * as a fresh subprocess (so WORKING_DIR resolves to src/). Writes the current + * SHA to src/wp-includes/.gutenberg-hash afterward so future runs can skip + * the copy when nothing has changed. + * Exits the process if the copy fails. + * + * @param {string} sha The expected Gutenberg SHA, written to the src hash file. + */ +function copyGutenbergToSrc( sha ) { + const buildResult = spawnSync( 'grunt', [ 'build:gutenberg', '--dev' ], { stdio: 'inherit', shell: true } ); + if ( buildResult.status !== 0 ) { + process.exit( buildResult.status ?? 1 ); + } + fs.mkdirSync( path.dirname( srcHashFilePath ), { recursive: true } ); + fs.writeFileSync( srcHashFilePath, sha ); +} + /** * Trigger a fresh download of the Gutenberg artifact by spawning download.js, - * then run `grunt build:gutenberg --dev` to copy the build to src/. + * then copy the build to src/. * Exits the process if either step fails. + * + * @param {string} sha The expected Gutenberg SHA. */ -function downloadGutenberg() { +function downloadGutenberg( sha ) { const downloadResult = spawnSync( 'node', [ path.join( __dirname, 'download.js' ) ], { stdio: 'inherit' } ); if ( downloadResult.status !== 0 ) { process.exit( downloadResult.status ?? 1 ); } - - const buildResult = spawnSync( 'grunt', [ 'build:gutenberg', '--dev' ], { stdio: 'inherit', shell: true } ); - if ( buildResult.status !== 0 ) { - process.exit( buildResult.status ?? 1 ); - } + copyGutenbergToSrc( sha ); } /** @@ -78,7 +95,7 @@ function verifyGutenbergVersion() { // Check for conditions that require a fresh download. if ( ! fs.existsSync( gutenbergDir ) ) { console.log( 'ℹ️ Gutenberg directory not found. Downloading...' ); - downloadGutenberg(); + downloadGutenberg( sha ); } else { let installedHash = null; try { @@ -92,10 +109,10 @@ function verifyGutenbergVersion() { if ( installedHash === null ) { console.log( 'ℹ️ Hash file not found. Downloading expected version...' ); - downloadGutenberg(); + downloadGutenberg( sha ); } else if ( installedHash !== sha ) { console.log( `ℹ️ Hash mismatch (found ${ installedHash }, expected ${ sha }). Downloading expected version...` ); - downloadGutenberg(); + downloadGutenberg( sha ); } } @@ -115,6 +132,24 @@ function verifyGutenbergVersion() { process.exit( 1 ); } + // If the artifact is current but src/ was never populated (or is stale), + // copy now. This handles environments where the artifact was cached before + // this copy step was introduced. + let srcHash = null; + try { + srcHash = fs.readFileSync( srcHashFilePath, 'utf8' ).trim(); + } catch ( error ) { + if ( error.code !== 'ENOENT' ) { + console.error( `❌ ${ error.message }` ); + process.exit( 1 ); + } + } + + if ( srcHash !== sha ) { + console.log( 'ℹ️ Gutenberg files in src/ are missing or outdated. Copying...' ); + copyGutenbergToSrc( sha ); + } + console.log( '✅ Version verified' ); } diff --git a/tools/release/sync-gutenberg-packages.js b/tools/release/sync-gutenberg-packages.js deleted file mode 100644 index a8ea545e18514..0000000000000 --- a/tools/release/sync-gutenberg-packages.js +++ /dev/null @@ -1,227 +0,0 @@ -/* eslint-disable no-console */ -/** - * External dependencies - */ -const fs = require( 'fs' ); -const spawn = require( 'cross-spawn' ); -const { zip, uniq, identity, groupBy } = require( 'lodash' ); - -/** - * Constants - */ -const WORDPRESS_PACKAGES_PREFIX = '@wordpress/'; -const { getArgFromCLI } = require( `../../node_modules/@wordpress/scripts/utils` ); -const distTag = getArgFromCLI( '--dist-tag' ) || 'latest'; - -/** - * The main function of this task. - * - * It installs any missing WordPress packages, and updates the - * mismatched dependencies versions, e.g. it would detect that Gutenberg - * updated react from 16.0.4 to 17.0.2 and install the latter. - */ -function main() { - const initialPackageJSON = readJSONFile( `package.json` ); - - // Install any missing WordPress packages: - const missingWordPressPackages = getMissingWordPressPackages(); - if ( missingWordPressPackages.length ) { - console.log( "The following @wordpress dependencies are missing: " ); - console.log( missingWordPressPackages ); - console.log( "Installing via npm..." ); - installPackages( missingWordPressPackages.map( name => [name, distTag] ) ); - } - - // Update any outdated non-WordPress packages: - const versionMismatches = getMismatchedNonWordPressDependencies(); - if ( versionMismatches.length ) { - console.log( "The following dependencies are outdated: " ); - console.log( versionMismatches ); - console.log( "Updating via npm..." ); - const requiredPackages = versionMismatches.map( ( { name, required } ) => [name, required] ); - installPackages( requiredPackages ); - } - - const finalPackageJSON = readJSONFile( "package.json" ); - outputPackageDiffReport( - getPackageVersionDiff( initialPackageJSON, finalPackageJSON ), - ); - process.exit( 0 ); -} - -/** - * @param {string} fileName File to read. - * @return {Object} Parsed data. - */ -function readJSONFile( fileName ) { - const data = fs.readFileSync( fileName, 'utf8' ); - return JSON.parse( data ); -} - -/** - * Spawns npm install --save. - * - * @param {Array} packages List of tuples [packageName, version] to install. - * @return {string} CLI output. - */ -function installPackages( packages ) { - const packagesWithVersion = packages.map( - ( [packageName, version] ) => `${ packageName }@${ version }`, - ); - return spawn.sync( 'npm', ['install', ...packagesWithVersion, '--save'], { - stdio: 'inherit', - } ); -} - -/** - * Computes which @wordpress packages are required by the Gutenberg - * dependencies that are missing from WordPress package.json. - * - * @return {Array} List of tuples [packageName, version]. - */ -function getMissingWordPressPackages() { - const perPackageDeps = getPerPackageDeps(); - const currentPackages = perPackageDeps.map( ( [name] ) => name ); - - const requiredWpPackages = uniq( perPackageDeps - // Capture the @wordpress dependencies of our dependencies into a flat list. - .flatMap( ( [, dependencies] ) => getWordPressPackages( { dependencies } ) ) - .sort(), - ); - - return requiredWpPackages.filter( - packageName => !currentPackages.includes( packageName ) ); -} - -/** - * Computes which third party packages are required by the @wordpress - * packages, but not by the WordPress repo itself. This includes - * both packages that are missing from package.json and any version - * mismatches. - * - * @return {Array} List of objects {name, required, actual} describing version mismatches. - */ -function getMismatchedNonWordPressDependencies() { - // Get the installed dependencies from package-lock.json - const currentPackageJSON = readJSONFile( "package.json" ); - const currentPackages = getWordPressPackages( currentPackageJSON ); - - const packageLock = readJSONFile( "package-lock.json" ); - const versionConflicts = Object.entries( packageLock.packages[''].dependencies ) - .filter( ( [packageName] ) => currentPackages.includes( packageName ) ) - .flatMap( ( [, { dependencies }] ) => Object.entries( dependencies || {} ) ) - .filter( identity ) - .map( ( [name, { version }] ) => ( { - name, - required: version, - actual: packageLock.dependencies[ name ].version, - } ) ) - .filter( ( { required, actual } ) => required !== actual ) - ; - - // Ensure that all the conflicts can be resolved with the same version - const unresolvableConflicts = Object.entries( groupBy( versionConflicts, ( {name} ) => name ) ) - .map( ( [name, group] ) => [name, uniq( group.map( ( { required } ) => required ) )] ) - .filter( ( [, group] ) => group.length > 1 ); - if ( unresolvableConflicts.length > 0 ) { - console.error( "Can't resolve some conflicts automatically." ); - console.error( "Multiple required versions of the following packages were detected:" ); - console.error( unresolvableConflicts ); - process.exit( 1 ); - } - return versionConflicts; -} - -/** - * Returns a list of dependencies of each @wordpress dependency. - * - * @return {Object} An object of shape {packageName: [[packageName, version]]}. - */ -function getPerPackageDeps() { - // Get the dependencies currently listed in the wordpress-develop package.json - const currentPackageJSON = readJSONFile( "package.json" ); - const currentPackages = getWordPressPackages( currentPackageJSON ); - - // Get the dependencies that the above dependencies list in their package.json. - const deps = currentPackages - .map( ( packageName ) => `node_modules/${ packageName }/package.json` ) - .map( ( jsonPath ) => readJSONFile( jsonPath ).dependencies ); - return zip( currentPackages, deps ); -} - -/** - * Takes unserialized package.json data and returns a list of @wordpress dependencies. - * - * @param {Object} dependencies unserialized package.json data. - * @return {string[]} a list of @wordpress dependencies. - */ -function getWordPressPackages( { dependencies = {} } ) { - return Object.keys( dependencies ) - .filter( isWordPressPackage ); -} - -/** - * Returns true if packageName represents a @wordpress package. - * - * @param {string} packageName Package name to test. - * @return {boolean} Is it a @wodpress package? - */ -function isWordPressPackage( packageName ) { - return packageName.startsWith( WORDPRESS_PACKAGES_PREFIX ); -} - -/** - * Computes the dependencies difference between two unserialized - * package JSON objects. Needed only for the final reporting. - * - * @param {Object} initialPackageJSON Initial package JSON data. - * @param {Object} finalPackageJSON Final package JSON data. - * @return {Object} Delta. - */ -function getPackageVersionDiff( initialPackageJSON, finalPackageJSON ) { - const diff = ['dependencies', 'devDependencies'].reduce( - ( result, keyPackageJSON ) => { - return Object.keys( - finalPackageJSON[ keyPackageJSON ] || {}, - ).reduce( ( _result, dependency ) => { - const initial = - initialPackageJSON[ keyPackageJSON ][ dependency ]; - const final = finalPackageJSON[ keyPackageJSON ][ dependency ]; - if ( initial !== final ) { - _result.push( { dependency, initial, final } ); - } - return _result; - }, result ); - }, - [], - ); - return diff.sort( ( a, b ) => a.dependency.localeCompare( b.dependency ) ); -} - -/** - * Prints the delta between two package.json files. - * - * @param {Object} packageDiff Delta. - */ -function outputPackageDiffReport( packageDiff ) { - const readableDiff = - packageDiff - .map( ( { dependency, initial, final } ) => { - return `${ dependency }: ${ initial } -> ${ final }`; - } ) - .filter( identity ); - if ( !readableDiff.length ) { - console.log( 'No changes detected' ); - return; - } - console.log( - [ - 'The following package versions were changed:', - ...readableDiff, - ].join( '\n' ), - ); -} - -main(); - -/* eslint-enable no-console */ diff --git a/tools/release/sync-stable-blocks.js b/tools/release/sync-stable-blocks.js deleted file mode 100644 index 3f2a1727d7e3b..0000000000000 --- a/tools/release/sync-stable-blocks.js +++ /dev/null @@ -1,144 +0,0 @@ -/* eslint-disable no-console */ -/** - * External dependencies - */ -const fs = require( 'fs' ); -const path = require( 'path' ); - -/** - * Constants - */ -const BLOCK_LIBRARY_SRC = 'node_modules/@wordpress/block-library/src/'; - -const REPOSITORY_ROOT = path.dirname( path.dirname( __dirname ) ); - -/** - * The main function of this task. - * - * Refreshes the PHP files referring to stable @wordpress/block-library blocks. - */ -function main() { - const blocks = getStableBlocksMetadata(); - const toolWarningMessage = '// This file was autogenerated by tools/release/sync-stable-blocks.js, do not change manually!'; - - // wp-includes/blocks/require-blocks.php - console.log( 'Refreshing wp-includes/blocks/require-static-blocks.php...' ); - const staticBlockFolderNames = blocks - .filter( ( metadata ) => ! isDynamic( metadata ) ) - .map( toDirectoryName ) - .sort() - // To the block folder name statement: - .map( dirname => ` '${ dirname }',` ) - .join( "\n" ); - - fs.writeFileSync( - `${ REPOSITORY_ROOT }/src/wp-includes/blocks/require-static-blocks.php`, - ` `require_once ABSPATH . WPINC . '/blocks/${ dirname }.php';` ) - .join( "\n" ); - - fs.writeFileSync( - `${ REPOSITORY_ROOT }/src/wp-includes/blocks/require-dynamic-blocks.php`, - ` path.join( BLOCK_LIBRARY_SRC, dirMaybe, 'block.json' ) ) - .filter( fs.existsSync ) - .map( blockJsonPath => ( { - ...JSON.parse( fs.readFileSync( blockJsonPath ) ), - path: blockJsonPath, - } ) ) - .filter( metadata => ( - !( '__experimental' in metadata ) || metadata.__experimental === false - ) ) - ); -} - -/** - * Returns true if the specified metadata refers to a dynamic block. - * - * @param {Object} metadata Block metadata in question. - * @return {boolean} Is it a dynamic block? - */ -function isDynamic( metadata ) { - return ( - fs.existsSync( path.join( metadata.path, '..', 'index.php' ) ) - ); -} - -/** - * Returns a name of the directory where a given block resides. - * - * @param {Object} metadata Block metadata in question. - * @return {string} Parent directory name. - */ -function toDirectoryName( metadata ) { - return ( - path.basename( path.dirname( metadata.path ) ) - ); -} - -module.exports = { - main, - isDynamic, - toDirectoryName, - getStableBlocksMetadata, -}; - -/* eslint-enable no-console */ From 30e36e7198e0d70e5b313bc5b5974ad9d9dbf7bc Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Thu, 19 Mar 2026 08:14:19 -0400 Subject: [PATCH 2/3] Revert "Remove old block editor package sync scripts." This reverts commit bfada879f4ec072a77804299a303937ff4e6a1a8. --- Gruntfile.js | 45 +++++ package.json | 4 +- tools/gutenberg/utils.js | 55 +----- tools/release/sync-gutenberg-packages.js | 227 +++++++++++++++++++++++ tools/release/sync-stable-blocks.js | 144 ++++++++++++++ 5 files changed, 429 insertions(+), 46 deletions(-) create mode 100644 tools/release/sync-gutenberg-packages.js create mode 100644 tools/release/sync-stable-blocks.js diff --git a/Gruntfile.js b/Gruntfile.js index dddc595d2e29d..d6b33d391e6d5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1564,6 +1564,36 @@ module.exports = function(grunt) { 'qunit:compiled' ] ); + grunt.registerTask( 'sync-gutenberg-packages', function() { + if ( grunt.option( 'update-browserlist' ) ) { + /* + * Updating the browserlist database is opt-in and up to the release lead. + * + * Browserlist database should be updated: + * - In each release cycle up until RC1 + * - If Webpack throws a warning about an outdated database + * + * It should not be updated: + * - After the RC1 + * - When backporting fixes to older WordPress releases. + * + * For more context, see: + * https://github.com/WordPress/wordpress-develop/pull/2621#discussion_r859840515 + * https://core.trac.wordpress.org/ticket/55559 + */ + grunt.task.run( 'browserslist:update' ); + } + + // Install the latest version of the packages already listed in package.json. + grunt.task.run( 'wp-packages:update' ); + + /* + * Install any new @wordpress packages that are now required. + * Update any non-@wordpress deps to the same version as required in the @wordpress packages (e.g. react 16 -> 17). + */ + grunt.task.run( 'wp-packages:refresh-deps' ); + } ); + // Gutenberg integration tasks. grunt.registerTask( 'gutenberg:verify', 'Verifies the installed Gutenberg version matches the expected SHA.', function() { const done = this.async(); @@ -2197,6 +2227,21 @@ module.exports = function(grunt) { } ); } ); + grunt.registerTask( 'wp-packages:refresh-deps', 'Update version of dependencies in package.json to match the ones listed in the latest WordPress packages', function() { + const distTag = grunt.option('dist-tag') || 'latest'; + grunt.log.writeln( `Updating versions of dependencies listed in package.json (--dist-tag=${distTag})` ); + spawn( 'node', [ 'tools/release/sync-gutenberg-packages.js', `--dist-tag=${distTag}` ], { + cwd: __dirname, + stdio: 'inherit', + } ); + } ); + + grunt.registerTask( 'wp-packages:sync-stable-blocks', 'Refresh the PHP files referring to stable @wordpress/block-library blocks.', function() { + grunt.log.writeln( `Syncing stable blocks from @wordpress/block-library to src/` ); + const { main } = require( './tools/release/sync-stable-blocks' ); + main(); + } ); + // Patch task. grunt.renameTask('patch_wordpress', 'patch'); diff --git a/package.json b/package.json index 5e340bd0bebb8..3084630a2d726 100644 --- a/package.json +++ b/package.json @@ -142,6 +142,8 @@ "gutenberg:copy": "node tools/gutenberg/copy.js", "gutenberg:verify": "node tools/gutenberg/utils.js", "gutenberg:download": "node tools/gutenberg/download.js && grunt build:gutenberg --dev", - "vendor:copy": "node tools/vendors/copy-vendors.js" + "vendor:copy": "node tools/vendors/copy-vendors.js", + "sync-gutenberg-packages": "grunt sync-gutenberg-packages", + "postsync-gutenberg-packages": "grunt wp-packages:sync-stable-blocks && grunt build --dev && grunt build" } } diff --git a/tools/gutenberg/utils.js b/tools/gutenberg/utils.js index 398ec344315c9..dc696d5e7bfd7 100644 --- a/tools/gutenberg/utils.js +++ b/tools/gutenberg/utils.js @@ -18,7 +18,6 @@ const path = require( 'path' ); const rootDir = path.resolve( __dirname, '../..' ); const gutenbergDir = path.join( rootDir, 'gutenberg' ); const hashFilePath = path.join( gutenbergDir, '.gutenberg-hash' ); -const srcHashFilePath = path.join( rootDir, 'src/wp-includes/.gutenberg-hash' ); /** * Read Gutenberg configuration from package.json. @@ -42,37 +41,21 @@ function readGutenbergConfig() { return { sha, ghcrRepo }; } -/** - * Copy the Gutenberg build to src/ by running `grunt build:gutenberg --dev` - * as a fresh subprocess (so WORKING_DIR resolves to src/). Writes the current - * SHA to src/wp-includes/.gutenberg-hash afterward so future runs can skip - * the copy when nothing has changed. - * Exits the process if the copy fails. - * - * @param {string} sha The expected Gutenberg SHA, written to the src hash file. - */ -function copyGutenbergToSrc( sha ) { - const buildResult = spawnSync( 'grunt', [ 'build:gutenberg', '--dev' ], { stdio: 'inherit', shell: true } ); - if ( buildResult.status !== 0 ) { - process.exit( buildResult.status ?? 1 ); - } - fs.mkdirSync( path.dirname( srcHashFilePath ), { recursive: true } ); - fs.writeFileSync( srcHashFilePath, sha ); -} - /** * Trigger a fresh download of the Gutenberg artifact by spawning download.js, - * then copy the build to src/. + * then run `grunt build:gutenberg --dev` to copy the build to src/. * Exits the process if either step fails. - * - * @param {string} sha The expected Gutenberg SHA. */ -function downloadGutenberg( sha ) { +function downloadGutenberg() { const downloadResult = spawnSync( 'node', [ path.join( __dirname, 'download.js' ) ], { stdio: 'inherit' } ); if ( downloadResult.status !== 0 ) { process.exit( downloadResult.status ?? 1 ); } - copyGutenbergToSrc( sha ); + + const buildResult = spawnSync( 'grunt', [ 'build:gutenberg', '--dev' ], { stdio: 'inherit', shell: true } ); + if ( buildResult.status !== 0 ) { + process.exit( buildResult.status ?? 1 ); + } } /** @@ -95,7 +78,7 @@ function verifyGutenbergVersion() { // Check for conditions that require a fresh download. if ( ! fs.existsSync( gutenbergDir ) ) { console.log( 'ℹ️ Gutenberg directory not found. Downloading...' ); - downloadGutenberg( sha ); + downloadGutenberg(); } else { let installedHash = null; try { @@ -109,10 +92,10 @@ function verifyGutenbergVersion() { if ( installedHash === null ) { console.log( 'ℹ️ Hash file not found. Downloading expected version...' ); - downloadGutenberg( sha ); + downloadGutenberg(); } else if ( installedHash !== sha ) { console.log( `ℹ️ Hash mismatch (found ${ installedHash }, expected ${ sha }). Downloading expected version...` ); - downloadGutenberg( sha ); + downloadGutenberg(); } } @@ -132,24 +115,6 @@ function verifyGutenbergVersion() { process.exit( 1 ); } - // If the artifact is current but src/ was never populated (or is stale), - // copy now. This handles environments where the artifact was cached before - // this copy step was introduced. - let srcHash = null; - try { - srcHash = fs.readFileSync( srcHashFilePath, 'utf8' ).trim(); - } catch ( error ) { - if ( error.code !== 'ENOENT' ) { - console.error( `❌ ${ error.message }` ); - process.exit( 1 ); - } - } - - if ( srcHash !== sha ) { - console.log( 'ℹ️ Gutenberg files in src/ are missing or outdated. Copying...' ); - copyGutenbergToSrc( sha ); - } - console.log( '✅ Version verified' ); } diff --git a/tools/release/sync-gutenberg-packages.js b/tools/release/sync-gutenberg-packages.js new file mode 100644 index 0000000000000..a8ea545e18514 --- /dev/null +++ b/tools/release/sync-gutenberg-packages.js @@ -0,0 +1,227 @@ +/* eslint-disable no-console */ +/** + * External dependencies + */ +const fs = require( 'fs' ); +const spawn = require( 'cross-spawn' ); +const { zip, uniq, identity, groupBy } = require( 'lodash' ); + +/** + * Constants + */ +const WORDPRESS_PACKAGES_PREFIX = '@wordpress/'; +const { getArgFromCLI } = require( `../../node_modules/@wordpress/scripts/utils` ); +const distTag = getArgFromCLI( '--dist-tag' ) || 'latest'; + +/** + * The main function of this task. + * + * It installs any missing WordPress packages, and updates the + * mismatched dependencies versions, e.g. it would detect that Gutenberg + * updated react from 16.0.4 to 17.0.2 and install the latter. + */ +function main() { + const initialPackageJSON = readJSONFile( `package.json` ); + + // Install any missing WordPress packages: + const missingWordPressPackages = getMissingWordPressPackages(); + if ( missingWordPressPackages.length ) { + console.log( "The following @wordpress dependencies are missing: " ); + console.log( missingWordPressPackages ); + console.log( "Installing via npm..." ); + installPackages( missingWordPressPackages.map( name => [name, distTag] ) ); + } + + // Update any outdated non-WordPress packages: + const versionMismatches = getMismatchedNonWordPressDependencies(); + if ( versionMismatches.length ) { + console.log( "The following dependencies are outdated: " ); + console.log( versionMismatches ); + console.log( "Updating via npm..." ); + const requiredPackages = versionMismatches.map( ( { name, required } ) => [name, required] ); + installPackages( requiredPackages ); + } + + const finalPackageJSON = readJSONFile( "package.json" ); + outputPackageDiffReport( + getPackageVersionDiff( initialPackageJSON, finalPackageJSON ), + ); + process.exit( 0 ); +} + +/** + * @param {string} fileName File to read. + * @return {Object} Parsed data. + */ +function readJSONFile( fileName ) { + const data = fs.readFileSync( fileName, 'utf8' ); + return JSON.parse( data ); +} + +/** + * Spawns npm install --save. + * + * @param {Array} packages List of tuples [packageName, version] to install. + * @return {string} CLI output. + */ +function installPackages( packages ) { + const packagesWithVersion = packages.map( + ( [packageName, version] ) => `${ packageName }@${ version }`, + ); + return spawn.sync( 'npm', ['install', ...packagesWithVersion, '--save'], { + stdio: 'inherit', + } ); +} + +/** + * Computes which @wordpress packages are required by the Gutenberg + * dependencies that are missing from WordPress package.json. + * + * @return {Array} List of tuples [packageName, version]. + */ +function getMissingWordPressPackages() { + const perPackageDeps = getPerPackageDeps(); + const currentPackages = perPackageDeps.map( ( [name] ) => name ); + + const requiredWpPackages = uniq( perPackageDeps + // Capture the @wordpress dependencies of our dependencies into a flat list. + .flatMap( ( [, dependencies] ) => getWordPressPackages( { dependencies } ) ) + .sort(), + ); + + return requiredWpPackages.filter( + packageName => !currentPackages.includes( packageName ) ); +} + +/** + * Computes which third party packages are required by the @wordpress + * packages, but not by the WordPress repo itself. This includes + * both packages that are missing from package.json and any version + * mismatches. + * + * @return {Array} List of objects {name, required, actual} describing version mismatches. + */ +function getMismatchedNonWordPressDependencies() { + // Get the installed dependencies from package-lock.json + const currentPackageJSON = readJSONFile( "package.json" ); + const currentPackages = getWordPressPackages( currentPackageJSON ); + + const packageLock = readJSONFile( "package-lock.json" ); + const versionConflicts = Object.entries( packageLock.packages[''].dependencies ) + .filter( ( [packageName] ) => currentPackages.includes( packageName ) ) + .flatMap( ( [, { dependencies }] ) => Object.entries( dependencies || {} ) ) + .filter( identity ) + .map( ( [name, { version }] ) => ( { + name, + required: version, + actual: packageLock.dependencies[ name ].version, + } ) ) + .filter( ( { required, actual } ) => required !== actual ) + ; + + // Ensure that all the conflicts can be resolved with the same version + const unresolvableConflicts = Object.entries( groupBy( versionConflicts, ( {name} ) => name ) ) + .map( ( [name, group] ) => [name, uniq( group.map( ( { required } ) => required ) )] ) + .filter( ( [, group] ) => group.length > 1 ); + if ( unresolvableConflicts.length > 0 ) { + console.error( "Can't resolve some conflicts automatically." ); + console.error( "Multiple required versions of the following packages were detected:" ); + console.error( unresolvableConflicts ); + process.exit( 1 ); + } + return versionConflicts; +} + +/** + * Returns a list of dependencies of each @wordpress dependency. + * + * @return {Object} An object of shape {packageName: [[packageName, version]]}. + */ +function getPerPackageDeps() { + // Get the dependencies currently listed in the wordpress-develop package.json + const currentPackageJSON = readJSONFile( "package.json" ); + const currentPackages = getWordPressPackages( currentPackageJSON ); + + // Get the dependencies that the above dependencies list in their package.json. + const deps = currentPackages + .map( ( packageName ) => `node_modules/${ packageName }/package.json` ) + .map( ( jsonPath ) => readJSONFile( jsonPath ).dependencies ); + return zip( currentPackages, deps ); +} + +/** + * Takes unserialized package.json data and returns a list of @wordpress dependencies. + * + * @param {Object} dependencies unserialized package.json data. + * @return {string[]} a list of @wordpress dependencies. + */ +function getWordPressPackages( { dependencies = {} } ) { + return Object.keys( dependencies ) + .filter( isWordPressPackage ); +} + +/** + * Returns true if packageName represents a @wordpress package. + * + * @param {string} packageName Package name to test. + * @return {boolean} Is it a @wodpress package? + */ +function isWordPressPackage( packageName ) { + return packageName.startsWith( WORDPRESS_PACKAGES_PREFIX ); +} + +/** + * Computes the dependencies difference between two unserialized + * package JSON objects. Needed only for the final reporting. + * + * @param {Object} initialPackageJSON Initial package JSON data. + * @param {Object} finalPackageJSON Final package JSON data. + * @return {Object} Delta. + */ +function getPackageVersionDiff( initialPackageJSON, finalPackageJSON ) { + const diff = ['dependencies', 'devDependencies'].reduce( + ( result, keyPackageJSON ) => { + return Object.keys( + finalPackageJSON[ keyPackageJSON ] || {}, + ).reduce( ( _result, dependency ) => { + const initial = + initialPackageJSON[ keyPackageJSON ][ dependency ]; + const final = finalPackageJSON[ keyPackageJSON ][ dependency ]; + if ( initial !== final ) { + _result.push( { dependency, initial, final } ); + } + return _result; + }, result ); + }, + [], + ); + return diff.sort( ( a, b ) => a.dependency.localeCompare( b.dependency ) ); +} + +/** + * Prints the delta between two package.json files. + * + * @param {Object} packageDiff Delta. + */ +function outputPackageDiffReport( packageDiff ) { + const readableDiff = + packageDiff + .map( ( { dependency, initial, final } ) => { + return `${ dependency }: ${ initial } -> ${ final }`; + } ) + .filter( identity ); + if ( !readableDiff.length ) { + console.log( 'No changes detected' ); + return; + } + console.log( + [ + 'The following package versions were changed:', + ...readableDiff, + ].join( '\n' ), + ); +} + +main(); + +/* eslint-enable no-console */ diff --git a/tools/release/sync-stable-blocks.js b/tools/release/sync-stable-blocks.js new file mode 100644 index 0000000000000..3f2a1727d7e3b --- /dev/null +++ b/tools/release/sync-stable-blocks.js @@ -0,0 +1,144 @@ +/* eslint-disable no-console */ +/** + * External dependencies + */ +const fs = require( 'fs' ); +const path = require( 'path' ); + +/** + * Constants + */ +const BLOCK_LIBRARY_SRC = 'node_modules/@wordpress/block-library/src/'; + +const REPOSITORY_ROOT = path.dirname( path.dirname( __dirname ) ); + +/** + * The main function of this task. + * + * Refreshes the PHP files referring to stable @wordpress/block-library blocks. + */ +function main() { + const blocks = getStableBlocksMetadata(); + const toolWarningMessage = '// This file was autogenerated by tools/release/sync-stable-blocks.js, do not change manually!'; + + // wp-includes/blocks/require-blocks.php + console.log( 'Refreshing wp-includes/blocks/require-static-blocks.php...' ); + const staticBlockFolderNames = blocks + .filter( ( metadata ) => ! isDynamic( metadata ) ) + .map( toDirectoryName ) + .sort() + // To the block folder name statement: + .map( dirname => ` '${ dirname }',` ) + .join( "\n" ); + + fs.writeFileSync( + `${ REPOSITORY_ROOT }/src/wp-includes/blocks/require-static-blocks.php`, + ` `require_once ABSPATH . WPINC . '/blocks/${ dirname }.php';` ) + .join( "\n" ); + + fs.writeFileSync( + `${ REPOSITORY_ROOT }/src/wp-includes/blocks/require-dynamic-blocks.php`, + ` path.join( BLOCK_LIBRARY_SRC, dirMaybe, 'block.json' ) ) + .filter( fs.existsSync ) + .map( blockJsonPath => ( { + ...JSON.parse( fs.readFileSync( blockJsonPath ) ), + path: blockJsonPath, + } ) ) + .filter( metadata => ( + !( '__experimental' in metadata ) || metadata.__experimental === false + ) ) + ); +} + +/** + * Returns true if the specified metadata refers to a dynamic block. + * + * @param {Object} metadata Block metadata in question. + * @return {boolean} Is it a dynamic block? + */ +function isDynamic( metadata ) { + return ( + fs.existsSync( path.join( metadata.path, '..', 'index.php' ) ) + ); +} + +/** + * Returns a name of the directory where a given block resides. + * + * @param {Object} metadata Block metadata in question. + * @return {string} Parent directory name. + */ +function toDirectoryName( metadata ) { + return ( + path.basename( path.dirname( metadata.path ) ) + ); +} + +module.exports = { + main, + isDynamic, + toDirectoryName, + getStableBlocksMetadata, +}; + +/* eslint-enable no-console */ From cb674edb9d6fd855de9186f11600fb297e1c6e3c Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Thu, 19 Mar 2026 08:18:46 -0400 Subject: [PATCH 3/3] Reapply changes without unrelated ones. --- Gruntfile.js | 45 ----- package.json | 4 +- tools/release/sync-gutenberg-packages.js | 227 ----------------------- tools/release/sync-stable-blocks.js | 144 -------------- 4 files changed, 1 insertion(+), 419 deletions(-) delete mode 100644 tools/release/sync-gutenberg-packages.js delete mode 100644 tools/release/sync-stable-blocks.js diff --git a/Gruntfile.js b/Gruntfile.js index d6b33d391e6d5..dddc595d2e29d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1564,36 +1564,6 @@ module.exports = function(grunt) { 'qunit:compiled' ] ); - grunt.registerTask( 'sync-gutenberg-packages', function() { - if ( grunt.option( 'update-browserlist' ) ) { - /* - * Updating the browserlist database is opt-in and up to the release lead. - * - * Browserlist database should be updated: - * - In each release cycle up until RC1 - * - If Webpack throws a warning about an outdated database - * - * It should not be updated: - * - After the RC1 - * - When backporting fixes to older WordPress releases. - * - * For more context, see: - * https://github.com/WordPress/wordpress-develop/pull/2621#discussion_r859840515 - * https://core.trac.wordpress.org/ticket/55559 - */ - grunt.task.run( 'browserslist:update' ); - } - - // Install the latest version of the packages already listed in package.json. - grunt.task.run( 'wp-packages:update' ); - - /* - * Install any new @wordpress packages that are now required. - * Update any non-@wordpress deps to the same version as required in the @wordpress packages (e.g. react 16 -> 17). - */ - grunt.task.run( 'wp-packages:refresh-deps' ); - } ); - // Gutenberg integration tasks. grunt.registerTask( 'gutenberg:verify', 'Verifies the installed Gutenberg version matches the expected SHA.', function() { const done = this.async(); @@ -2227,21 +2197,6 @@ module.exports = function(grunt) { } ); } ); - grunt.registerTask( 'wp-packages:refresh-deps', 'Update version of dependencies in package.json to match the ones listed in the latest WordPress packages', function() { - const distTag = grunt.option('dist-tag') || 'latest'; - grunt.log.writeln( `Updating versions of dependencies listed in package.json (--dist-tag=${distTag})` ); - spawn( 'node', [ 'tools/release/sync-gutenberg-packages.js', `--dist-tag=${distTag}` ], { - cwd: __dirname, - stdio: 'inherit', - } ); - } ); - - grunt.registerTask( 'wp-packages:sync-stable-blocks', 'Refresh the PHP files referring to stable @wordpress/block-library blocks.', function() { - grunt.log.writeln( `Syncing stable blocks from @wordpress/block-library to src/` ); - const { main } = require( './tools/release/sync-stable-blocks' ); - main(); - } ); - // Patch task. grunt.renameTask('patch_wordpress', 'patch'); diff --git a/package.json b/package.json index 3084630a2d726..5e340bd0bebb8 100644 --- a/package.json +++ b/package.json @@ -142,8 +142,6 @@ "gutenberg:copy": "node tools/gutenberg/copy.js", "gutenberg:verify": "node tools/gutenberg/utils.js", "gutenberg:download": "node tools/gutenberg/download.js && grunt build:gutenberg --dev", - "vendor:copy": "node tools/vendors/copy-vendors.js", - "sync-gutenberg-packages": "grunt sync-gutenberg-packages", - "postsync-gutenberg-packages": "grunt wp-packages:sync-stable-blocks && grunt build --dev && grunt build" + "vendor:copy": "node tools/vendors/copy-vendors.js" } } diff --git a/tools/release/sync-gutenberg-packages.js b/tools/release/sync-gutenberg-packages.js deleted file mode 100644 index a8ea545e18514..0000000000000 --- a/tools/release/sync-gutenberg-packages.js +++ /dev/null @@ -1,227 +0,0 @@ -/* eslint-disable no-console */ -/** - * External dependencies - */ -const fs = require( 'fs' ); -const spawn = require( 'cross-spawn' ); -const { zip, uniq, identity, groupBy } = require( 'lodash' ); - -/** - * Constants - */ -const WORDPRESS_PACKAGES_PREFIX = '@wordpress/'; -const { getArgFromCLI } = require( `../../node_modules/@wordpress/scripts/utils` ); -const distTag = getArgFromCLI( '--dist-tag' ) || 'latest'; - -/** - * The main function of this task. - * - * It installs any missing WordPress packages, and updates the - * mismatched dependencies versions, e.g. it would detect that Gutenberg - * updated react from 16.0.4 to 17.0.2 and install the latter. - */ -function main() { - const initialPackageJSON = readJSONFile( `package.json` ); - - // Install any missing WordPress packages: - const missingWordPressPackages = getMissingWordPressPackages(); - if ( missingWordPressPackages.length ) { - console.log( "The following @wordpress dependencies are missing: " ); - console.log( missingWordPressPackages ); - console.log( "Installing via npm..." ); - installPackages( missingWordPressPackages.map( name => [name, distTag] ) ); - } - - // Update any outdated non-WordPress packages: - const versionMismatches = getMismatchedNonWordPressDependencies(); - if ( versionMismatches.length ) { - console.log( "The following dependencies are outdated: " ); - console.log( versionMismatches ); - console.log( "Updating via npm..." ); - const requiredPackages = versionMismatches.map( ( { name, required } ) => [name, required] ); - installPackages( requiredPackages ); - } - - const finalPackageJSON = readJSONFile( "package.json" ); - outputPackageDiffReport( - getPackageVersionDiff( initialPackageJSON, finalPackageJSON ), - ); - process.exit( 0 ); -} - -/** - * @param {string} fileName File to read. - * @return {Object} Parsed data. - */ -function readJSONFile( fileName ) { - const data = fs.readFileSync( fileName, 'utf8' ); - return JSON.parse( data ); -} - -/** - * Spawns npm install --save. - * - * @param {Array} packages List of tuples [packageName, version] to install. - * @return {string} CLI output. - */ -function installPackages( packages ) { - const packagesWithVersion = packages.map( - ( [packageName, version] ) => `${ packageName }@${ version }`, - ); - return spawn.sync( 'npm', ['install', ...packagesWithVersion, '--save'], { - stdio: 'inherit', - } ); -} - -/** - * Computes which @wordpress packages are required by the Gutenberg - * dependencies that are missing from WordPress package.json. - * - * @return {Array} List of tuples [packageName, version]. - */ -function getMissingWordPressPackages() { - const perPackageDeps = getPerPackageDeps(); - const currentPackages = perPackageDeps.map( ( [name] ) => name ); - - const requiredWpPackages = uniq( perPackageDeps - // Capture the @wordpress dependencies of our dependencies into a flat list. - .flatMap( ( [, dependencies] ) => getWordPressPackages( { dependencies } ) ) - .sort(), - ); - - return requiredWpPackages.filter( - packageName => !currentPackages.includes( packageName ) ); -} - -/** - * Computes which third party packages are required by the @wordpress - * packages, but not by the WordPress repo itself. This includes - * both packages that are missing from package.json and any version - * mismatches. - * - * @return {Array} List of objects {name, required, actual} describing version mismatches. - */ -function getMismatchedNonWordPressDependencies() { - // Get the installed dependencies from package-lock.json - const currentPackageJSON = readJSONFile( "package.json" ); - const currentPackages = getWordPressPackages( currentPackageJSON ); - - const packageLock = readJSONFile( "package-lock.json" ); - const versionConflicts = Object.entries( packageLock.packages[''].dependencies ) - .filter( ( [packageName] ) => currentPackages.includes( packageName ) ) - .flatMap( ( [, { dependencies }] ) => Object.entries( dependencies || {} ) ) - .filter( identity ) - .map( ( [name, { version }] ) => ( { - name, - required: version, - actual: packageLock.dependencies[ name ].version, - } ) ) - .filter( ( { required, actual } ) => required !== actual ) - ; - - // Ensure that all the conflicts can be resolved with the same version - const unresolvableConflicts = Object.entries( groupBy( versionConflicts, ( {name} ) => name ) ) - .map( ( [name, group] ) => [name, uniq( group.map( ( { required } ) => required ) )] ) - .filter( ( [, group] ) => group.length > 1 ); - if ( unresolvableConflicts.length > 0 ) { - console.error( "Can't resolve some conflicts automatically." ); - console.error( "Multiple required versions of the following packages were detected:" ); - console.error( unresolvableConflicts ); - process.exit( 1 ); - } - return versionConflicts; -} - -/** - * Returns a list of dependencies of each @wordpress dependency. - * - * @return {Object} An object of shape {packageName: [[packageName, version]]}. - */ -function getPerPackageDeps() { - // Get the dependencies currently listed in the wordpress-develop package.json - const currentPackageJSON = readJSONFile( "package.json" ); - const currentPackages = getWordPressPackages( currentPackageJSON ); - - // Get the dependencies that the above dependencies list in their package.json. - const deps = currentPackages - .map( ( packageName ) => `node_modules/${ packageName }/package.json` ) - .map( ( jsonPath ) => readJSONFile( jsonPath ).dependencies ); - return zip( currentPackages, deps ); -} - -/** - * Takes unserialized package.json data and returns a list of @wordpress dependencies. - * - * @param {Object} dependencies unserialized package.json data. - * @return {string[]} a list of @wordpress dependencies. - */ -function getWordPressPackages( { dependencies = {} } ) { - return Object.keys( dependencies ) - .filter( isWordPressPackage ); -} - -/** - * Returns true if packageName represents a @wordpress package. - * - * @param {string} packageName Package name to test. - * @return {boolean} Is it a @wodpress package? - */ -function isWordPressPackage( packageName ) { - return packageName.startsWith( WORDPRESS_PACKAGES_PREFIX ); -} - -/** - * Computes the dependencies difference between two unserialized - * package JSON objects. Needed only for the final reporting. - * - * @param {Object} initialPackageJSON Initial package JSON data. - * @param {Object} finalPackageJSON Final package JSON data. - * @return {Object} Delta. - */ -function getPackageVersionDiff( initialPackageJSON, finalPackageJSON ) { - const diff = ['dependencies', 'devDependencies'].reduce( - ( result, keyPackageJSON ) => { - return Object.keys( - finalPackageJSON[ keyPackageJSON ] || {}, - ).reduce( ( _result, dependency ) => { - const initial = - initialPackageJSON[ keyPackageJSON ][ dependency ]; - const final = finalPackageJSON[ keyPackageJSON ][ dependency ]; - if ( initial !== final ) { - _result.push( { dependency, initial, final } ); - } - return _result; - }, result ); - }, - [], - ); - return diff.sort( ( a, b ) => a.dependency.localeCompare( b.dependency ) ); -} - -/** - * Prints the delta between two package.json files. - * - * @param {Object} packageDiff Delta. - */ -function outputPackageDiffReport( packageDiff ) { - const readableDiff = - packageDiff - .map( ( { dependency, initial, final } ) => { - return `${ dependency }: ${ initial } -> ${ final }`; - } ) - .filter( identity ); - if ( !readableDiff.length ) { - console.log( 'No changes detected' ); - return; - } - console.log( - [ - 'The following package versions were changed:', - ...readableDiff, - ].join( '\n' ), - ); -} - -main(); - -/* eslint-enable no-console */ diff --git a/tools/release/sync-stable-blocks.js b/tools/release/sync-stable-blocks.js deleted file mode 100644 index 3f2a1727d7e3b..0000000000000 --- a/tools/release/sync-stable-blocks.js +++ /dev/null @@ -1,144 +0,0 @@ -/* eslint-disable no-console */ -/** - * External dependencies - */ -const fs = require( 'fs' ); -const path = require( 'path' ); - -/** - * Constants - */ -const BLOCK_LIBRARY_SRC = 'node_modules/@wordpress/block-library/src/'; - -const REPOSITORY_ROOT = path.dirname( path.dirname( __dirname ) ); - -/** - * The main function of this task. - * - * Refreshes the PHP files referring to stable @wordpress/block-library blocks. - */ -function main() { - const blocks = getStableBlocksMetadata(); - const toolWarningMessage = '// This file was autogenerated by tools/release/sync-stable-blocks.js, do not change manually!'; - - // wp-includes/blocks/require-blocks.php - console.log( 'Refreshing wp-includes/blocks/require-static-blocks.php...' ); - const staticBlockFolderNames = blocks - .filter( ( metadata ) => ! isDynamic( metadata ) ) - .map( toDirectoryName ) - .sort() - // To the block folder name statement: - .map( dirname => ` '${ dirname }',` ) - .join( "\n" ); - - fs.writeFileSync( - `${ REPOSITORY_ROOT }/src/wp-includes/blocks/require-static-blocks.php`, - ` `require_once ABSPATH . WPINC . '/blocks/${ dirname }.php';` ) - .join( "\n" ); - - fs.writeFileSync( - `${ REPOSITORY_ROOT }/src/wp-includes/blocks/require-dynamic-blocks.php`, - ` path.join( BLOCK_LIBRARY_SRC, dirMaybe, 'block.json' ) ) - .filter( fs.existsSync ) - .map( blockJsonPath => ( { - ...JSON.parse( fs.readFileSync( blockJsonPath ) ), - path: blockJsonPath, - } ) ) - .filter( metadata => ( - !( '__experimental' in metadata ) || metadata.__experimental === false - ) ) - ); -} - -/** - * Returns true if the specified metadata refers to a dynamic block. - * - * @param {Object} metadata Block metadata in question. - * @return {boolean} Is it a dynamic block? - */ -function isDynamic( metadata ) { - return ( - fs.existsSync( path.join( metadata.path, '..', 'index.php' ) ) - ); -} - -/** - * Returns a name of the directory where a given block resides. - * - * @param {Object} metadata Block metadata in question. - * @return {string} Parent directory name. - */ -function toDirectoryName( metadata ) { - return ( - path.basename( path.dirname( metadata.path ) ) - ); -} - -module.exports = { - main, - isDynamic, - toDirectoryName, - getStableBlocksMetadata, -}; - -/* eslint-enable no-console */