diff --git a/bin/api-docs/are-api-docs-unstaged.js b/bin/api-docs/are-api-docs-unstaged.js
new file mode 100644
index 00000000000000..b7d956b9e145c3
--- /dev/null
+++ b/bin/api-docs/are-api-docs-unstaged.js
@@ -0,0 +1,43 @@
+#!/usr/bin/env node
+
+/**
+ * Node dependencies.
+ */
+const { extname } = require( 'path' );
+const chalk = require( 'chalk' );
+const execSync = require( 'child_process' ).execSync;
+const { readFile } = require( 'fs' ).promises;
+
+const getUnstagedFiles = () =>
+ execSync( 'git diff --name-only', { encoding: 'utf8' } )
+ .split( '\n' )
+ .filter( Boolean );
+
+const fileHasToken = async ( file ) =>
+ ( await readFile( file, 'utf8' ) ).includes( '
+ * // content within will be filled by docgen
+ *
+ *
+ * @example Delimiter tokens that use a specific source file:
+ *
+ * // content within will be filled by docgen
+ *
+ *
+ * @type {RegExp}
+ * @see DEFAULT_PATH
+ */
+const TOKEN_PATTERN = //g;
+
+/**
+ * Given an absolute file path, returns the package name.
+ *
+ * @param {string} file Absolute path.
+ *
+ * @return {string} Package name.
+ */
+function getFilePackage( file ) {
+ return relative( PACKAGES_DIR, file ).split( sep )[ 0 ];
+}
+
+/**
+ * Returns an appropriate glob pattern for the packages directory to match
+ * relevant documentation files for a given set of files.
+ *
+ * @param {string[]} files Set of files to match. Pass an empty set to match
+ * all packages.
+ *
+ * @return {string} Packages glob pattern.
+ */
+function getPackagePattern( files ) {
+ if ( ! files.length ) {
+ return '*';
+ }
+
+ // Since brace expansion doesn't work with a single package, special-case
+ // the pattern for the singular match.
+ const packages = Array.from( new Set( files.map( getFilePackage ) ) );
+ return packages.length === 1 ? packages[ 0 ] : '{' + packages.join() + '}';
+}
+
+/**
+ * Returns the conventional store name of a given package.
+ *
+ * @param {string} packageName Package name.
+ *
+ * @return {string} Store name.
+ */
+function getPackageStoreName( packageName ) {
+ let storeName = 'core';
+ if ( packageName !== 'core-data' ) {
+ storeName += '/' + packageName;
+ }
+
+ return storeName;
+}
+
+/**
+ * Returns the conventional documentation file name of a given package.
+ *
+ * @param {string} packageName Package name.
+ *
+ * @return {string} Documentation file name.
+ */
+function getDataDocumentationFile( packageName ) {
+ const storeName = getPackageStoreName( packageName );
+ return `data-${ storeName.replace( '/', '-' ) }.md`;
+}
+
+/**
+ * Returns an appropriate glob pattern for the data documentation directory to
+ * match relevant documentation files for a given set of files.
+ *
+ * @param {string[]} files Set of files to match. Pass an empty set to match
+ * all packages.
+ *
+ * @return {string} Packages glob pattern.
+ */
+function getDataDocumentationPattern( files ) {
+ if ( ! files.length ) {
+ return '*';
+ }
+
+ // Since brace expansion doesn't work with a single package, special-case
+ // the pattern for the singular match.
+ const filePackages = Array.from( new Set( files.map( getFilePackage ) ) );
+ const docFiles = filePackages.map( getDataDocumentationFile );
+
+ return docFiles.length === 1 ? docFiles[ 0 ] : '{' + docFiles.join() + '}';
+}
+
+/**
+ * Stream transform which filters out README files to include only those
+ * containing matched token pattern, yielding a tuple of the file and its
+ * matched tokens.
+ *
+ * @type {Transform}
+ */
+const filterTokenTransform = new Transform( {
+ objectMode: true,
+
+ async transform( file, _encoding, callback ) {
+ let content;
+ try {
+ content = await readFile( file, 'utf8' );
+ } catch {}
+
+ if ( content ) {
+ const tokens = [];
+
+ for ( const match of content.matchAll( TOKEN_PATTERN ) ) {
+ const [ , token, path = DEFAULT_PATH ] = match;
+ tokens.push( [ token, path ] );
+ }
+
+ if ( tokens.length ) {
+ this.push( [ file, tokens ] );
+ }
+ }
+
+ callback();
+ },
+} );
+
+/**
+ * Optional process arguments for which to generate documentation.
+ *
+ * @type {string[]}
+ */
+const files = process.argv.slice( 2 );
+
+glob.stream( [
+ `${ PACKAGES_DIR }/${ getPackagePattern( files ) }/README.md`,
+ `${ DATA_DOCS_DIR }/${ getDataDocumentationPattern( files ) }`,
+] )
+ .pipe( filterTokenTransform )
+ .on( 'data', async ( /** @type {WPReadmeFileData} */ data ) => {
+ const [ file, tokens ] = data;
+ const output = relative( ROOT_DIR, file );
+
+ // Each file can have more than one placeholder content to update, each
+ // represented by tokens. The docgen script updates one token at a time,
+ // so the tokens must be replaced in sequence to prevent the processes
+ // from overriding each other.
+ for ( const [ token, path ] of tokens ) {
+ await execa(
+ join( __dirname, '..', '..', 'node_modules', '.bin', 'docgen' ),
+ [
+ relative( ROOT_DIR, resolve( dirname( file ), path ) ),
+ `--output ${ output }`,
+ '--to-token',
+ `--use-token "${ token }"`,
+ '--ignore "/unstable|experimental/i"',
+ ],
+ { shell: true }
+ );
+ }
+ } );
diff --git a/bin/api-docs/update-readmes.js b/bin/api-docs/update-readmes.js
deleted file mode 100755
index ab1805c3fdeccd..00000000000000
--- a/bin/api-docs/update-readmes.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * Node dependencies.
- */
-const { join } = require( 'path' );
-const spawnSync = require( 'child_process' ).spawnSync;
-
-/**
- * Local dependencies.
- */
-const getPackages = require( './packages' );
-
-getPackages().forEach( ( entry ) => {
- const [ packageName, targetFiles ] = entry;
-
- Object.entries( targetFiles ).forEach( ( [ token, path ] ) => {
- // Each target operates over the same file, so it needs to be processed synchronously,
- // as to make sure the processes don't overwrite each other.
- const { status, stderr } = spawnSync(
- join(
- __dirname,
- '..',
- '..',
- 'node_modules',
- '.bin',
- 'docgen'
- ).replace( / /g, '\\ ' ),
- [
- join( 'packages', packageName, path ),
- `--output packages/${ packageName }/README.md`,
- '--to-token',
- `--use-token "${ token }"`,
- '--ignore "/unstable|experimental/i"',
- ],
- { shell: true }
- );
-
- if ( status !== 0 ) {
- process.stderr.write( `${ packageName } ${ stderr.toString() }\n` );
- process.exit( 1 );
- }
- } );
-} );
diff --git a/docs/designers-developers/developers/data/data-core-annotations.md b/docs/designers-developers/developers/data/data-core-annotations.md
index e71aefd27d2129..0b5840c617d1e4 100644
--- a/docs/designers-developers/developers/data/data-core-annotations.md
+++ b/docs/designers-developers/developers/data/data-core-annotations.md
@@ -4,17 +4,17 @@ Namespace: `core/annotations`.
## Selectors
-
+
Nothing to document.
-
-
+
## Actions
-
+
Nothing to document.
-
+
+
diff --git a/docs/designers-developers/developers/data/data-core-block-editor.md b/docs/designers-developers/developers/data/data-core-block-editor.md
index 1bd2c38e601a1e..e19a7cb52c12b1 100644
--- a/docs/designers-developers/developers/data/data-core-block-editor.md
+++ b/docs/designers-developers/developers/data/data-core-block-editor.md
@@ -4,7 +4,7 @@ Namespace: `core/block-editor`.
## Selectors
-
+
# **canInsertBlockType**
@@ -907,12 +907,11 @@ _Returns_
- `?boolean`: Whether the template is valid or not.
-
-
+
## Actions
-
+
# **clearSelectedBlock**
@@ -1386,6 +1385,15 @@ _Returns_
# **updateSettings**
-Undocumented declaration.
+Returns an action object used in signalling that the block editor settings have been updated.
+
+_Parameters_
+
+- _settings_ `Object`: Updated settings
+
+_Returns_
+
+- `Object`: Action object
+
-
+
diff --git a/docs/designers-developers/developers/data/data-core-blocks.md b/docs/designers-developers/developers/data/data-core-blocks.md
index 933c432cd93260..8d577f4fca040c 100644
--- a/docs/designers-developers/developers/data/data-core-blocks.md
+++ b/docs/designers-developers/developers/data/data-core-blocks.md
@@ -4,7 +4,7 @@ Namespace: `core/blocks`.
## Selectors
-
+
# **getBlockStyles**
@@ -231,12 +231,11 @@ _Returns_
- `Array