Skip to content
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
8 changes: 6 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,9 @@ pnpm-debug.log*

.eslintcache

## Ignore content.ts
src/content.ts
## Ignore generated files
src/content.ts
src/apiIndex.json
textContent/*.mdx

coverage/
1 change: 0 additions & 1 deletion astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,5 @@ export default defineConfig({
}
}
},

adapter: cloudflare()
});
5 changes: 4 additions & 1 deletion cli/__tests__/convertToMDX.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import { convertToMDX } from '../convertToMDX.ts'
jest.mock('fs/promises', () => ({
readFile: jest.fn(),
writeFile: jest.fn(),
access: jest.fn().mockResolvedValue(undefined), // Mock access to always resolve (file exists)
}))

jest.mock('glob', () => ({
glob: jest.fn(),
}))

jest.mock('../fileExists', () => ({
fileExists: jest.fn().mockResolvedValue(true), // Mock fileExists to always return true (file exists)
}))

beforeEach(() => {
jest.clearAllMocks()
})
Expand Down
40 changes: 22 additions & 18 deletions cli/__tests__/createCollectionContent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ it('should call writeFile with the expected file location and content without th
await createCollectionContent('/foo/', '/config/dir/pf-docs.config.mjs', false)

const expectedContent = [
{ name: 'test', base: '/config/dir/src/docs', pattern: '**/*.md' }
{ name: 'test', base: '/config/dir/src/docs', pattern: '**/*.md', version: 'v6' }
]

expect(writeFile).toHaveBeenCalledWith(
Expand Down Expand Up @@ -208,11 +208,12 @@ it('should handle content with packageName by finding package in node_modules',
await createCollectionContent('/foo/', '/config/dir/pf-docs.config.mjs', false)

const expectedContent = [
{
{
base: '/config/dir/node_modules/@patternfly/react-core',
name: 'test',
packageName: '@patternfly/react-core',
pattern: '**/*.md'
name: 'test',
packageName: '@patternfly/react-core',
pattern: '**/*.md',
version: 'v6'
}
]

Expand Down Expand Up @@ -242,11 +243,12 @@ it('should handle content with packageName when package is not found locally but
await createCollectionContent('/foo/', '/config/dir/pf-docs.config.mjs', false)

const expectedContent = [
{
{
base: '/config/node_modules/@patternfly/react-core',
name: 'test',
packageName: '@patternfly/react-core',
pattern: '**/*.md'
name: 'test',
packageName: '@patternfly/react-core',
pattern: '**/*.md',
version: 'v6'
}
]

Expand Down Expand Up @@ -274,11 +276,12 @@ it('should handle content with packageName when package is not found anywhere',
await createCollectionContent('/foo/', '/config/dir/pf-docs.config.mjs', false)

const expectedContent = [
{
{
base: null,
name: 'test',
packageName: '@patternfly/react-core',
pattern: '**/*.md'
name: 'test',
packageName: '@patternfly/react-core',
pattern: '**/*.md',
version: 'v6'
}
]

Expand Down Expand Up @@ -307,12 +310,13 @@ it('should handle mixed content with both base and packageName entries', async (
await createCollectionContent('/foo/', '/config/dir/pf-docs.config.mjs', false)

const expectedContent = [
{ name: 'docs', base: '/config/dir/src/docs', pattern: '**/*.md' },
{
{ name: 'docs', base: '/config/dir/src/docs', pattern: '**/*.md', version: 'v6' },
{
base: '/config/dir/node_modules/@patternfly/react-core',
name: 'components',
packageName: '@patternfly/react-core',
pattern: '**/*.md'
name: 'components',
packageName: '@patternfly/react-core',
pattern: '**/*.md',
version: 'v6'
}
]

Expand Down
35 changes: 35 additions & 0 deletions cli/__tests__/fileExists.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { access } from 'fs/promises'
import { fileExists } from '../fileExists'

jest.mock('fs/promises', () => ({
access: jest.fn(),
}))

it('returns true when file exists', async () => {
;(access as jest.Mock).mockResolvedValue(undefined)

const result = await fileExists('/path/to/existing/file.txt')

expect(result).toBe(true)
expect(access).toHaveBeenCalledWith('/path/to/existing/file.txt')
})

it('returns false when file does not exist', async () => {
;(access as jest.Mock).mockRejectedValue(
new Error('ENOENT: no such file or directory'),
)

const result = await fileExists('/path/to/nonexistent/file.txt')

expect(result).toBe(false)
expect(access).toHaveBeenCalledWith('/path/to/nonexistent/file.txt')
})

it('returns false when access throws any error', async () => {
;(access as jest.Mock).mockRejectedValue(new Error('Permission denied'))

const result = await fileExists('/path/to/file.txt')

expect(result).toBe(false)
expect(access).toHaveBeenCalledWith('/path/to/file.txt')
})
25 changes: 24 additions & 1 deletion cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { symLinkConfig } from './symLinkConfig.js'
import { buildPropsData } from './buildPropsData.js'
import { hasFile } from './hasFile.js'
import { convertToMDX } from './convertToMDX.js'
import { mkdir } from 'fs/promises'
import { mkdir, copyFile } from 'fs/promises'
import { fileExists } from './fileExists.js'

const currentDir = process.cwd()
const config = await getConfig(`${currentDir}/pf-docs.config.mjs`)
Expand Down Expand Up @@ -86,6 +87,26 @@ async function transformMDContentToMDX() {
}
}

async function initializeApiIndex() {
const templateIndexPath = join(astroRoot, 'cli', 'templates', 'apiIndex.json')
const targetIndexPath = join(astroRoot, 'src', 'apiIndex.json')

const indexExists = await fileExists(targetIndexPath)

// early return if the file exists from a previous build
if (indexExists) {
console.log('apiIndex.json already exists, skipping initialization')
return
}

try {
await copyFile(templateIndexPath, targetIndexPath)
console.log('Initialized apiIndex.json')
} catch (e: any) {
console.error('Error copying apiIndex.json template:', e)
}
}

async function buildProject(): Promise<DocsConfig | undefined> {
await updateContent(program)
await generateProps(program, true)
Expand All @@ -103,6 +124,7 @@ async function buildProject(): Promise<DocsConfig | undefined> {
return config
}

await initializeApiIndex()
await transformMDContentToMDX()

build({
Expand Down Expand Up @@ -172,6 +194,7 @@ program.command('init').action(async () => {

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

// 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 Down
7 changes: 2 additions & 5 deletions cli/convertToMDX.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { readFile, writeFile, access } from 'fs/promises'
import { readFile, writeFile } from 'fs/promises'
import { glob } from 'glob'
import path from 'path'
import { fileExists } from './fileExists.js'

function handleTsExamples(content: string): string {
//regex link: https://regexr.com/8f0bu
Expand Down Expand Up @@ -57,10 +58,6 @@ 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> {
const exists = await fileExists(file)

Expand Down
5 changes: 5 additions & 0 deletions cli/createCollectionContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export async function createCollectionContent(
verboseModeLog('repoRootDir: ', repoRootDir, '\n')

const contentWithAbsolutePaths = content.map((contentEntry) => {
const version = contentEntry.version || 'v6'

if (contentEntry.base) {
const absoluteBase = resolve(configDir, contentEntry.base)

Expand All @@ -89,6 +91,7 @@ export async function createCollectionContent(
return {
...contentEntry,
base: absoluteBase,
version
}
}

Expand All @@ -103,6 +106,7 @@ export async function createCollectionContent(
return {
...contentEntry,
base: null,
version
}
}

Expand All @@ -116,6 +120,7 @@ export async function createCollectionContent(
return {
base: packagePath,
...contentEntry,
version
}
})

Expand Down
7 changes: 7 additions & 0 deletions cli/fileExists.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { access } from 'fs/promises'

export async function fileExists(file: string): Promise<boolean> {
return access(file)
.then(() => true)
.catch(() => false)
}
1 change: 1 addition & 0 deletions cli/getConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
export interface CollectionDefinition {
base?: string
packageName?: string
version?: string
pattern: string
name: string
}
Expand Down
6 changes: 6 additions & 0 deletions cli/templates/apiIndex.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"versions": [],
"sections": {},
"pages": {},
"tabs": {}
}
2 changes: 2 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ const config: Config = {
'^.+\\.m?jsx?$': 'babel-jest',
},
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$',
testPathIgnorePatterns: ['/node_modules/', '/__tests__/helpers/'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/src/__mocks__/styleMock.ts',
'(.+)\\.js': '$1',
'^astro:content$': '<rootDir>/src/__mocks__/astro-content.ts',
},
setupFilesAfterEnv: ['<rootDir>/test.setup.ts'],
transformIgnorePatterns: [
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@
"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": "npm run build:cli && node --max-old-space-size=4096 ./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",
"preview": "astro build && wrangler pages dev",
"preview": "wrangler pages dev",
"astro": "astro",
"deploy": "npm run build && wrangler pages deploy",
"deploy": "wrangler pages deploy",
"versions:upload": "wrangler versions upload",
"prettier": "prettier --write ./src",
"lint": "eslint . --cache --cache-strategy content",
"test": "jest",
Expand Down
22 changes: 22 additions & 0 deletions public/_routes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"version": 1,
"include": [
"/*"
],
"exclude": [
"/",
"/_astro/*",
"/.assetsignore",
"/PF-HorizontalLogo-Color.svg",
"/PF-HorizontalLogo-Reverse.svg",
"/avatarImg.svg",
"/avatarImgDark.svg",
"/favicon.svg",
"/content/*",
"/components/*",
"/layouts/*",
"/patterns/*",
"/utility-classes/*",
"/extensions/*"
]
}
6 changes: 6 additions & 0 deletions src/__mocks__/astro-content.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Mock for astro:content module
// This is a virtual module in Astro, so we need to provide a mock for Jest

export const getCollection = jest.fn();
export const getEntry = jest.fn();
export const getEntries = jest.fn();
Loading