Skip to content

Commit

Permalink
Port changes after rebase
Browse files Browse the repository at this point in the history
  • Loading branch information
aduth authored and oandregal committed Dec 19, 2019
1 parent d3fcb4a commit 21963bf
Show file tree
Hide file tree
Showing 6 changed files with 300 additions and 45 deletions.
156 changes: 131 additions & 25 deletions bin/api-docs/update-readmes.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,141 @@
/**
* Node dependencies.
* External dependencies
*/
const { join } = require( 'path' );
const spawnSync = require( 'child_process' ).spawnSync;
const { join, relative, resolve, sep } = require( 'path' );
const glob = require( 'fast-glob' );
const execa = require( 'execa' );
const { Transform } = require( 'stream' );
const { readFile } = require( 'fs' ).promises;

/**
* Local dependencies.
* README file tokens, defined as a tuple of token identifier, source path.
*
* @typedef {[string,string]} WPReadmeFileTokens
*/
const getPackages = require( './packages' );

getPackages().forEach( ( entry ) => {
const [ packageName, targetFiles ] = entry;
/**
* README file data, defined as a tuple of README file path, token details.
*
* @typedef {[string,WPReadmeFileTokens]} WPReadmeFileData
*/

/**
* Path to packages directory.
*
* @type {string}
*/
const PACKAGES_DIR = resolve( __dirname, '../packages' );

/**
* Pattern matching start token of a README file.
*
* @type {RegExp}
*/
const TOKEN_PATTERN = /<!-- START TOKEN\((.+?(?:\|(.+?))?)\) -->/g;

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 },
);
/**
* 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 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 = files.map( getFilePackage );
return packages.length === 1 ?
packages[ 0 ] :
'{' + packages.join() + '}';
}

if ( status !== 0 ) {
process.stderr.write( `${ packageName } ${ stderr.toString() }\n` );
process.exit( 1 );
/**
* 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 = 'src/index.js' ] = 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` )
.pipe( filterTokenTransform )
.on( 'data', async ( /** @type {WPReadmeFileData} */ data ) => {
const [ file, tokens ] = data;

const packageName = getFilePackage( 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 ) {
try {
await execa(
join( __dirname, '..', 'node_modules', '.bin', 'docgen' ),
[
join( 'packages', packageName, path ),
`--output packages/${ packageName }/README.md`,
'--to-token',
`--use-token "${ token }"`,
'--ignore "/unstable|experimental/i"',
],
{ shell: true }
);
} catch ( error ) {
// Disable reason: Errors should log to console.

// eslint-disable-next-line no-console
console.error( error );
process.exit( 1 );
}
}
} );
173 changes: 160 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
"enzyme": "3.9.0",
"eslint-plugin-eslint-comments": "3.1.2",
"eslint-plugin-import": "2.18.2",
"execa": "3.4.0",
"fast-glob": "2.2.7",
"fbjs": "0.8.17",
"glob": "7.1.2",
Expand Down
Loading

0 comments on commit 21963bf

Please sign in to comment.