Skip to content

Misc bug fixes for the cli, live examples, and prop/css tables #115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions cli/__tests__/convertToMDX.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ jest.mock('fs/promises', () => ({
readFile: jest.fn(),
writeFile: jest.fn(),
unlink: jest.fn(),
access: jest.fn().mockResolvedValue(undefined), // Mock access to always resolve (file exists)
}))

jest.mock('glob', () => ({
Expand Down
51 changes: 35 additions & 16 deletions cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import { buildPropsData } from './buildPropsData.js'
import { hasFile } from './hasFile.js'
import { convertToMDX } from './convertToMDX.js'

function updateContent(program: Command) {
async function updateContent(program: Command) {
const { verbose } = program.opts()

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

createCollectionContent(
await createCollectionContent(
astroRoot,
`${process.cwd()}/pf-docs.config.mjs`,
verbose,
Expand All @@ -45,39 +45,58 @@ async function generateProps(program: Command, forceProps: boolean = false) {
verbose,
)
}

async function transformMDContentToMDX() {
const config = await getConfig(`${currentDir}/pf-docs.config.mjs`)
if (!config) {
console.error(
'No config found, please run the `setup` command or manually create a pf-docs.config.mjs file',
)
return config
}

if (config.content) {
await Promise.all(
config.content.map((contentObj) => convertToMDX(contentObj.pattern)),
)
}
}

async function buildProject(): Promise<DocsConfig | undefined> {
updateContent(program)
await updateContent(program)
await generateProps(program, true)
const config = await getConfig(`${currentDir}/pf-docs.config.mjs`)
if (!config) {
console.error(
'No config found, please run the `setup` command or manually create a pf-docs.config.mjs file',
)
return config;
return config
}

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

await transformMDContentToMDX()

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

return config
}

async function deploy() {
const { verbose } = program.opts()

if (verbose) {
console.log('Starting Cloudflare deployment...')
}

try {
// First build the project
const config = await buildProject();
const config = await buildProject()
if (config) {
if (verbose) {
console.log('Build complete, deploying to Cloudflare...')
Expand All @@ -86,12 +105,12 @@ async function deploy() {
// Deploy using Wrangler
const { execSync } = await import('child_process')
const outputPath = join(currentDir, config.outputDir)

execSync(`npx wrangler pages deploy ${outputPath}`, {
stdio: 'inherit',
cwd: currentDir
cwd: currentDir,
})

console.log('Successfully deployed to Cloudflare Pages!')
}
} catch (error) {
Expand Down Expand Up @@ -143,7 +162,7 @@ program.command('init').action(async () => {
})

program.command('start').action(async () => {
updateContent(program)
await updateContent(program)

// if a props file hasn't been generated yet, but the consumer has propsData, it will cause a runtime error so to
// prevent that we're just creating a props file regardless of what they say if one doesn't exist yet
Expand All @@ -153,7 +172,7 @@ program.command('start').action(async () => {
})

program.command('build').action(async () => {
await buildProject();
await buildProject()
})

program.command('generate-props').action(async () => {
Expand All @@ -162,7 +181,7 @@ program.command('generate-props').action(async () => {
})

program.command('serve').action(async () => {
updateContent(program)
await updateContent(program)
preview({ root: astroRoot })
})

Expand All @@ -178,7 +197,7 @@ program
})

program.command('deploy').action(async () => {
await deploy()
await deploy()
})

program.parse(process.argv)
13 changes: 10 additions & 3 deletions cli/convertToMDX.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { readFile, writeFile, unlink } from 'fs/promises'
import { readFile, writeFile, unlink, access } from 'fs/promises'
import { glob } from 'glob'
import path from 'path'

Expand Down Expand Up @@ -46,7 +46,7 @@ function removeNoLiveTags(content: string): string {

function removeExistingImports(content: string): string {
// Remove imports that don't end in .css
const importRegex = /^import {?[\w\s,\n]*}? from ['"](?!.*\.css['"])[^'"]*['"]\n/gm
const importRegex = /^import {?[\w\s,\n]*}? from ['"](?!.*\.css['"])[^'"]*['"];?\n/gm
return content.replace(importRegex, '')
}

Expand All @@ -57,8 +57,15 @@ function convertCommentsToMDX(content: string): string {
)
}

async function fileExists(file: string): Promise<boolean> {
return access(file).then(() => true).catch(() => false)
}

async function processFile(file: string): Promise<void> {
if (file.endsWith('.mdx')) {
const exists = await fileExists(file)

// if the file is already an mdx file or doesn't exist we don't need to do anything
if (file.endsWith('.mdx') || !exists) {
return
}

Expand Down
3 changes: 2 additions & 1 deletion cli/createCollectionContent.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable no-console */
import { writeFile } from 'fs/promises'
import { join } from 'path'
import { getConfig } from './getConfig.js'

export async function createCollectionContent(rootDir: string, configFile: string, verbose: boolean) {
Expand All @@ -14,7 +15,7 @@ export async function createCollectionContent(rootDir: string, configFile: strin
return
}

const contentFile = rootDir + 'src/content.ts'
const contentFile = join(rootDir, 'src', 'content.ts')

try {
await writeFile(
Expand Down
93 changes: 93 additions & 0 deletions package-lock.json

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

10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
"access": "public"
},
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro check && astro build",
"dev": "npm run start:cli",
"start": "npm run dev",
"start:cli": "npm run build:cli && node ./dist/cli/cli.js start",
"start:astro": "astro dev",
"build": "npm run build:cli && node ./dist/cli/cli.js build",
"build:astro": "astro check && astro build",
"build:cli": "tsc --build ./cli/tsconfig.json",
"build:cli:watch": "tsc --build --watch ./cli/tsconfig.json",
"build:props": "npm run build:cli && node ./dist/cli/cli.js generate-props",
Expand Down Expand Up @@ -52,6 +55,7 @@
"@patternfly/patternfly": "^6.0.0",
"@patternfly/react-code-editor": "^6.2.2",
"@patternfly/react-core": "^6.0.0",
"@patternfly/react-drag-drop": "^6.0.0",
"@patternfly/react-icons": "^6.0.0",
"@patternfly/react-styles": "^6.0.0",
"@patternfly/react-table": "^6.0.0",
Expand Down
12 changes: 9 additions & 3 deletions src/components/DocsTables.astro
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
---
import { Stack, StackItem } from '@patternfly/react-core'
import PropsTables from './PropsTables.astro'
import { PropsTables } from './PropsTables'
import CSSTable from './CSSTable.astro'

const { propComponents, cssPrefix } = Astro.props

const { url } = Astro

const hasTables = !!propComponents || !!cssPrefix
---

Expand All @@ -14,12 +16,16 @@ const hasTables = !!propComponents || !!cssPrefix
<Stack hasGutter>
{propComponents && (
<StackItem>
<PropsTables propComponents={propComponents} server:defer />
<PropsTables
propComponents={propComponents}
url={url}
client:only="react"
/>
</StackItem>
)}
{cssPrefix && (
<StackItem>
<CSSTable cssPrefix={cssPrefix} server:defer />
<CSSTable cssPrefix={cssPrefix} />
</StackItem>
)}
</Stack>
Expand Down
2 changes: 2 additions & 0 deletions src/components/LiveExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { convertToReactComponent } from '@patternfly/ast-helpers'
import { ErrorBoundary } from 'react-error-boundary'
import * as reactCoreModule from '@patternfly/react-core'
import * as reactIconsModule from '@patternfly/react-icons'
import * as reactDragDropModule from '@patternfly/react-drag-drop'
import styles from '@patternfly/react-styles/css/components/_index'
import * as reactTokensModule from '@patternfly/react-tokens'
import { ExampleToolbar } from './ExampleToolbar'
Expand All @@ -33,6 +34,7 @@ function getLivePreview(editorCode: string) {
const scope = {
...reactCoreModule,
...reactIconsModule,
...reactDragDropModule,
styles,
...reactTokensModule,
...{ useState, Fragment, useRef, useEffect, createRef, useReducer },
Expand Down
Loading