@patternfly/documentation-framework 1.0.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/CHANGELOG.md +3964 -0
- package/README.md +92 -0
- package/app.js +118 -0
- package/assets/android-chrome-36x36.png +0 -0
- package/assets/android-chrome-48x48.png +0 -0
- package/assets/android-chrome-96x96.png +0 -0
- package/assets/favicon-16x16.png +0 -0
- package/assets/favicon-32x32.png +0 -0
- package/assets/favicon-48x48.png +0 -0
- package/assets/favicon.ico +0 -0
- package/assets/manifest.json +29 -0
- package/components/autoLinkHeader/autoLinkHeader.css +22 -0
- package/components/autoLinkHeader/autoLinkHeader.js +41 -0
- package/components/cssVariables/cssSearch.js +32 -0
- package/components/cssVariables/cssVariables.css +15 -0
- package/components/cssVariables/cssVariables.js +233 -0
- package/components/example/example.css +106 -0
- package/components/example/example.js +196 -0
- package/components/example/exampleToolbar.js +208 -0
- package/components/example/missing-thumbnail.jpg +0 -0
- package/components/footer/RHLogo.png +0 -0
- package/components/footer/footer.css +114 -0
- package/components/footer/footer.js +262 -0
- package/components/gdprBanner/gdprBanner.css +14 -0
- package/components/gdprBanner/gdprBanner.js +31 -0
- package/components/index.js +12 -0
- package/components/inlineAlert/inlineAlert.js +19 -0
- package/components/link/link.js +68 -0
- package/components/propsTable/propTypeWithLinks.js +33 -0
- package/components/propsTable/propsTable.js +82 -0
- package/components/sideNav/sideNav.css +17 -0
- package/components/sideNav/sideNav.js +95 -0
- package/components/tableOfContents/tableOfContents.css +77 -0
- package/components/tableOfContents/tableOfContents.js +89 -0
- package/components/topNav/topNav.css +30 -0
- package/components/topNav/topNav.js +24 -0
- package/global.css +7 -0
- package/helpers/asyncComponentFactory.js +41 -0
- package/helpers/capitalize.js +7 -0
- package/helpers/codeTitleTransformer.js +40 -0
- package/helpers/codesandbox.js +204 -0
- package/helpers/copy.js +19 -0
- package/helpers/createHandlebars.js +26 -0
- package/helpers/d3-timer.js +7 -0
- package/helpers/extractExampleHelpers.js +24 -0
- package/helpers/fonts.js +164 -0
- package/helpers/getId.js +6 -0
- package/helpers/getTitle.js +5 -0
- package/helpers/index.js +9 -0
- package/helpers/liveCodeTypes.js +4 -0
- package/helpers/slugger.js +35 -0
- package/helpers/trackEvent.js +17 -0
- package/helpers/xterm-addon-fit.js +3 -0
- package/helpers/xterm.js +8 -0
- package/images/patternfly-logo.svg +14 -0
- package/images/patternfly-orb.svg +28 -0
- package/layouts/index.js +1 -0
- package/layouts/logo.svg +33 -0
- package/layouts/sideNavLayout/sideNavLayout.css +104 -0
- package/layouts/sideNavLayout/sideNavLayout.js +237 -0
- package/package.json +87 -0
- package/pages/404/404.css +16 -0
- package/pages/404/404.svg +26 -0
- package/pages/404/chart.svg +24 -0
- package/pages/404/components.svg +1 -0
- package/pages/404/guidelines.svg +1 -0
- package/pages/404/index.js +136 -0
- package/pages/404/patternfly-flat.svg +1 -0
- package/pages/global-css-variables.md +108 -0
- package/pages/img/component-variable-mapping.png +0 -0
- package/pages/red-hat-font.md +40 -0
- package/routes-client.js +1 -0
- package/routes-generated.js +1 -0
- package/routes.js +155 -0
- package/scripts/cli/build.js +95 -0
- package/scripts/cli/buildClient.js +23 -0
- package/scripts/cli/buildServer.js +24 -0
- package/scripts/cli/cli.js +63 -0
- package/scripts/cli/generate.js +23 -0
- package/scripts/cli/helpers.js +9 -0
- package/scripts/cli/init.js +68 -0
- package/scripts/cli/serve.js +13 -0
- package/scripts/cli/start.js +32 -0
- package/scripts/md/anchor-header.js +69 -0
- package/scripts/md/auto-link-url.js +33 -0
- package/scripts/md/example-captions.js +67 -0
- package/scripts/md/jsxAttributes.js +20 -0
- package/scripts/md/mdx-ast-to-mdx-hast.js +210 -0
- package/scripts/md/mdx-hast-to-jsx.js +233 -0
- package/scripts/md/parseMD.js +308 -0
- package/scripts/md/remove-comments.js +21 -0
- package/scripts/md/styled-tags.js +87 -0
- package/scripts/md/typecheck.js +133 -0
- package/scripts/tsDocgen.js +155 -0
- package/scripts/webpack/getHtmlWebpackPlugins.js +78 -0
- package/scripts/webpack/prerender.js +59 -0
- package/scripts/webpack/webpack.base.config.js +159 -0
- package/scripts/webpack/webpack.client.config.js +146 -0
- package/scripts/webpack/webpack.server.config.js +55 -0
- package/scripts/writeScreenshots.js +66 -0
- package/templates/design-guidelines.js +13 -0
- package/templates/html.ejs +52 -0
- package/templates/mdx.css +308 -0
- package/templates/mdx.js +185 -0
- package/templates/patternfly-docs/content/extensions/extension/design-guidelines/design-guidelines.md +25 -0
- package/templates/patternfly-docs/content/extensions/extension/design-guidelines/img/card-elements.png +0 -0
- package/templates/patternfly-docs/content/extensions/extension/examples/Basic.jsx +4 -0
- package/templates/patternfly-docs/content/extensions/extension/examples/basic.md +25 -0
- package/templates/patternfly-docs/pages/index.js +27 -0
- package/templates/patternfly-docs/patternfly-docs.config.js +6 -0
- package/templates/patternfly-docs/patternfly-docs.css.js +8 -0
- package/templates/patternfly-docs/patternfly-docs.routes.js +12 -0
- package/templates/patternfly-docs/patternfly-docs.source.js +24 -0
- package/templates/sitemap.ejs +10 -0
- package/versions.json +870 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const visit = require('unist-util-visit');
|
|
2
|
+
const remove = require('unist-util-remove');
|
|
3
|
+
const { parseJSXAttributes } = require('./jsxAttributes');
|
|
4
|
+
const { liveCodeTypes } = require('../../helpers/liveCodeTypes');
|
|
5
|
+
|
|
6
|
+
function isExample(node, file) {
|
|
7
|
+
if (node.type !== 'code' || !liveCodeTypes.includes(node.lang)) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
if (node.meta) {
|
|
11
|
+
let properties = {};
|
|
12
|
+
try {
|
|
13
|
+
Object.entries(parseJSXAttributes(`<Component ${node.meta} />`))
|
|
14
|
+
.forEach(([key, val]) => {
|
|
15
|
+
properties[key] = val;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
file.fail(`Error parsing "${node.meta}": ${error}`);
|
|
20
|
+
}
|
|
21
|
+
if (properties.noLive) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function exampleCaptions() {
|
|
30
|
+
return (tree, file) => {
|
|
31
|
+
visit(tree, node => isExample(node, file), (node, _index, parent) => {
|
|
32
|
+
let title = 'Untitled example';
|
|
33
|
+
let caption = [];
|
|
34
|
+
|
|
35
|
+
// Starting from node, look up for h3s
|
|
36
|
+
let startLooking = false;
|
|
37
|
+
for(let i = parent.children.length - 1; i > 0; i--) {
|
|
38
|
+
const child = parent.children[i];
|
|
39
|
+
if (child === node) {
|
|
40
|
+
startLooking = true;
|
|
41
|
+
}
|
|
42
|
+
else if (startLooking) {
|
|
43
|
+
if (
|
|
44
|
+
child.type === 'heading' &&
|
|
45
|
+
child.depth === 3 &&
|
|
46
|
+
child.children &&
|
|
47
|
+
child.children[0].value
|
|
48
|
+
) {
|
|
49
|
+
title = child.children[0].value;
|
|
50
|
+
child.needsDeletion = true;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
caption.unshift(Object.assign({}, child));
|
|
55
|
+
child.needsDeletion = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
node.title = title;
|
|
61
|
+
node.children = caption;
|
|
62
|
+
});
|
|
63
|
+
remove(tree, node => node.needsDeletion);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = exampleCaptions;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const { parse } = require('@patternfly/ast-helpers');
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
parseJSXAttributes: jsx => {
|
|
5
|
+
// Patch until https://github.com/patternfly/patternfly/pull/3324 is in react-docs
|
|
6
|
+
jsx = jsx.replace(/=(true|false)/g, (_, match) => `="${match}"`);
|
|
7
|
+
const properties = {};
|
|
8
|
+
const jsxAttributes = parse(jsx)
|
|
9
|
+
.body[0]
|
|
10
|
+
.expression
|
|
11
|
+
.openingElement
|
|
12
|
+
.attributes;
|
|
13
|
+
|
|
14
|
+
jsxAttributes.forEach(attr => {
|
|
15
|
+
properties[attr.name.name] = attr.value ? attr.value.value : true;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
return properties;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const toHAST = require('mdast-util-to-hast');
|
|
4
|
+
const detab = require('detab');
|
|
5
|
+
const normalize = require('mdurl/encode');
|
|
6
|
+
const all = require('mdast-util-to-hast/lib/all');
|
|
7
|
+
const styleToObject = require('style-to-object');
|
|
8
|
+
const camelCaseCSS = require('camelcase-css');
|
|
9
|
+
const { parseJSXAttributes } = require('./jsxAttributes');
|
|
10
|
+
const { getExampleDeclaration, prettyExampleCode } = require('../../helpers/codesandbox');
|
|
11
|
+
const { liveCodeTypes } = require('../../helpers/liveCodeTypes');
|
|
12
|
+
|
|
13
|
+
let srcCounter = 0;
|
|
14
|
+
|
|
15
|
+
// Adapted from https://github.com/mdx-js/mdx/blob/next/packages/mdx/mdx-ast-to-mdx-hast.js
|
|
16
|
+
function mdxAstToMdxHast({ watchExternal }) {
|
|
17
|
+
return (tree, file) => {
|
|
18
|
+
const srcImports = [];
|
|
19
|
+
|
|
20
|
+
function imageHandler(h, node) {
|
|
21
|
+
const { src, ...rest } = node.props || {};
|
|
22
|
+
const srcImport = `srcImport${srcCounter++}`;
|
|
23
|
+
const url = (node.url || src).replace(/'/g, "\\'");
|
|
24
|
+
const props = {
|
|
25
|
+
src: srcImport,
|
|
26
|
+
alt: node.alt,
|
|
27
|
+
title: node.title,
|
|
28
|
+
isResponsive: /\.(png|jpe?g|webp)$/.test(url),
|
|
29
|
+
...rest
|
|
30
|
+
};
|
|
31
|
+
// Add import statement
|
|
32
|
+
srcImports.push({
|
|
33
|
+
type: 'import',
|
|
34
|
+
value: `import ${srcImport} from '${url}';`
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return h(node, 'img', props);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function mdxExpression(h, node) {
|
|
41
|
+
// Treat JSX <img> tags like commonmark ![]() image tags
|
|
42
|
+
if (node.name === 'img') {
|
|
43
|
+
node.props = node.attributes.reduce((acc, attr) => {
|
|
44
|
+
acc[attr.name] = attr.value;
|
|
45
|
+
return acc;
|
|
46
|
+
}, {});
|
|
47
|
+
if (typeof node.props.src === 'string') {
|
|
48
|
+
return imageHandler(h, node);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
node.attributes.forEach(attr => {
|
|
52
|
+
// style="backgroundcolor: black" -> style={{backgroundColor: "black"}}
|
|
53
|
+
if (attr.name === 'style' && typeof attr.value === 'string') {
|
|
54
|
+
const styleObject = {};
|
|
55
|
+
styleToObject(attr.value, (name, value) => styleObject[camelCaseCSS(name)] = value);
|
|
56
|
+
attr.value = {
|
|
57
|
+
type: 'mdxValueExpression',
|
|
58
|
+
value: JSON.stringify(styleObject)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// class="my-class" -> className="my-class"
|
|
63
|
+
if (attr.name === 'class') {
|
|
64
|
+
attr.name = 'className';
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return Object.assign({}, node, {children: all(h, node)});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const handlers = {
|
|
72
|
+
// `inlineCode` gets passed as `code` by the HAST transform.
|
|
73
|
+
// This makes sure it ends up being `inlineCode`
|
|
74
|
+
inlineCode(h, node) {
|
|
75
|
+
return Object.assign({}, node, {
|
|
76
|
+
type: 'element',
|
|
77
|
+
tagName: 'code',
|
|
78
|
+
properties: {},
|
|
79
|
+
children: [
|
|
80
|
+
{
|
|
81
|
+
type: 'text',
|
|
82
|
+
value: node.value
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
code(h, node) {
|
|
88
|
+
const properties = {
|
|
89
|
+
code: node.value ? detab(node.value + '\n').trim() : '',
|
|
90
|
+
title: node.title
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
if (node.lang) {
|
|
94
|
+
properties.lang = node.lang;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (node.meta) {
|
|
98
|
+
try {
|
|
99
|
+
const dirname = path.dirname(file.history[0]);
|
|
100
|
+
Object.entries(parseJSXAttributes(`<Component ${node.meta} />`))
|
|
101
|
+
.forEach(([key, val]) => {
|
|
102
|
+
if (key === 'file') {
|
|
103
|
+
const filePath = path.join(dirname, val);
|
|
104
|
+
properties.code = fs.readFileSync(filePath, 'utf8');
|
|
105
|
+
watchExternal(filePath);
|
|
106
|
+
} else {
|
|
107
|
+
properties[key] = val;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch(error) {
|
|
112
|
+
file.fail(`Error parsing "${node.meta}": ${error}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (liveCodeTypes.includes(node.lang) && node.lang !== 'html' && !properties.noLive) {
|
|
116
|
+
try {
|
|
117
|
+
const declaration = getExampleDeclaration(properties.code);
|
|
118
|
+
if (
|
|
119
|
+
declaration.type === 'ExpressionStatement' &&
|
|
120
|
+
declaration.expression.type === 'JSXElement'
|
|
121
|
+
) {
|
|
122
|
+
// Lone JSX
|
|
123
|
+
properties.code = prettyExampleCode(node.title, properties.code, declaration);
|
|
124
|
+
}
|
|
125
|
+
else if (
|
|
126
|
+
!declaration ||
|
|
127
|
+
// Allow Example = () => {...}
|
|
128
|
+
declaration.type === 'ExpressionStatement' && !(
|
|
129
|
+
declaration.expression.type === 'AssignmentExpression' &&
|
|
130
|
+
declaration.expression.right.body &&
|
|
131
|
+
declaration.expression.right.body.type === 'BlockStatement'
|
|
132
|
+
)
|
|
133
|
+
) {
|
|
134
|
+
file.message(`Example "${node.title}" must be a class, named block statement, or plain JSX`, node.position);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
file.message(`Example "${node.title}" has invalid JSX: ${err.toString()}`)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return Object.assign({}, node, {
|
|
143
|
+
type: 'element',
|
|
144
|
+
tagName: 'Example',
|
|
145
|
+
properties,
|
|
146
|
+
children: all(h, node)
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
import(h, node) {
|
|
150
|
+
return Object.assign({}, node, {
|
|
151
|
+
type: 'import'
|
|
152
|
+
});
|
|
153
|
+
},
|
|
154
|
+
comment(h, node) {
|
|
155
|
+
return Object.assign({}, node, {
|
|
156
|
+
type: 'comment'
|
|
157
|
+
});
|
|
158
|
+
},
|
|
159
|
+
image(h, node) {
|
|
160
|
+
return imageHandler(h, node);
|
|
161
|
+
},
|
|
162
|
+
link(h, node) {
|
|
163
|
+
const href = normalize(node.href || node.url);
|
|
164
|
+
|
|
165
|
+
const properties = {};
|
|
166
|
+
if (node.title !== null && node.title !== undefined) {
|
|
167
|
+
properties.title = node.title;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (href) {
|
|
171
|
+
properties.to = href;
|
|
172
|
+
|
|
173
|
+
return Object.assign({}, node, {
|
|
174
|
+
type: 'element',
|
|
175
|
+
tagName: 'PatternflyThemeLink',
|
|
176
|
+
properties,
|
|
177
|
+
children: all(h, node)
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
properties.href = href;
|
|
182
|
+
return h(node, 'a', properties, all(h, node));
|
|
183
|
+
},
|
|
184
|
+
mdxBlockElement(h, node) {
|
|
185
|
+
return mdxExpression(h, node);
|
|
186
|
+
},
|
|
187
|
+
mdxSpanElement(h, node) {
|
|
188
|
+
return mdxExpression(h, node);
|
|
189
|
+
},
|
|
190
|
+
mdxBlockExpression(h, node) {
|
|
191
|
+
return Object.assign({}, node, {
|
|
192
|
+
type: 'mdxBlockExpression'
|
|
193
|
+
});
|
|
194
|
+
},
|
|
195
|
+
mdxSpanExpression(h, node) {
|
|
196
|
+
return Object.assign({}, node, {
|
|
197
|
+
type: 'mdxSpanExpression'
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const hast = toHAST(tree, { handlers });
|
|
203
|
+
|
|
204
|
+
hast.children.unshift(...srcImports);
|
|
205
|
+
|
|
206
|
+
return hast;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
module.exports = mdxAstToMdxHast
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const { serializeTags } = require('remark-mdx/lib/serialize/mdx-element');
|
|
4
|
+
const serializeMdxExpression = require('remark-mdx/lib/serialize/mdx-expression');
|
|
5
|
+
const toH = require('hast-to-hyperscript');
|
|
6
|
+
const { toTemplateLiteral } = require('@mdx-js/util');
|
|
7
|
+
const { parse } = require('@patternfly/ast-helpers');
|
|
8
|
+
const { capitalize } = require('../../helpers/capitalize');
|
|
9
|
+
const { slugger } = require('../../helpers/slugger');
|
|
10
|
+
const { liveCodeTypes } = require('../../helpers/liveCodeTypes');
|
|
11
|
+
|
|
12
|
+
// Adapted from https://github.com/mdx-js/mdx/blob/next/packages/mdx/mdx-hast-to-jsx.js
|
|
13
|
+
function toJSX(node, parentNode = {}, options = {}) {
|
|
14
|
+
options.examples = options.examples || {};
|
|
15
|
+
options.indent = options.indent || 2;
|
|
16
|
+
if (node.type === 'root') {
|
|
17
|
+
return serializeRoot(node, options);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (node.type === 'element') {
|
|
21
|
+
return serializeElement(node, options, parentNode);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Wraps text nodes inside template string, so that we don't run into escaping issues.
|
|
25
|
+
if (node.type === 'text') {
|
|
26
|
+
return serializeText(node, options, parentNode);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (node.type === 'mdxBlockExpression' || node.type === 'mdxSpanExpression') {
|
|
30
|
+
return serializeMdxExpression(node);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (node.type === 'mdxBlockElement' || node.type === 'mdxSpanElement') {
|
|
34
|
+
return serializeComponent(node, options, parentNode);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function compile(options = { }) {
|
|
39
|
+
this.Compiler = function(tree) {
|
|
40
|
+
return toJSX(tree, {}, options);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function serializeRoot(node, options) {
|
|
45
|
+
const { getOutPath, getRelPath, getPageData, examples } = options;
|
|
46
|
+
const pageData = {...getPageData()};
|
|
47
|
+
// Save some kb
|
|
48
|
+
delete pageData.toc;
|
|
49
|
+
const exportName = pageData.slug.replace(/[\/-](.)?/g, (_, match) => capitalize(match)) + 'Docs';
|
|
50
|
+
const groups = {
|
|
51
|
+
import: [],
|
|
52
|
+
rest: []
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
for (const child of node.children) {
|
|
56
|
+
let kind = 'rest'
|
|
57
|
+
|
|
58
|
+
if (child.type === 'import') {
|
|
59
|
+
kind = child.type
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
groups[kind].push(child)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const thumbnailFolder = path.join(path.dirname(getOutPath()), pageData.source);
|
|
66
|
+
const thumbnails = fs.existsSync(thumbnailFolder) ? fs.readdirSync(thumbnailFolder) : [];
|
|
67
|
+
const thumbnailImports = thumbnails.map(img =>
|
|
68
|
+
`import srcImport${path.basename(img, '.png').replace(/-/g, '')} from './${pageData.source}/${img}';`)
|
|
69
|
+
|
|
70
|
+
const importStatements = groups.import
|
|
71
|
+
.map(node => node.value)
|
|
72
|
+
.map(imp => imp.replace(/(['"])\./g, (_, match) => `${match}${getRelPath()}${path.posix.sep}\.`))
|
|
73
|
+
.concat(thumbnailImports)
|
|
74
|
+
.join('\n')
|
|
75
|
+
|
|
76
|
+
// https://astexplorer.net/#/gist/9c531dd372dfc57e194c13c2889d31c3/03f2d6e889db1a733c6a079554e8af7784863739
|
|
77
|
+
options.importSpecifiers = parse(importStatements).body
|
|
78
|
+
.map(node => node.specifiers)
|
|
79
|
+
.flat(1)
|
|
80
|
+
.map(spec => spec.local ? spec.local.name : null)
|
|
81
|
+
.filter(Boolean);
|
|
82
|
+
const liveContext = options.importSpecifiers
|
|
83
|
+
.filter(localName => !/srcImport.*/.test(localName)) // Images in MD like [!img](./src)
|
|
84
|
+
.join(',\n ');
|
|
85
|
+
|
|
86
|
+
const childNodes = groups.rest
|
|
87
|
+
.map(childNode => toJSX(childNode, node, options))
|
|
88
|
+
.join('');
|
|
89
|
+
|
|
90
|
+
let res = `import React from 'react';
|
|
91
|
+
import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components';
|
|
92
|
+
${importStatements}
|
|
93
|
+
const pageData = ${JSON.stringify(pageData, null, 2)};
|
|
94
|
+
`;
|
|
95
|
+
if (liveContext) {
|
|
96
|
+
res += `pageData.liveContext = {\n${
|
|
97
|
+
' ' + liveContext
|
|
98
|
+
}\n};\n`
|
|
99
|
+
}
|
|
100
|
+
if (examples) {
|
|
101
|
+
res += `pageData.examples = {\n${
|
|
102
|
+
' ' + Object.entries(examples)
|
|
103
|
+
.map(([key, val]) => `'${key}': ${val}`)
|
|
104
|
+
.join(',\n ')
|
|
105
|
+
}\n};\n`;
|
|
106
|
+
}
|
|
107
|
+
res += `\nconst Component = () => (
|
|
108
|
+
<React.Fragment>${childNodes.replace(/\n\s*\n/g, '\n')}
|
|
109
|
+
</React.Fragment>
|
|
110
|
+
);
|
|
111
|
+
Component.displayName = '${exportName}';
|
|
112
|
+
Component.pageData = pageData;
|
|
113
|
+
|
|
114
|
+
export default Component;\n`;
|
|
115
|
+
|
|
116
|
+
return res;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function serializeElement(node, options) {
|
|
120
|
+
const { indent, examples } = options;
|
|
121
|
+
const { type, props } = toH(
|
|
122
|
+
fakeReactCreateElement,
|
|
123
|
+
Object.assign({}, node, {children: []}),
|
|
124
|
+
{prefix: false}
|
|
125
|
+
);
|
|
126
|
+
const content = serializeChildren(node, {...options});
|
|
127
|
+
|
|
128
|
+
delete props.key;
|
|
129
|
+
|
|
130
|
+
const srcImport = node.properties.src;
|
|
131
|
+
if (type === 'img') {
|
|
132
|
+
delete props.src;
|
|
133
|
+
delete props.isResponsive;
|
|
134
|
+
}
|
|
135
|
+
const spread = Object.keys(props).length === 0
|
|
136
|
+
? null
|
|
137
|
+
: JSON.stringify(props);
|
|
138
|
+
|
|
139
|
+
const indentText = ' '.repeat(indent);
|
|
140
|
+
let res = '\n';
|
|
141
|
+
const isFullscreenExample = type === 'Example'
|
|
142
|
+
&& liveCodeTypes.includes(props.lang)
|
|
143
|
+
&& !props.noLive;
|
|
144
|
+
res += `${indentText}<${type}`;
|
|
145
|
+
if (isFullscreenExample) {
|
|
146
|
+
res += ' {...pageData} {...props}';
|
|
147
|
+
const thumbnailImport = `srcImport${slugger(props.title).replace(/-/g, '')}`;
|
|
148
|
+
if (options.importSpecifiers.includes(thumbnailImport)) {
|
|
149
|
+
res += ` thumbnail={${thumbnailImport}}`;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else if (type === 'img') {
|
|
153
|
+
res += ` src={${srcImport}}`;
|
|
154
|
+
if (node.properties.isResponsive) {
|
|
155
|
+
if (!props.width) {
|
|
156
|
+
res += ` width={${srcImport}.width}`;
|
|
157
|
+
res += ` height={${srcImport}.height}`;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
props.width = props.width.replace('px', '');
|
|
161
|
+
res += ` height={${srcImport}.height * ${props.width} / ${srcImport}.width}`;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (spread) {
|
|
166
|
+
res += ` {...${spread}}`;
|
|
167
|
+
}
|
|
168
|
+
res += `>\n${indentText} ${content}`;
|
|
169
|
+
res += `\n${indentText}</${type}>`;
|
|
170
|
+
if (isFullscreenExample) {
|
|
171
|
+
// Props lets us pass `isFullscreenPreview` to <Example> so it knows to take 100% height
|
|
172
|
+
examples[props.title] = `props => ${res}`;
|
|
173
|
+
res = `\n${indentText}{React.createElement(pageData.examples[${
|
|
174
|
+
JSON.stringify(props.title)
|
|
175
|
+
}])}`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return res;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function serializeComponent(node, options) {
|
|
182
|
+
let content = serializeChildren(node, options);
|
|
183
|
+
const tags = serializeTags(
|
|
184
|
+
Object.assign({}, node, {children: content ? ['!'] : []})
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
if (node.type === 'mdxBlockElement' && content) {
|
|
188
|
+
content = '\n' + content + '\n';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const indentText = ' '.repeat(options.indent);
|
|
192
|
+
return `${indentText}${tags.open}${content}${tags.close || ''}`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function serializeText(node, options, parentNode) {
|
|
196
|
+
// Don't wrap newlines unless specifically instructed to by the flag,
|
|
197
|
+
// to avoid issues like React warnings caused by text nodes in tables.
|
|
198
|
+
const shouldPreserveNewlines = options.preserveNewlines || parentNode.tagName === 'p';
|
|
199
|
+
|
|
200
|
+
if (node.value === '\n' && !shouldPreserveNewlines) {
|
|
201
|
+
return node.value;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return toTemplateLiteral(node.value);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function serializeChildren(node, options) {
|
|
208
|
+
const children = node.children || [];
|
|
209
|
+
const childOptions = Object.assign({}, options, {
|
|
210
|
+
// Tell all children inside <pre> tags to preserve newlines as text nodes
|
|
211
|
+
preserveNewlines: options.preserveNewlines || node.tagName === 'pre',
|
|
212
|
+
indent: options.indent + 1
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const indentText = ' '.repeat(options.indent + 1);
|
|
216
|
+
|
|
217
|
+
return children
|
|
218
|
+
.map(childNode => toJSX(childNode, node, childOptions))
|
|
219
|
+
.join(`\n${indentText}`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// We only do this for the props, so we’re ignoring children.
|
|
223
|
+
function fakeReactCreateElement(name, props) {
|
|
224
|
+
return {
|
|
225
|
+
type: name,
|
|
226
|
+
props: props,
|
|
227
|
+
// Needed for `toH` to think this is React.
|
|
228
|
+
key: null,
|
|
229
|
+
_owner: null
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
module.exports = compile;
|