@patternfly/patternfly-doc-core 1.2.0 → 1.3.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.
Files changed (83) hide show
  1. package/.astro/collections/textContent.schema.json +6 -0
  2. package/README.md +11 -10
  3. package/astro.config.mjs +8 -1
  4. package/cli/buildPropsData.ts +113 -0
  5. package/cli/cli.ts +52 -6
  6. package/cli/getConfig.ts +6 -0
  7. package/cli/hasFile.ts +5 -0
  8. package/cli/templates/pf-docs.config.mjs +13 -2
  9. package/cli/tsDocGen.js +199 -0
  10. package/dist/cli/buildPropsData.js +68 -0
  11. package/dist/cli/cli.js +37 -4
  12. package/dist/cli/hasFile.js +4 -0
  13. package/dist/cli/templates/pf-docs.config.mjs +12 -1
  14. package/dist/cli/tsDocGen.js +153 -0
  15. package/dist/cli/tsconfig.tsbuildinfo +1 -1
  16. package/dist/client/_astro/_page_.SnUmZn2y.css +1 -0
  17. package/dist/client/design-foundations/typography/index.html +219 -0
  18. package/dist/client/design-foundations/usage-and-behavior/index.html +368 -0
  19. package/dist/client/get-started/contribute/index.html +115 -0
  20. package/dist/client/index.html +42 -0
  21. package/dist/server/_@astrojs-ssr-adapter.mjs +1 -0
  22. package/dist/server/_noop-middleware.mjs +3 -0
  23. package/dist/server/chunks/PropsTables_D_v4KAMn.mjs +1826 -0
  24. package/dist/server/chunks/_@astrojs-ssr-adapter_ByVMUK8O.mjs +3621 -0
  25. package/dist/server/chunks/_astro_assets_CLOMnm-3.mjs +1507 -0
  26. package/dist/server/chunks/_astro_data-layer-content_DDGBHvtb.mjs +1 -0
  27. package/dist/server/chunks/angle-down-icon_BNJvzYv-.mjs +3970 -0
  28. package/dist/server/chunks/astro/server_D4f31GMD.mjs +2769 -0
  29. package/dist/server/chunks/astro-designed-error-pages_CpHpbfhr.mjs +282 -0
  30. package/dist/server/chunks/consts_BmVDRGlB.mjs +32 -0
  31. package/dist/server/chunks/content-assets_DleWbedO.mjs +1 -0
  32. package/dist/server/chunks/content-modules_Dz-S_Wwv.mjs +1 -0
  33. package/dist/server/chunks/path_Cvt6sEOY.mjs +58 -0
  34. package/dist/server/chunks/sharp_BYpUyJGL.mjs +88 -0
  35. package/dist/server/entry.mjs +45 -0
  36. package/dist/server/manifest_Bln0Ib60.mjs +102 -0
  37. package/dist/server/pages/_image.astro.mjs +132 -0
  38. package/dist/server/pages/_section_/_---page_.astro.mjs +1 -0
  39. package/dist/server/pages/_section_/_page_/_---tab_.astro.mjs +1 -0
  40. package/dist/server/pages/index.astro.mjs +1 -0
  41. package/dist/server/pages/props.astro.mjs +25 -0
  42. package/dist/server/renderers.mjs +259 -0
  43. package/jest.config.ts +1 -1
  44. package/package.json +5 -2
  45. package/pf-docs.config.mjs +31 -0
  46. package/release.config.mjs +1 -1
  47. package/src/components/PropsTable.tsx +3 -3
  48. package/src/components/PropsTables.astro +38 -0
  49. package/src/content.config.ts +1 -0
  50. package/src/pages/[section]/[...page].astro +16 -8
  51. package/src/pages/[section]/[page]/[...tab].astro +4 -1
  52. package/src/pages/props.ts +17 -0
  53. package/textContent/contribute.md +1 -0
  54. package/dist/design-foundations/typography/index.html +0 -193
  55. package/dist/design-foundations/usage-and-behavior/index.html +0 -342
  56. package/dist/get-started/contribute/index.html +0 -89
  57. package/dist/index.html +0 -42
  58. /package/dist/{PF-HorizontalLogo-Color.svg → client/PF-HorizontalLogo-Color.svg} +0 -0
  59. /package/dist/{PF-HorizontalLogo-Reverse.svg → client/PF-HorizontalLogo-Reverse.svg} +0 -0
  60. /package/dist/{_astro → client/_astro}/Button.C3_jB5tC.js +0 -0
  61. /package/dist/{_astro → client/_astro}/ClientRouter.astro_astro_type_script_index_0_lang.Cainpjm5.js +0 -0
  62. /package/dist/{_astro → client/_astro}/Navigation.Cede__Ud.js +0 -0
  63. /package/dist/{_astro → client/_astro}/PageContext.C7BqCh9N.js +0 -0
  64. /package/dist/{_astro → client/_astro}/PageToggle.DDEjruql.js +0 -0
  65. /package/dist/{_astro → client/_astro}/RedHatDisplayVF-Italic.CRpusWc8.woff2 +0 -0
  66. /package/dist/{_astro → client/_astro}/RedHatDisplayVF.CYDHf1NI.woff2 +0 -0
  67. /package/dist/{_astro → client/_astro}/RedHatMonoVF-Italic.DGQo2ogW.woff2 +0 -0
  68. /package/dist/{_astro → client/_astro}/RedHatMonoVF.C4fMH6Vz.woff2 +0 -0
  69. /package/dist/{_astro → client/_astro}/RedHatTextVF-Italic.Dkj_WqbA.woff2 +0 -0
  70. /package/dist/{_astro → client/_astro}/RedHatTextVF.wYvZ7prR.woff2 +0 -0
  71. /package/dist/{_astro → client/_astro}/Toolbar.TAdHxLSQ.js +0 -0
  72. /package/dist/{_astro → client/_astro}/_page_.CXyz_BEo.css +0 -0
  73. /package/dist/{_astro → client/_astro}/_page_.DVvr_Mfl.css +0 -0
  74. /package/dist/{_astro → client/_astro}/client.CeeiqVaE.js +0 -0
  75. /package/dist/{_astro → client/_astro}/divider.BSD-oFoh.js +0 -0
  76. /package/dist/{_astro → client/_astro}/fa-solid-900.DguXoeIz.woff2 +0 -0
  77. /package/dist/{_astro → client/_astro}/index.CTH3fVMn.js +0 -0
  78. /package/dist/{_astro → client/_astro}/page.B65lVdBS.js +0 -0
  79. /package/dist/{_astro → client/_astro}/pf-v6-pficon.Dy6oiu9u.woff2 +0 -0
  80. /package/dist/{avatarImg.svg → client/avatarImg.svg} +0 -0
  81. /package/dist/{avatarImgDark.svg → client/avatarImgDark.svg} +0 -0
  82. /package/dist/{content → client/content}/typography/line-height.png +0 -0
  83. /package/dist/{favicon.svg → client/favicon.svg} +0 -0
@@ -16,6 +16,12 @@
16
16
  "title": {
17
17
  "type": "string"
18
18
  },
19
+ "propComponents": {
20
+ "type": "array",
21
+ "items": {
22
+ "type": "string"
23
+ }
24
+ },
19
25
  "tab": {
20
26
  "type": "string"
21
27
  },
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,8 @@ 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 { buildPropsData } from './buildPropsData.js'
12
+ import { hasFile } from './hasFile.js'
11
13
 
12
14
  function updateContent(program: Command) {
13
15
  const { verbose } = program.opts()
@@ -23,16 +25,47 @@ function updateContent(program: Command) {
23
25
  )
24
26
  }
25
27
 
26
- const astroRoot = import.meta
27
- .resolve('@patternfly/patternfly-doc-core')
28
- .replace('dist/cli/cli.js', '')
29
- .replace('file://', '')
28
+ async function generateProps(program: Command, forceProps: boolean = false) {
29
+ const { verbose, props } = program.opts()
30
+
31
+ if (!props && !forceProps) {
32
+ return
33
+ }
34
+
35
+ if (verbose) {
36
+ console.log('Verbose mode enabled')
37
+ }
38
+
39
+ buildPropsData(
40
+ currentDir,
41
+ astroRoot,
42
+ `${currentDir}/pf-docs.config.mjs`,
43
+ verbose,
44
+ )
45
+ }
46
+
47
+ let astroRoot = ''
48
+
49
+ try {
50
+ astroRoot = import.meta
51
+ .resolve('@patternfly/patternfly-doc-core')
52
+ .replace('dist/cli/cli.js', '')
53
+ .replace('file://', '')
54
+ } catch (e: any) {
55
+ if (e.code === 'ERR_MODULE_NOT_FOUND') {
56
+ astroRoot = process.cwd()
57
+ } else {
58
+ console.error('Error resolving astroRoot', e)
59
+ }
60
+ }
61
+
30
62
  const currentDir = process.cwd()
31
63
 
32
64
  const program = new Command()
33
65
  program.name('pf-doc-core')
34
66
 
35
67
  program.option('--verbose', 'verbose mode', false)
68
+ program.option('--props', 'generate props data', false)
36
69
 
37
70
  program.command('setup').action(async () => {
38
71
  await Promise.all([
@@ -54,11 +87,17 @@ program.command('init').action(async () => {
54
87
 
55
88
  program.command('start').action(async () => {
56
89
  updateContent(program)
90
+
91
+ // if a props file hasn't been generated yet, but the consumer has propsData, it will cause a runtime error so to
92
+ // prevent that we're just creating a props file regardless of what they say if one doesn't exist yet
93
+ const hasPropsFile = await hasFile(join(astroRoot, 'dist', 'props.json'))
94
+ await generateProps(program, !hasPropsFile)
57
95
  dev({ mode: 'development', root: astroRoot })
58
96
  })
59
97
 
60
98
  program.command('build').action(async () => {
61
99
  updateContent(program)
100
+ await generateProps(program, true)
62
101
  const config = await getConfig(`${currentDir}/pf-docs.config.mjs`)
63
102
  if (!config) {
64
103
  console.error(
@@ -68,13 +107,20 @@ program.command('build').action(async () => {
68
107
  }
69
108
 
70
109
  if (!config.outputDir) {
71
- console.error("No outputDir found in config file, an output directory must be defined in your config file e.g. 'dist'")
110
+ console.error(
111
+ "No outputDir found in config file, an output directory must be defined in your config file e.g. 'dist'",
112
+ )
72
113
  return
73
114
  }
74
-
115
+
75
116
  build({ root: astroRoot, outDir: join(currentDir, config.outputDir) })
76
117
  })
77
118
 
119
+ program.command('generate-props').action(async () => {
120
+ await generateProps(program, true)
121
+ console.log('\nProps data generated')
122
+ })
123
+
78
124
  program.command('serve').action(async () => {
79
125
  updateContent(program)
80
126
  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,5 @@
1
+ import { readFile } from "fs/promises";
2
+
3
+ export async function hasFile(path: string) {
4
+ return readFile(path).then(() => true, () => false)
5
+ }
@@ -16,5 +16,16 @@ export const config = {
16
16
  // name: "react-component-docs",
17
17
  // },
18
18
  ],
19
- outputDir: "./dist/docs"
20
- };
19
+ outputDir: './dist/docs',
20
+ propsGlobs: [
21
+ // {
22
+ // include: ['*/@patternfly/react-core/src/**/*.tsx'],
23
+ // exclude: [
24
+ // '/**/examples/**',
25
+ // '/**/__mocks__/**',
26
+ // '/**/__tests__/**',
27
+ // '/**/*.test.tsx',
28
+ // ],
29
+ // },
30
+ ],
31
+ }
@@ -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
+ }
package/dist/cli/cli.js CHANGED
@@ -8,6 +8,8 @@ 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 { buildPropsData } from './buildPropsData.js';
12
+ import { hasFile } from './hasFile.js';
11
13
  function updateContent(program) {
12
14
  const { verbose } = program.opts();
13
15
  if (verbose) {
@@ -15,14 +17,36 @@ function updateContent(program) {
15
17
  }
16
18
  createCollectionContent(astroRoot, `${process.cwd()}/pf-docs.config.mjs`, verbose);
17
19
  }
18
- const astroRoot = import.meta
19
- .resolve('@patternfly/patternfly-doc-core')
20
- .replace('dist/cli/cli.js', '')
21
- .replace('file://', '');
20
+ async function generateProps(program, forceProps = false) {
21
+ const { verbose, props } = program.opts();
22
+ if (!props && !forceProps) {
23
+ return;
24
+ }
25
+ if (verbose) {
26
+ console.log('Verbose mode enabled');
27
+ }
28
+ buildPropsData(currentDir, astroRoot, `${currentDir}/pf-docs.config.mjs`, verbose);
29
+ }
30
+ let astroRoot = '';
31
+ try {
32
+ astroRoot = import.meta
33
+ .resolve('@patternfly/patternfly-doc-core')
34
+ .replace('dist/cli/cli.js', '')
35
+ .replace('file://', '');
36
+ }
37
+ catch (e) {
38
+ if (e.code === 'ERR_MODULE_NOT_FOUND') {
39
+ astroRoot = process.cwd();
40
+ }
41
+ else {
42
+ console.error('Error resolving astroRoot', e);
43
+ }
44
+ }
22
45
  const currentDir = process.cwd();
23
46
  const program = new Command();
24
47
  program.name('pf-doc-core');
25
48
  program.option('--verbose', 'verbose mode', false);
49
+ program.option('--props', 'generate props data', false);
26
50
  program.command('setup').action(async () => {
27
51
  await Promise.all([
28
52
  updatePackageFile(astroRoot, currentDir),
@@ -36,10 +60,15 @@ program.command('init').action(async () => {
36
60
  });
37
61
  program.command('start').action(async () => {
38
62
  updateContent(program);
63
+ // if a props file hasn't been generated yet, but the consumer has propsData, it will cause a runtime error so to
64
+ // prevent that we're just creating a props file regardless of what they say if one doesn't exist yet
65
+ const hasPropsFile = await hasFile(join(astroRoot, 'dist', 'props.json'));
66
+ await generateProps(program, !hasPropsFile);
39
67
  dev({ mode: 'development', root: astroRoot });
40
68
  });
41
69
  program.command('build').action(async () => {
42
70
  updateContent(program);
71
+ await generateProps(program, true);
43
72
  const config = await getConfig(`${currentDir}/pf-docs.config.mjs`);
44
73
  if (!config) {
45
74
  console.error('No config found, please run the `setup` command or manually create a pf-docs.config.mjs file');
@@ -51,6 +80,10 @@ program.command('build').action(async () => {
51
80
  }
52
81
  build({ root: astroRoot, outDir: join(currentDir, config.outputDir) });
53
82
  });
83
+ program.command('generate-props').action(async () => {
84
+ await generateProps(program, true);
85
+ console.log('\nProps data generated');
86
+ });
54
87
  program.command('serve').action(async () => {
55
88
  updateContent(program);
56
89
  preview({ root: astroRoot });
@@ -0,0 +1,4 @@
1
+ import { readFile } from "fs/promises";
2
+ export async function hasFile(path) {
3
+ return readFile(path).then(() => true, () => false);
4
+ }
@@ -16,5 +16,16 @@ export const config = {
16
16
  // name: "react-component-docs",
17
17
  // },
18
18
  ],
19
- outputDir: "./dist/docs"
19
+ outputDir: './dist/docs',
20
+ propsGlobs: [
21
+ // {
22
+ // include: ['*/@patternfly/react-core/src/**/*.tsx'],
23
+ // exclude: [
24
+ // '/**/examples/**',
25
+ // '/**/__mocks__/**',
26
+ // '/**/__tests__/**',
27
+ // '/**/*.test.tsx',
28
+ // ],
29
+ // },
30
+ ],
20
31
  };