Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';

import node from '@astrojs/node';

// https://astro.build/config
export default defineConfig({
integrations: [react()],

vite: {
ssr: {
noExternal: ["@patternfly/*", "react-dropzone"],
Expand All @@ -14,5 +17,9 @@ export default defineConfig({
allow: ['./']
}
}
}
},

adapter: node({
mode: 'standalone'
})
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes enable astro to run a node server for the custom endpoint below in props.json.ts

});
94 changes: 94 additions & 0 deletions cli/buildPropsData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/* eslint-disable no-console */
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file ingests the files which should have their props parsed, parses the props out using tsDocGen, compiles that data into a single object, then writes that object to a json file.


import { glob } from 'glob'
import { writeFile } from 'fs/promises'
import { join } from 'path'

import { tsDocgen } from './tsDocGen.js'
import { getConfig, PropsGlobs } from './getConfig.js'

// Build unique names for components with a "variant" extension
function getTsDocName(name: string, variant: string) {
return `${name}${variant ? `-${variant}` : ''}`
}

function getTsDocNameVariant(source: string) {
if (source.includes('next')) {
return 'next'
}

if (source.includes('deprecated')) {
return 'deprecated'
}
}

async function getFiles(root: string, globs: PropsGlobs[]) {
const files = await Promise.all(
globs.map(async ({ include, exclude }) => {
const files = await glob(include, { cwd: root, ignore: exclude })
return files
}),
)
return files.flat()
}

async function getPropsData(files: string[], verbose: boolean) {
const perFilePropsData = await Promise.all(
files.map(async (file) => {
if (verbose) {
console.log(`Parsing props from ${file}`)
}

const props = await tsDocgen(file)

const tsDocs = props.reduce((acc, { name, description, props }) => {
const key = getTsDocName(name, getTsDocNameVariant(file))
return { ...acc, [key]: { name, description, props } }
}, {})

return tsDocs
}),
)

const combinedPropsData = perFilePropsData.reduce((acc, props) => {
Object.keys(props).forEach((key) => {
if (acc[key]) {
acc[key].props = [...acc[key].props, ...props[key].props]
} else {
acc[key] = props[key]
}
})
return acc
}, {})

return combinedPropsData
}

export async function buildPropsData(
rootDir: string,
astroRoot: string,
configFile: string,
verbose: boolean,
) {
const config = await getConfig(configFile)
if (!config) {
return
}

const { propsGlobs } = config
if (!propsGlobs) {
console.error('No props data found in config')
return
}

const files = await getFiles(rootDir, propsGlobs)
if (verbose) {
console.log(`Found ${files.length} files to parse`)
}

const propsData = await getPropsData(files, verbose)

const propsFile = join(astroRoot, 'dist', 'props.json')

await writeFile(propsFile, JSON.stringify(propsData))
}
53 changes: 47 additions & 6 deletions cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { setFsRootDir } from './setFsRootDir.js'
import { createConfigFile } from './createConfigFile.js'
import { updatePackageFile } from './updatePackageFile.js'
import { getConfig } from './getConfig.js'
import { buildPropsData } from './buildPropsData.js'

function updateContent(program: Command) {
const { verbose } = program.opts()
Expand All @@ -23,16 +24,47 @@ function updateContent(program: Command) {
)
}

const astroRoot = import.meta
.resolve('@patternfly/patternfly-doc-core')
.replace('dist/cli/cli.js', '')
.replace('file://', '')
async function generateProps(program: Command, forceProps: boolean = false) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, what would the expected use case of forceProps be?

Copy link
Copy Markdown
Contributor Author

@wise-king-sullyman wise-king-sullyman Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whenever we want to enforce the props being generated on the CLI internals side regardless of if the user passes the --props flag, such as for when doing a production build.

const { verbose, props } = program.opts()

if (!props && !forceProps) {
return
}

if (verbose) {
console.log('Verbose mode enabled')
}

buildPropsData(
currentDir,
astroRoot,
`${currentDir}/pf-docs.config.mjs`,
verbose,
)
}

let astroRoot = ''

try {
astroRoot = import.meta
.resolve('@patternfly/patternfly-doc-core')
.replace('dist/cli/cli.js', '')
.replace('file://', '')
} catch (e) {
if (e.code === 'ERR_MODULE_NOT_FOUND') {
astroRoot = process.cwd()
} else {
console.error('Error resolving astroRoot', e)
}
}
Comment on lines +48 to +60
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change just makes it so that we can run the docs-core locally more easily


const currentDir = process.cwd()

const program = new Command()
program.name('pf-doc-core')

program.option('--verbose', 'verbose mode', false)
program.option('--props', 'generate props data', false)

program.command('setup').action(async () => {
await Promise.all([
Expand All @@ -54,11 +86,13 @@ program.command('init').action(async () => {

program.command('start').action(async () => {
updateContent(program)
await generateProps(program)
dev({ mode: 'development', root: astroRoot })
})

program.command('build').action(async () => {
updateContent(program)
await generateProps(program, true)
const config = await getConfig(`${currentDir}/pf-docs.config.mjs`)
if (!config) {
console.error(
Expand All @@ -68,13 +102,20 @@ program.command('build').action(async () => {
}

if (!config.outputDir) {
console.error("No outputDir found in config file, an output directory must be defined in your config file e.g. 'dist'")
console.error(
"No outputDir found in config file, an output directory must be defined in your config file e.g. 'dist'",
)
return
}

build({ root: astroRoot, outDir: join(currentDir, config.outputDir) })
})

program.command('generate-props').action(async () => {
await generateProps(program, true)
console.log('\nProps data generated')
})

program.command('serve').action(async () => {
updateContent(program)
preview({ root: astroRoot })
Expand Down
6 changes: 6 additions & 0 deletions cli/getConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@ export interface CollectionDefinition {
name: string
}

export interface PropsGlobs {
include: string[]
exclude: string[]
}

export interface DocsConfig {
content: CollectionDefinition[];
outputDir: string;
propsGlobs: PropsGlobs[];
}

export async function getConfig(fileLocation: string): Promise<DocsConfig | undefined> {
Expand Down
15 changes: 13 additions & 2 deletions cli/templates/pf-docs.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,16 @@ export const config = {
// name: "react-component-docs",
// },
],
outputDir: "./dist/docs"
};
outputDir: './dist/docs',
propsGlobs: [
// {
// include: ['*/@patternfly/react-core/src/**/*.tsx'],
// exclude: [
// '/**/examples/**',
// '/**/__mocks__/**',
// '/**/__tests__/**',
// '/**/*.test.tsx',
// ],
// },
Comment on lines +21 to +29
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this expected to be removed or uncommented before merging?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope I was planning to leave it commented in the template file like the content entry, but I'm not dead set on that.

],
}
Loading
Loading