/
githubmirror
/
gutenberg
Обзор
Документация
Войти
/
githubmirror
/
gutenberg
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
trunk
tools/docs/update-api-docs.js
255 строк
7 KB
Marco Ciampini
ESLint: Replace strict config with bulk suppressions (#81248)
07 авг 2026, 14:34
Не верифицирован
07 авг 2026, 14:34
7f43eaf
Код
Авторство
О чём код?
const { relative, resolve, sep, dirname } = require( 'path' ); const { Transform } = require( 'stream' ); const { readFile } = require( 'fs' ).promises; const glob = require( 'fast-glob' ); const execa = require( 'execa' ); /** * README file tokens, defined as a tuple of token identifier, source path. * * @typedef {[string,string]} WPReadmeFileTokens */ /** * README file data, defined as a tuple of README file path, token details. * * @typedef {[string,WPReadmeFileTokens]} WPReadmeFileData */ /** * Absolute path to the `docgen` bin. Resolved via module resolution rather than * a `node_modules/.bin` path, whose location depends on the install layout. * * @type {string} */ const DOCGEN_BIN = ( () => { const packageJsonPath = require.resolve( '@wordpress/docgen/package.json' ); return resolve( dirname( packageJsonPath ), require( packageJsonPath ).bin.docgen ); } )(); /** * Path to root project directory. * * @type {string} */ const ROOT_DIR = resolve( __dirname, '../..' ).replace( /\\/g, '/' ); /** * Path to packages directory. * * @type {string} */ const PACKAGES_DIR = resolve( ROOT_DIR, 'packages' ).replace( /\\/g, '/' ); /** * Path to data documentation directory. * * @type {string} */ const DATA_DOCS_DIR = resolve( ROOT_DIR, 'docs/reference-guides/data' ).replace( /\\/g, '/' ); /** * Pattern matching start token of a README file. * * @example Delimiter tokens that use the default source file: * <!-- START TOKEN(Autogenerated API docs) --> * // content within will be filled by docgen * <!-- END TOKEN(Autogenerated API docs) --> * * @example Delimiter tokens that use a specific source file: * <!-- START TOKEN(Autogenerated actions|src/actions.js) --> * // content within will be filled by docgen * <!-- END TOKEN(Autogenerated actions|src/actions.js) --> * * @type {RegExp} */ const TOKEN_PATTERN = /<!-- START TOKEN\((.+?(?:\|(.+?))?)\) -->/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 ] = match; tokens.push( [ token, path ] ); } if ( tokens.length ) { this.push( [ file, tokens ] ); } } callback(); }, } ); /** * Find default source file (`src/index.{js,ts,tsx}`) in a specified package directory * * @param {string} dir Package directory to search in * @return {string} Name of matching file */ function findDefaultSourcePath( dir ) { const defaultPathMatches = glob.sync( 'src/index.{js,ts,tsx}', { cwd: dir, } ); if ( ! defaultPathMatches.length ) { throw new Error( `Cannot find default source file in ${ dir }` ); } return defaultPathMatches[ 0 ]; } /** * 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. try { for ( const [ token, path = findDefaultSourcePath( dirname( file ) ), ] of tokens ) { const sourcePath = relative( ROOT_DIR, resolve( dirname( file ), path ) ); await execa( DOCGEN_BIN, [ sourcePath, '--output', output, '--to-token', '--use-token', token, '--ignore', '/unstable|experimental/i', ], { cwd: ROOT_DIR } ); } await execa( 'npm', [ 'run', 'format', output ], { cwd: ROOT_DIR, } ); } catch ( error ) { console.error( error ); process.exit( 1 ); } } );