@patternfly/patternfly-doc-core 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.astro/collections/textContent.schema.json +6 -0
- package/README.md +11 -10
- package/astro.config.mjs +8 -1
- package/cli/buildPropsData.ts +113 -0
- package/cli/cli.ts +54 -6
- package/cli/getConfig.ts +6 -0
- package/cli/hasFile.ts +5 -0
- package/cli/symLinkConfig.ts +21 -0
- package/cli/templates/pf-docs.config.mjs +14 -2
- package/cli/tsDocGen.js +199 -0
- package/dist/cli/buildPropsData.js +68 -0
- package/dist/cli/cli.js +39 -4
- package/dist/cli/hasFile.js +4 -0
- package/dist/cli/symLinkConfig.js +15 -0
- package/dist/cli/templates/pf-docs.config.mjs +13 -1
- package/dist/cli/tsDocGen.js +153 -0
- package/dist/cli/tsconfig.tsbuildinfo +1 -1
- package/dist/client/_astro/Navigation.75VF_8AW.js +1 -0
- package/dist/client/_astro/_page_.SnUmZn2y.css +1 -0
- package/dist/client/design-foundations/typography/index.html +219 -0
- package/dist/client/design-foundations/usage-and-behavior/index.html +368 -0
- package/dist/client/get-started/contribute/index.html +115 -0
- package/dist/client/index.html +42 -0
- package/dist/server/_@astrojs-ssr-adapter.mjs +1 -0
- package/dist/server/_noop-middleware.mjs +3 -0
- package/dist/server/chunks/PropsTables_D_v4KAMn.mjs +1826 -0
- package/dist/server/chunks/_@astrojs-ssr-adapter_ByVMUK8O.mjs +3621 -0
- package/dist/server/chunks/_astro_assets_CLOMnm-3.mjs +1507 -0
- package/dist/server/chunks/_astro_data-layer-content_DDGBHvtb.mjs +1 -0
- package/dist/server/chunks/angle-down-icon_BNJvzYv-.mjs +3970 -0
- package/dist/server/chunks/astro/server_D4f31GMD.mjs +2769 -0
- package/dist/server/chunks/astro-designed-error-pages_CpHpbfhr.mjs +282 -0
- package/dist/server/chunks/consts_BmVDRGlB.mjs +32 -0
- package/dist/server/chunks/content-assets_DleWbedO.mjs +1 -0
- package/dist/server/chunks/content-modules_Dz-S_Wwv.mjs +1 -0
- package/dist/server/chunks/path_Cvt6sEOY.mjs +58 -0
- package/dist/server/chunks/sharp_BYpUyJGL.mjs +88 -0
- package/dist/server/entry.mjs +45 -0
- package/dist/server/manifest_CBenwYiZ.mjs +102 -0
- package/dist/server/pages/_image.astro.mjs +132 -0
- package/dist/server/pages/_section_/_---page_.astro.mjs +1 -0
- package/dist/server/pages/_section_/_page_/_---tab_.astro.mjs +1 -0
- package/dist/server/pages/index.astro.mjs +1 -0
- package/dist/server/pages/props.astro.mjs +25 -0
- package/dist/server/renderers.mjs +259 -0
- package/jest.config.ts +1 -1
- package/package.json +4 -1
- package/pf-docs.config.mjs +31 -0
- package/src/components/Navigation.astro +15 -4
- package/src/components/Navigation.tsx +26 -2
- package/src/components/PropsTable.tsx +3 -3
- package/src/components/PropsTables.astro +38 -0
- package/src/content.config.ts +1 -0
- package/src/pages/[section]/[...page].astro +16 -8
- package/src/pages/[section]/[page]/[...tab].astro +4 -1
- package/src/pages/props.ts +17 -0
- package/src/pf-docs.config.mjs +21 -0
- package/textContent/contribute.md +1 -0
- package/dist/_astro/Navigation.Cede__Ud.js +0 -1
- package/dist/design-foundations/typography/index.html +0 -193
- package/dist/design-foundations/usage-and-behavior/index.html +0 -342
- package/dist/get-started/contribute/index.html +0 -89
- package/dist/index.html +0 -42
- /package/dist/{PF-HorizontalLogo-Color.svg → client/PF-HorizontalLogo-Color.svg} +0 -0
- /package/dist/{PF-HorizontalLogo-Reverse.svg → client/PF-HorizontalLogo-Reverse.svg} +0 -0
- /package/dist/{_astro → client/_astro}/Button.C3_jB5tC.js +0 -0
- /package/dist/{_astro → client/_astro}/ClientRouter.astro_astro_type_script_index_0_lang.Cainpjm5.js +0 -0
- /package/dist/{_astro → client/_astro}/PageContext.C7BqCh9N.js +0 -0
- /package/dist/{_astro → client/_astro}/PageToggle.DDEjruql.js +0 -0
- /package/dist/{_astro → client/_astro}/RedHatDisplayVF-Italic.CRpusWc8.woff2 +0 -0
- /package/dist/{_astro → client/_astro}/RedHatDisplayVF.CYDHf1NI.woff2 +0 -0
- /package/dist/{_astro → client/_astro}/RedHatMonoVF-Italic.DGQo2ogW.woff2 +0 -0
- /package/dist/{_astro → client/_astro}/RedHatMonoVF.C4fMH6Vz.woff2 +0 -0
- /package/dist/{_astro → client/_astro}/RedHatTextVF-Italic.Dkj_WqbA.woff2 +0 -0
- /package/dist/{_astro → client/_astro}/RedHatTextVF.wYvZ7prR.woff2 +0 -0
- /package/dist/{_astro → client/_astro}/Toolbar.TAdHxLSQ.js +0 -0
- /package/dist/{_astro → client/_astro}/_page_.CXyz_BEo.css +0 -0
- /package/dist/{_astro → client/_astro}/_page_.DVvr_Mfl.css +0 -0
- /package/dist/{_astro → client/_astro}/client.CeeiqVaE.js +0 -0
- /package/dist/{_astro → client/_astro}/divider.BSD-oFoh.js +0 -0
- /package/dist/{_astro → client/_astro}/fa-solid-900.DguXoeIz.woff2 +0 -0
- /package/dist/{_astro → client/_astro}/index.CTH3fVMn.js +0 -0
- /package/dist/{_astro → client/_astro}/page.B65lVdBS.js +0 -0
- /package/dist/{_astro → client/_astro}/pf-v6-pficon.Dy6oiu9u.woff2 +0 -0
- /package/dist/{avatarImg.svg → client/avatarImg.svg} +0 -0
- /package/dist/{avatarImgDark.svg → client/avatarImgDark.svg} +0 -0
- /package/dist/{content → client/content}/typography/line-height.png +0 -0
- /package/dist/{favicon.svg → client/favicon.svg} +0 -0
package/README.md
CHANGED
|
@@ -37,13 +37,14 @@ To define the markdown schema this project uses a typescript based schema known
|
|
|
37
37
|
|
|
38
38
|
All commands are run from the root of the project, from a terminal:
|
|
39
39
|
|
|
40
|
-
| Command | Action
|
|
41
|
-
| :------------------------ |
|
|
42
|
-
| `npm install` | Installs dependencies
|
|
43
|
-
| `npm run dev` | Starts local dev server at `localhost:4321`
|
|
44
|
-
| `npm run build` | Build your production site to `./dist/`
|
|
45
|
-
| `npm run preview` | Preview your build locally, before deploying
|
|
46
|
-
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check`
|
|
47
|
-
| `npm run astro -- --help` | Get help using the Astro CLI
|
|
48
|
-
| `npm run build:cli` | Create a JS build of the documentation core CLI
|
|
49
|
-
| `npm run build:cli:watch` | Run the CLI builder in watch mode
|
|
40
|
+
| Command | Action |
|
|
41
|
+
| :------------------------ | :-----------------------------------------------------------------|
|
|
42
|
+
| `npm install` | Installs dependencies |
|
|
43
|
+
| `npm run dev` | Starts local dev server at `localhost:4321` |
|
|
44
|
+
| `npm run build` | Build your production site to `./dist/` |
|
|
45
|
+
| `npm run preview` | Preview your build locally, before deploying |
|
|
46
|
+
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
|
|
47
|
+
| `npm run astro -- --help` | Get help using the Astro CLI |
|
|
48
|
+
| `npm run build:cli` | Create a JS build of the documentation core CLI |
|
|
49
|
+
| `npm run build:cli:watch` | Run the CLI builder in watch mode |
|
|
50
|
+
| `npm run build:props` | Create a json file of your TsDoc compatible in code documentation |
|
package/astro.config.mjs
CHANGED
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
import { defineConfig } from 'astro/config';
|
|
3
3
|
import react from '@astrojs/react';
|
|
4
4
|
|
|
5
|
+
import node from '@astrojs/node';
|
|
6
|
+
|
|
5
7
|
// https://astro.build/config
|
|
6
8
|
export default defineConfig({
|
|
7
9
|
integrations: [react()],
|
|
10
|
+
|
|
8
11
|
vite: {
|
|
9
12
|
ssr: {
|
|
10
13
|
noExternal: ["@patternfly/*", "react-dropzone"],
|
|
@@ -14,5 +17,9 @@ export default defineConfig({
|
|
|
14
17
|
allow: ['./']
|
|
15
18
|
}
|
|
16
19
|
}
|
|
17
|
-
}
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
adapter: node({
|
|
23
|
+
mode: 'standalone'
|
|
24
|
+
})
|
|
18
25
|
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
3
|
+
import { glob } from 'glob'
|
|
4
|
+
import { writeFile } from 'fs/promises'
|
|
5
|
+
import { join } from 'path'
|
|
6
|
+
|
|
7
|
+
import { tsDocgen } from './tsDocGen.js'
|
|
8
|
+
import { getConfig, PropsGlobs } from './getConfig.js'
|
|
9
|
+
|
|
10
|
+
interface Prop {
|
|
11
|
+
name: string
|
|
12
|
+
type: string
|
|
13
|
+
description?: string
|
|
14
|
+
required?: boolean
|
|
15
|
+
defaultValue?: string
|
|
16
|
+
hide?: boolean
|
|
17
|
+
}
|
|
18
|
+
interface TsDoc {
|
|
19
|
+
name: string
|
|
20
|
+
description: string
|
|
21
|
+
props: Prop[]
|
|
22
|
+
}
|
|
23
|
+
interface PropsData {
|
|
24
|
+
[key: string]: TsDoc
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Build unique names for components with a "variant" extension
|
|
28
|
+
type TsDocVariants = 'next' | 'deprecated' | undefined
|
|
29
|
+
function getTsDocName(name: string, variant: TsDocVariants) {
|
|
30
|
+
return `${name}${variant ? `-${variant}` : ''}`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getTsDocNameVariant(source: string) {
|
|
34
|
+
if (source.includes('next')) {
|
|
35
|
+
return 'next'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (source.includes('deprecated')) {
|
|
39
|
+
return 'deprecated'
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function getFiles(root: string, globs: PropsGlobs[]) {
|
|
44
|
+
const files = await Promise.all(
|
|
45
|
+
globs.map(async ({ include, exclude }) => {
|
|
46
|
+
const files = await glob(include, { cwd: root, ignore: exclude })
|
|
47
|
+
return files
|
|
48
|
+
}),
|
|
49
|
+
)
|
|
50
|
+
return files.flat()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function getPropsData(files: string[], verbose: boolean) {
|
|
54
|
+
const perFilePropsData = await Promise.all(
|
|
55
|
+
files.map(async (file) => {
|
|
56
|
+
if (verbose) {
|
|
57
|
+
console.log(`Parsing props from ${file}`)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const props = (await tsDocgen(file)) as TsDoc[]
|
|
61
|
+
|
|
62
|
+
const tsDocs = props.reduce((acc, { name, description, props }) => {
|
|
63
|
+
const key = getTsDocName(name, getTsDocNameVariant(file))
|
|
64
|
+
return { ...acc, [key]: { name, description, props } }
|
|
65
|
+
}, {} as PropsData)
|
|
66
|
+
|
|
67
|
+
return tsDocs
|
|
68
|
+
}),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
const combinedPropsData = perFilePropsData.reduce((acc, props) => {
|
|
72
|
+
Object.keys(props).forEach((key) => {
|
|
73
|
+
const propsData = props[key]
|
|
74
|
+
if (acc[key]) {
|
|
75
|
+
acc[key].props = [...acc[key].props, ...propsData.props]
|
|
76
|
+
} else {
|
|
77
|
+
acc[key] = propsData
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
return acc
|
|
81
|
+
}, {})
|
|
82
|
+
|
|
83
|
+
return combinedPropsData
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function buildPropsData(
|
|
87
|
+
rootDir: string,
|
|
88
|
+
astroRoot: string,
|
|
89
|
+
configFile: string,
|
|
90
|
+
verbose: boolean,
|
|
91
|
+
) {
|
|
92
|
+
const config = await getConfig(configFile)
|
|
93
|
+
if (!config) {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const { propsGlobs } = config
|
|
98
|
+
if (!propsGlobs) {
|
|
99
|
+
console.error('No props data found in config')
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const files = await getFiles(rootDir, propsGlobs)
|
|
104
|
+
if (verbose) {
|
|
105
|
+
console.log(`Found ${files.length} files to parse`)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const propsData = await getPropsData(files, verbose)
|
|
109
|
+
|
|
110
|
+
const propsFile = join(astroRoot, 'dist', 'props.json')
|
|
111
|
+
|
|
112
|
+
await writeFile(propsFile, JSON.stringify(propsData))
|
|
113
|
+
}
|
package/cli/cli.ts
CHANGED
|
@@ -8,6 +8,9 @@ import { setFsRootDir } from './setFsRootDir.js'
|
|
|
8
8
|
import { createConfigFile } from './createConfigFile.js'
|
|
9
9
|
import { updatePackageFile } from './updatePackageFile.js'
|
|
10
10
|
import { getConfig } from './getConfig.js'
|
|
11
|
+
import { symLinkConfig } from './symLinkConfig.js'
|
|
12
|
+
import { buildPropsData } from './buildPropsData.js'
|
|
13
|
+
import { hasFile } from './hasFile.js'
|
|
11
14
|
|
|
12
15
|
function updateContent(program: Command) {
|
|
13
16
|
const { verbose } = program.opts()
|
|
@@ -23,16 +26,47 @@ function updateContent(program: Command) {
|
|
|
23
26
|
)
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
.
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
async function generateProps(program: Command, forceProps: boolean = false) {
|
|
30
|
+
const { verbose, props } = program.opts()
|
|
31
|
+
|
|
32
|
+
if (!props && !forceProps) {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (verbose) {
|
|
37
|
+
console.log('Verbose mode enabled')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
buildPropsData(
|
|
41
|
+
currentDir,
|
|
42
|
+
astroRoot,
|
|
43
|
+
`${currentDir}/pf-docs.config.mjs`,
|
|
44
|
+
verbose,
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let astroRoot = ''
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
astroRoot = import.meta
|
|
52
|
+
.resolve('@patternfly/patternfly-doc-core')
|
|
53
|
+
.replace('dist/cli/cli.js', '')
|
|
54
|
+
.replace('file://', '')
|
|
55
|
+
} catch (e: any) {
|
|
56
|
+
if (e.code === 'ERR_MODULE_NOT_FOUND') {
|
|
57
|
+
astroRoot = process.cwd()
|
|
58
|
+
} else {
|
|
59
|
+
console.error('Error resolving astroRoot', e)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
30
63
|
const currentDir = process.cwd()
|
|
31
64
|
|
|
32
65
|
const program = new Command()
|
|
33
66
|
program.name('pf-doc-core')
|
|
34
67
|
|
|
35
68
|
program.option('--verbose', 'verbose mode', false)
|
|
69
|
+
program.option('--props', 'generate props data', false)
|
|
36
70
|
|
|
37
71
|
program.command('setup').action(async () => {
|
|
38
72
|
await Promise.all([
|
|
@@ -47,6 +81,7 @@ program.command('setup').action(async () => {
|
|
|
47
81
|
|
|
48
82
|
program.command('init').action(async () => {
|
|
49
83
|
await setFsRootDir(astroRoot, currentDir)
|
|
84
|
+
await symLinkConfig(astroRoot, currentDir)
|
|
50
85
|
console.log(
|
|
51
86
|
'\nInitialization complete, next update your pf-docs.config.mjs file and then run the `start` script to start the dev server',
|
|
52
87
|
)
|
|
@@ -54,11 +89,17 @@ program.command('init').action(async () => {
|
|
|
54
89
|
|
|
55
90
|
program.command('start').action(async () => {
|
|
56
91
|
updateContent(program)
|
|
92
|
+
|
|
93
|
+
// if a props file hasn't been generated yet, but the consumer has propsData, it will cause a runtime error so to
|
|
94
|
+
// prevent that we're just creating a props file regardless of what they say if one doesn't exist yet
|
|
95
|
+
const hasPropsFile = await hasFile(join(astroRoot, 'dist', 'props.json'))
|
|
96
|
+
await generateProps(program, !hasPropsFile)
|
|
57
97
|
dev({ mode: 'development', root: astroRoot })
|
|
58
98
|
})
|
|
59
99
|
|
|
60
100
|
program.command('build').action(async () => {
|
|
61
101
|
updateContent(program)
|
|
102
|
+
await generateProps(program, true)
|
|
62
103
|
const config = await getConfig(`${currentDir}/pf-docs.config.mjs`)
|
|
63
104
|
if (!config) {
|
|
64
105
|
console.error(
|
|
@@ -68,13 +109,20 @@ program.command('build').action(async () => {
|
|
|
68
109
|
}
|
|
69
110
|
|
|
70
111
|
if (!config.outputDir) {
|
|
71
|
-
console.error(
|
|
112
|
+
console.error(
|
|
113
|
+
"No outputDir found in config file, an output directory must be defined in your config file e.g. 'dist'",
|
|
114
|
+
)
|
|
72
115
|
return
|
|
73
116
|
}
|
|
74
|
-
|
|
117
|
+
|
|
75
118
|
build({ root: astroRoot, outDir: join(currentDir, config.outputDir) })
|
|
76
119
|
})
|
|
77
120
|
|
|
121
|
+
program.command('generate-props').action(async () => {
|
|
122
|
+
await generateProps(program, true)
|
|
123
|
+
console.log('\nProps data generated')
|
|
124
|
+
})
|
|
125
|
+
|
|
78
126
|
program.command('serve').action(async () => {
|
|
79
127
|
updateContent(program)
|
|
80
128
|
preview({ root: astroRoot })
|
package/cli/getConfig.ts
CHANGED
|
@@ -6,9 +6,15 @@ export interface CollectionDefinition {
|
|
|
6
6
|
name: string
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
export interface PropsGlobs {
|
|
10
|
+
include: string[]
|
|
11
|
+
exclude: string[]
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
export interface DocsConfig {
|
|
10
15
|
content: CollectionDefinition[];
|
|
11
16
|
outputDir: string;
|
|
17
|
+
propsGlobs: PropsGlobs[];
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
export async function getConfig(fileLocation: string): Promise<DocsConfig | undefined> {
|
package/cli/hasFile.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { symlink } from 'fs/promises'
|
|
3
|
+
|
|
4
|
+
export async function symLinkConfig(
|
|
5
|
+
astroRootDir: string,
|
|
6
|
+
consumerRootDir: string,
|
|
7
|
+
) {
|
|
8
|
+
const configFileName = '/pf-docs.config.mjs'
|
|
9
|
+
const docsConfigFile = consumerRootDir + configFileName
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
await symlink(docsConfigFile, astroRootDir + configFileName)
|
|
13
|
+
} catch (e: any) {
|
|
14
|
+
console.error(
|
|
15
|
+
`Error creating symlink to ${docsConfigFile} in ${astroRootDir}`,
|
|
16
|
+
e,
|
|
17
|
+
)
|
|
18
|
+
} finally {
|
|
19
|
+
console.log(`Symlink to ${docsConfigFile} in ${astroRootDir} created`)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -16,5 +16,17 @@ export const config = {
|
|
|
16
16
|
// name: "react-component-docs",
|
|
17
17
|
// },
|
|
18
18
|
],
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
navSectionOrder: ["get-started", "design-foundations"],
|
|
20
|
+
outputDir: './dist/docs',
|
|
21
|
+
propsGlobs: [
|
|
22
|
+
// {
|
|
23
|
+
// include: ['*/@patternfly/react-core/src/**/*.tsx'],
|
|
24
|
+
// exclude: [
|
|
25
|
+
// '/**/examples/**',
|
|
26
|
+
// '/**/__mocks__/**',
|
|
27
|
+
// '/**/__tests__/**',
|
|
28
|
+
// '/**/*.test.tsx',
|
|
29
|
+
// ],
|
|
30
|
+
// },
|
|
31
|
+
],
|
|
32
|
+
}
|
package/cli/tsDocGen.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { readFile } from 'fs/promises'
|
|
2
|
+
import { parse } from 'react-docgen'
|
|
3
|
+
import ts from 'typescript'
|
|
4
|
+
|
|
5
|
+
const annotations = [
|
|
6
|
+
{
|
|
7
|
+
regex: /@deprecated/,
|
|
8
|
+
name: 'deprecated',
|
|
9
|
+
type: 'Boolean',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
regex: /@hide/,
|
|
13
|
+
name: 'hide',
|
|
14
|
+
type: 'Boolean',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
regex: /@beta/,
|
|
18
|
+
name: 'beta',
|
|
19
|
+
type: 'Boolean',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
regex: /@propType\s+(.*)/,
|
|
23
|
+
name: 'type',
|
|
24
|
+
type: 'String',
|
|
25
|
+
},
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
function addAnnotations(prop) {
|
|
29
|
+
if (prop.description) {
|
|
30
|
+
annotations.forEach(({ regex, name }) => {
|
|
31
|
+
const match = prop.description.match(regex)
|
|
32
|
+
if (match) {
|
|
33
|
+
prop.description = prop.description.replace(regex, '').trim()
|
|
34
|
+
if (name) {
|
|
35
|
+
prop[name] = match[2] || match[1] || true
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return prop
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getComponentMetadata(filename, sourceText) {
|
|
45
|
+
let parsedComponents = null
|
|
46
|
+
try {
|
|
47
|
+
parsedComponents = parse(sourceText, { filename })
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
49
|
+
} catch (_err) {
|
|
50
|
+
// eslint-disable-next-line no-console
|
|
51
|
+
// console.warn(`No component found in ${filename}:`, err);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return (parsedComponents || []).filter(
|
|
55
|
+
(parsed) => parsed && parsed.displayName,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const getNodeText = (node, sourceText) => {
|
|
60
|
+
if (!node || !node.pos || !node.end) {
|
|
61
|
+
return undefined
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return sourceText.substring(node.pos, node.end).trim()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const buildJsDocProps = (nodes, sourceText) =>
|
|
68
|
+
nodes?.reduce((acc, member) => {
|
|
69
|
+
const name =
|
|
70
|
+
(member.name && member.name.escapedText) ||
|
|
71
|
+
(member.parameters &&
|
|
72
|
+
`[${getNodeText(member.parameters[0], sourceText)}]`) ||
|
|
73
|
+
'Unknown'
|
|
74
|
+
acc[name] = {
|
|
75
|
+
description: member.jsDoc
|
|
76
|
+
? member.jsDoc.map((doc) => doc.comment).join('\n')
|
|
77
|
+
: null,
|
|
78
|
+
required: member.questionToken === undefined,
|
|
79
|
+
type: {
|
|
80
|
+
raw: getNodeText(member.type, sourceText).trim(),
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
return acc
|
|
84
|
+
}, {})
|
|
85
|
+
|
|
86
|
+
const getSourceFileStatements = (filename, sourceText) => {
|
|
87
|
+
const { statements } = ts.createSourceFile(
|
|
88
|
+
filename,
|
|
89
|
+
sourceText,
|
|
90
|
+
ts.ScriptTarget.Latest, // languageVersion
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
return statements
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const getInterfaceMetadata = (filename, sourceText) =>
|
|
97
|
+
getSourceFileStatements(filename, sourceText).reduce(
|
|
98
|
+
(metaDataAcc, statement) => {
|
|
99
|
+
if (statement.kind === ts.SyntaxKind.InterfaceDeclaration) {
|
|
100
|
+
const _statement = statement
|
|
101
|
+
metaDataAcc.push({
|
|
102
|
+
displayName: _statement.name.escapedText,
|
|
103
|
+
description: _statement.jsDoc?.map((doc) => doc.comment).join('\n'),
|
|
104
|
+
props: buildJsDocProps(_statement.members, sourceText),
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return metaDataAcc
|
|
109
|
+
},
|
|
110
|
+
[],
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
const getTypeAliasMetadata = (filename, sourceText) =>
|
|
114
|
+
getSourceFileStatements(filename, sourceText).reduce(
|
|
115
|
+
(metaDataAcc, statement) => {
|
|
116
|
+
if (statement.kind === ts.SyntaxKind.TypeAliasDeclaration) {
|
|
117
|
+
const _statement = statement
|
|
118
|
+
const props = _statement.type.types?.reduce((propAcc, type) => {
|
|
119
|
+
if (type.members) {
|
|
120
|
+
propAcc.push(buildJsDocProps(type.members, sourceText))
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return propAcc
|
|
124
|
+
}, [])
|
|
125
|
+
|
|
126
|
+
metaDataAcc.push({
|
|
127
|
+
props,
|
|
128
|
+
displayName: _statement.name.escapedText,
|
|
129
|
+
description: _statement.jsDoc?.map((doc) => doc.comment).join('\n'),
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return metaDataAcc
|
|
134
|
+
},
|
|
135
|
+
[],
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
function normalizeProp([
|
|
139
|
+
name,
|
|
140
|
+
{ required, annotatedType, type, tsType, description, defaultValue },
|
|
141
|
+
]) {
|
|
142
|
+
const res = {
|
|
143
|
+
name,
|
|
144
|
+
type:
|
|
145
|
+
annotatedType ||
|
|
146
|
+
(type && type.name) ||
|
|
147
|
+
(type && (type.raw || type.name)) ||
|
|
148
|
+
(tsType && (tsType.raw || tsType.name)) ||
|
|
149
|
+
'No type info',
|
|
150
|
+
description,
|
|
151
|
+
}
|
|
152
|
+
if (required) {
|
|
153
|
+
res.required = true
|
|
154
|
+
}
|
|
155
|
+
if (defaultValue && defaultValue.value) {
|
|
156
|
+
res.defaultValue = defaultValue.value
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return res
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export async function tsDocgen(file) {
|
|
163
|
+
const sourceText = await readFile(file, 'utf8')
|
|
164
|
+
const componentMeta = getComponentMetadata(file, sourceText) // Array of components with props
|
|
165
|
+
const interfaceMeta = getInterfaceMetadata(file, sourceText) // Array of interfaces with props
|
|
166
|
+
const typeAliasMeta = getTypeAliasMetadata(file, sourceText) // Array of type aliases with props
|
|
167
|
+
const propsMetaMap = [...interfaceMeta, ...typeAliasMeta].reduce(function (
|
|
168
|
+
target,
|
|
169
|
+
interfaceOrTypeAlias,
|
|
170
|
+
) {
|
|
171
|
+
target[interfaceOrTypeAlias.displayName] = interfaceOrTypeAlias
|
|
172
|
+
return target
|
|
173
|
+
}, {})
|
|
174
|
+
|
|
175
|
+
// Go through each component and check if they have an interface or type alias with a jsDoc description
|
|
176
|
+
// If so copy it over (fix for https://github.com/patternfly/patternfly-react/issues/7612)
|
|
177
|
+
componentMeta.forEach((c) => {
|
|
178
|
+
if (c.description) {
|
|
179
|
+
return c
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const propsName = `${c.displayName}Props`
|
|
183
|
+
if (propsMetaMap[propsName]?.description) {
|
|
184
|
+
c.description = propsMetaMap[propsName].description
|
|
185
|
+
}
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
return [...componentMeta, ...interfaceMeta, ...typeAliasMeta].map(
|
|
189
|
+
(parsed) => ({
|
|
190
|
+
name: parsed.displayName,
|
|
191
|
+
description: parsed.description || '',
|
|
192
|
+
props: Object.entries(parsed.props || {})
|
|
193
|
+
.map(normalizeProp)
|
|
194
|
+
.map(addAnnotations)
|
|
195
|
+
.filter((prop) => !prop.hide)
|
|
196
|
+
.sort((p1, p2) => p1.name.localeCompare(p2.name)),
|
|
197
|
+
}),
|
|
198
|
+
)
|
|
199
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { glob } from 'glob';
|
|
3
|
+
import { writeFile } from 'fs/promises';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { tsDocgen } from './tsDocGen.js';
|
|
6
|
+
import { getConfig } from './getConfig.js';
|
|
7
|
+
function getTsDocName(name, variant) {
|
|
8
|
+
return `${name}${variant ? `-${variant}` : ''}`;
|
|
9
|
+
}
|
|
10
|
+
function getTsDocNameVariant(source) {
|
|
11
|
+
if (source.includes('next')) {
|
|
12
|
+
return 'next';
|
|
13
|
+
}
|
|
14
|
+
if (source.includes('deprecated')) {
|
|
15
|
+
return 'deprecated';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function getFiles(root, globs) {
|
|
19
|
+
const files = await Promise.all(globs.map(async ({ include, exclude }) => {
|
|
20
|
+
const files = await glob(include, { cwd: root, ignore: exclude });
|
|
21
|
+
return files;
|
|
22
|
+
}));
|
|
23
|
+
return files.flat();
|
|
24
|
+
}
|
|
25
|
+
async function getPropsData(files, verbose) {
|
|
26
|
+
const perFilePropsData = await Promise.all(files.map(async (file) => {
|
|
27
|
+
if (verbose) {
|
|
28
|
+
console.log(`Parsing props from ${file}`);
|
|
29
|
+
}
|
|
30
|
+
const props = (await tsDocgen(file));
|
|
31
|
+
const tsDocs = props.reduce((acc, { name, description, props }) => {
|
|
32
|
+
const key = getTsDocName(name, getTsDocNameVariant(file));
|
|
33
|
+
return { ...acc, [key]: { name, description, props } };
|
|
34
|
+
}, {});
|
|
35
|
+
return tsDocs;
|
|
36
|
+
}));
|
|
37
|
+
const combinedPropsData = perFilePropsData.reduce((acc, props) => {
|
|
38
|
+
Object.keys(props).forEach((key) => {
|
|
39
|
+
const propsData = props[key];
|
|
40
|
+
if (acc[key]) {
|
|
41
|
+
acc[key].props = [...acc[key].props, ...propsData.props];
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
acc[key] = propsData;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
return acc;
|
|
48
|
+
}, {});
|
|
49
|
+
return combinedPropsData;
|
|
50
|
+
}
|
|
51
|
+
export async function buildPropsData(rootDir, astroRoot, configFile, verbose) {
|
|
52
|
+
const config = await getConfig(configFile);
|
|
53
|
+
if (!config) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const { propsGlobs } = config;
|
|
57
|
+
if (!propsGlobs) {
|
|
58
|
+
console.error('No props data found in config');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const files = await getFiles(rootDir, propsGlobs);
|
|
62
|
+
if (verbose) {
|
|
63
|
+
console.log(`Found ${files.length} files to parse`);
|
|
64
|
+
}
|
|
65
|
+
const propsData = await getPropsData(files, verbose);
|
|
66
|
+
const propsFile = join(astroRoot, 'dist', 'props.json');
|
|
67
|
+
await writeFile(propsFile, JSON.stringify(propsData));
|
|
68
|
+
}
|