diff --git a/packages/documentation-framework/scripts/cli/build.js b/packages/documentation-framework/scripts/cli/build.js index 220f178aff..50eacc4e4b 100644 --- a/packages/documentation-framework/scripts/cli/build.js +++ b/packages/documentation-framework/scripts/cli/build.js @@ -76,7 +76,7 @@ async function execFile(file, args) { } async function build(cmd, options) { - generate(options); + await generate(options); const toBuild = cmd === 'all' ? ['server', 'client'] : cmd; diff --git a/packages/documentation-framework/scripts/cli/cli.js b/packages/documentation-framework/scripts/cli/cli.js index 17da8d1d2d..3ffb99fe6a 100755 --- a/packages/documentation-framework/scripts/cli/cli.js +++ b/packages/documentation-framework/scripts/cli/cli.js @@ -9,17 +9,17 @@ program program .command('generate') .description('generates source files') - .action(options => { + .action(async options => { const { generate } = require('./generate'); - generate(options); + await generate(options); }); program .command('start') .description('generates source files and runs webpack-dev-server') - .action(options => { + .action(async options => { const { start } = require('./start'); - start(options); + await start(options); }); program diff --git a/packages/documentation-framework/scripts/cli/generate.js b/packages/documentation-framework/scripts/cli/generate.js index d649a5823a..ed37138d78 100644 --- a/packages/documentation-framework/scripts/cli/generate.js +++ b/packages/documentation-framework/scripts/cli/generate.js @@ -1,15 +1,17 @@ const path = require('path'); -const { sourceMD, sourceProps, sourceFunctionDocs, writeIndex } = require('../md/parseMD'); +const { sourceMD, sourceProps, sourceFunctionDocs, writeIndex, waitForProps, processMD } = require('../md/parseMD'); function getSource(options) { return require(path.join(process.cwd(), options.parent.source)); } -function generate(options) { +async function generate(options) { const start = new Date(); console.log('write source files to patternfly-docs/generated'); const sourceMDWithOptions = (glob, source, ignore) => sourceMD(glob, source, ignore, options._name); getSource(options)(sourceMDWithOptions, sourceProps, sourceFunctionDocs); + await waitForProps(); + processMD(); const exitCode = writeIndex(); if (exitCode !== 0) { process.exit(exitCode); diff --git a/packages/documentation-framework/scripts/cli/start.js b/packages/documentation-framework/scripts/cli/start.js index 42b0cc0d88..86154b2149 100644 --- a/packages/documentation-framework/scripts/cli/start.js +++ b/packages/documentation-framework/scripts/cli/start.js @@ -19,7 +19,7 @@ function startDevServer(webpackConfig) { } async function start(options) { - generate(options, true); + await generate(options, true); const webpackClientConfig = await clientConfig(null, { mode: 'development', ...getConfig(options) }); console.log('start rspack-dev-server'); watchMD(); diff --git a/packages/documentation-framework/scripts/md/parseMD.js b/packages/documentation-framework/scripts/md/parseMD.js index 1fc5cf8319..49967e5460 100644 --- a/packages/documentation-framework/scripts/md/parseMD.js +++ b/packages/documentation-framework/scripts/md/parseMD.js @@ -19,6 +19,7 @@ const outputBase = path.join(process.cwd(), `patternfly-docs/generated`); const tsDocs = {}; let functionDocs = {}; const routes = {}; +const pendingProps = []; const globs = { props: [], md: [], @@ -267,8 +268,8 @@ function toReactComponent(mdFilePath, source, buildMode) { }; } -function sourcePropsFile(file) { - tsDocgen(file) +async function sourcePropsFile(file) { + (await tsDocgen(file)) .filter(({ hide }) => !hide) .forEach(({ name, description, props }) => { tsDocs[getTsDocName(name, getTsDocNameVariant(file))] = { name, description, props }; @@ -345,19 +346,32 @@ function getTsDocNameVariant(source) { module.exports = { sourceProps(glob, ignore) { globs.props.push({ glob, ignore }); - globSync(glob, { ignore }).forEach(sourcePropsFile); + const promise = Promise.all(globSync(glob, { ignore }).map(sourcePropsFile)); + pendingProps.push(promise); + }, + async waitForProps() { + await Promise.all(pendingProps); }, sourceMD(glob, source, ignore, buildMode) { - globs.md.push({ glob, source, ignore }); - globSync(glob, { ignore }).forEach(file => sourceMDFile(file, source, buildMode)); + globs.md.push({ glob, source, ignore, buildMode }); + }, + processMD() { + globs.md.forEach(({ glob, source, ignore, buildMode }) => { + globSync(glob, { ignore }).forEach(file => sourceMDFile(file, source, buildMode)); + }); }, sourceFunctionDocs, writeIndex, watchMD() { globs.props.forEach(({ glob, ignore }) => { const propWatcher = chokidar.watch(globSync(glob, { ignored: ignore, ignoreInitial: true})); - propWatcher.on('add', sourcePropsFile); - propWatcher.on('change', sourcePropsFile); + const onPropFile = (file) => { + sourcePropsFile(file).catch((err) => { + console.error('Error updating props from', file, err); + }); + }; + propWatcher.on('add', onPropFile); + propWatcher.on('change', onPropFile); }); globs.md.forEach(({ glob, source, ignore }) => { const mdWatcher = chokidar.watch(globSync(glob, { ignored: ignore, ignoreInitial: true })); diff --git a/packages/documentation-framework/scripts/tsDocgen.js b/packages/documentation-framework/scripts/tsDocgen.js index 8ba8d58281..b023714c72 100644 --- a/packages/documentation-framework/scripts/tsDocgen.js +++ b/packages/documentation-framework/scripts/tsDocgen.js @@ -1,7 +1,15 @@ const fs = require("fs"); -const reactDocgen = require("react-docgen"); const ts = require("typescript"); +// react-docgen v6+ is ESM-only; lazy-load it asynchronously on first use +let reactDocgenReady = null; +function loadReactDocgen() { + if (!reactDocgenReady) { + reactDocgenReady = import("react-docgen"); + } + return reactDocgenReady; +} + const annotations = [ { regex: /@deprecated/, @@ -41,7 +49,8 @@ function addAnnotations(prop) { return prop; } -function getComponentMetadata(filename, sourceText) { +async function getComponentMetadata(filename, sourceText) { + const reactDocgen = await loadReactDocgen(); let parsedComponents = null; try { parsedComponents = reactDocgen.parse(sourceText, { @@ -159,9 +168,9 @@ function normalizeProp([ return res; } -function tsDocgen(file) { +async function tsDocgen(file) { const sourceText = fs.readFileSync(file, "utf8"); - const componentMeta = getComponentMetadata(file, sourceText); // Array of components with props + const componentMeta = await getComponentMetadata(file, sourceText); // Array of components with props const interfaceMeta = getInterfaceMetadata(file, sourceText); // Array of interfaces with props const typeAliasMeta = getTypeAliasMetadata(file, sourceText); // Array of type aliases with props const propsMetaMap = [...interfaceMeta, ...typeAliasMeta].reduce(function (