@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.
Files changed (115) hide show
  1. package/CHANGELOG.md +3964 -0
  2. package/README.md +92 -0
  3. package/app.js +118 -0
  4. package/assets/android-chrome-36x36.png +0 -0
  5. package/assets/android-chrome-48x48.png +0 -0
  6. package/assets/android-chrome-96x96.png +0 -0
  7. package/assets/favicon-16x16.png +0 -0
  8. package/assets/favicon-32x32.png +0 -0
  9. package/assets/favicon-48x48.png +0 -0
  10. package/assets/favicon.ico +0 -0
  11. package/assets/manifest.json +29 -0
  12. package/components/autoLinkHeader/autoLinkHeader.css +22 -0
  13. package/components/autoLinkHeader/autoLinkHeader.js +41 -0
  14. package/components/cssVariables/cssSearch.js +32 -0
  15. package/components/cssVariables/cssVariables.css +15 -0
  16. package/components/cssVariables/cssVariables.js +233 -0
  17. package/components/example/example.css +106 -0
  18. package/components/example/example.js +196 -0
  19. package/components/example/exampleToolbar.js +208 -0
  20. package/components/example/missing-thumbnail.jpg +0 -0
  21. package/components/footer/RHLogo.png +0 -0
  22. package/components/footer/footer.css +114 -0
  23. package/components/footer/footer.js +262 -0
  24. package/components/gdprBanner/gdprBanner.css +14 -0
  25. package/components/gdprBanner/gdprBanner.js +31 -0
  26. package/components/index.js +12 -0
  27. package/components/inlineAlert/inlineAlert.js +19 -0
  28. package/components/link/link.js +68 -0
  29. package/components/propsTable/propTypeWithLinks.js +33 -0
  30. package/components/propsTable/propsTable.js +82 -0
  31. package/components/sideNav/sideNav.css +17 -0
  32. package/components/sideNav/sideNav.js +95 -0
  33. package/components/tableOfContents/tableOfContents.css +77 -0
  34. package/components/tableOfContents/tableOfContents.js +89 -0
  35. package/components/topNav/topNav.css +30 -0
  36. package/components/topNav/topNav.js +24 -0
  37. package/global.css +7 -0
  38. package/helpers/asyncComponentFactory.js +41 -0
  39. package/helpers/capitalize.js +7 -0
  40. package/helpers/codeTitleTransformer.js +40 -0
  41. package/helpers/codesandbox.js +204 -0
  42. package/helpers/copy.js +19 -0
  43. package/helpers/createHandlebars.js +26 -0
  44. package/helpers/d3-timer.js +7 -0
  45. package/helpers/extractExampleHelpers.js +24 -0
  46. package/helpers/fonts.js +164 -0
  47. package/helpers/getId.js +6 -0
  48. package/helpers/getTitle.js +5 -0
  49. package/helpers/index.js +9 -0
  50. package/helpers/liveCodeTypes.js +4 -0
  51. package/helpers/slugger.js +35 -0
  52. package/helpers/trackEvent.js +17 -0
  53. package/helpers/xterm-addon-fit.js +3 -0
  54. package/helpers/xterm.js +8 -0
  55. package/images/patternfly-logo.svg +14 -0
  56. package/images/patternfly-orb.svg +28 -0
  57. package/layouts/index.js +1 -0
  58. package/layouts/logo.svg +33 -0
  59. package/layouts/sideNavLayout/sideNavLayout.css +104 -0
  60. package/layouts/sideNavLayout/sideNavLayout.js +237 -0
  61. package/package.json +87 -0
  62. package/pages/404/404.css +16 -0
  63. package/pages/404/404.svg +26 -0
  64. package/pages/404/chart.svg +24 -0
  65. package/pages/404/components.svg +1 -0
  66. package/pages/404/guidelines.svg +1 -0
  67. package/pages/404/index.js +136 -0
  68. package/pages/404/patternfly-flat.svg +1 -0
  69. package/pages/global-css-variables.md +108 -0
  70. package/pages/img/component-variable-mapping.png +0 -0
  71. package/pages/red-hat-font.md +40 -0
  72. package/routes-client.js +1 -0
  73. package/routes-generated.js +1 -0
  74. package/routes.js +155 -0
  75. package/scripts/cli/build.js +95 -0
  76. package/scripts/cli/buildClient.js +23 -0
  77. package/scripts/cli/buildServer.js +24 -0
  78. package/scripts/cli/cli.js +63 -0
  79. package/scripts/cli/generate.js +23 -0
  80. package/scripts/cli/helpers.js +9 -0
  81. package/scripts/cli/init.js +68 -0
  82. package/scripts/cli/serve.js +13 -0
  83. package/scripts/cli/start.js +32 -0
  84. package/scripts/md/anchor-header.js +69 -0
  85. package/scripts/md/auto-link-url.js +33 -0
  86. package/scripts/md/example-captions.js +67 -0
  87. package/scripts/md/jsxAttributes.js +20 -0
  88. package/scripts/md/mdx-ast-to-mdx-hast.js +210 -0
  89. package/scripts/md/mdx-hast-to-jsx.js +233 -0
  90. package/scripts/md/parseMD.js +308 -0
  91. package/scripts/md/remove-comments.js +21 -0
  92. package/scripts/md/styled-tags.js +87 -0
  93. package/scripts/md/typecheck.js +133 -0
  94. package/scripts/tsDocgen.js +155 -0
  95. package/scripts/webpack/getHtmlWebpackPlugins.js +78 -0
  96. package/scripts/webpack/prerender.js +59 -0
  97. package/scripts/webpack/webpack.base.config.js +159 -0
  98. package/scripts/webpack/webpack.client.config.js +146 -0
  99. package/scripts/webpack/webpack.server.config.js +55 -0
  100. package/scripts/writeScreenshots.js +66 -0
  101. package/templates/design-guidelines.js +13 -0
  102. package/templates/html.ejs +52 -0
  103. package/templates/mdx.css +308 -0
  104. package/templates/mdx.js +185 -0
  105. package/templates/patternfly-docs/content/extensions/extension/design-guidelines/design-guidelines.md +25 -0
  106. package/templates/patternfly-docs/content/extensions/extension/design-guidelines/img/card-elements.png +0 -0
  107. package/templates/patternfly-docs/content/extensions/extension/examples/Basic.jsx +4 -0
  108. package/templates/patternfly-docs/content/extensions/extension/examples/basic.md +25 -0
  109. package/templates/patternfly-docs/pages/index.js +27 -0
  110. package/templates/patternfly-docs/patternfly-docs.config.js +6 -0
  111. package/templates/patternfly-docs/patternfly-docs.css.js +8 -0
  112. package/templates/patternfly-docs/patternfly-docs.routes.js +12 -0
  113. package/templates/patternfly-docs/patternfly-docs.source.js +24 -0
  114. package/templates/sitemap.ejs +10 -0
  115. 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;