Files
flipper/website/generate-uidocs.js
John Knox 5f1a0548f5 Migrate website to Docusaurus 2
Summary:
Docusaurus 2 is quite a lot more powerful than docu 1 it turns out.
This should convert the website fully.

* [done] Go through migration guide https://v2.docusaurus.io/docs/migrating-from-v1-to-v2
* [done] Convert landing page html
* [done] Convert all images to img tags
* [done] Convert all .md files to .mdx
* [done] Make sure ui-doc generation and including still works
* [done] Scan every page visually for sanity check
* [done] Make sure footer still works
* [done] Make sure search still works
* [done] Change all links/ to links/index
* [done] Change all links.md to links
* [done] Add some custom css to make the navbar look like the old one and darken the footer.

Reviewed By: passy

Differential Revision: D21158717

fbshipit-source-id: 5f45b711b1b6fd5ece4c5c15c55635c7ebbfb568
2020-04-27 04:05:01 -07:00

123 lines
3.4 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
const reactDocs = require('react-docgen');
const glob = require('glob');
const fs = require('fs');
const babylon = require('@babel/parser');
const docblockParser = require('docblock-parser');
const HEADER = `---
id: ui-components
title: UI Components
---
Flipper has a lot of built in React components to build UIs. You can import them directly using e.g. \`import {Button} from 'flipper'\`.`;
const TARGET = __dirname + '/../docs/extending/ui-components.mdx';
glob(__dirname + '/../desktop/app/src/ui/components/**/*.tsx', (err, files) => {
const content = files
.map(f => [f, fs.readFileSync(f)])
.map(([name, file]) => {
try {
const doc = reactDocs.parse(file, null, null, {filename: name});
console.log(`${name}`);
return doc;
} catch (e) {
const doc = parseHOC(name, file);
if (doc) {
console.log(`✅ HOC: ${name}`);
return doc;
} else {
console.error(`${name}: ${e.message}`);
return null;
}
}
})
.filter(Boolean)
.map(generateMarkdown)
.reduce((acc, cv) => acc + cv, '');
fs.writeFileSync(TARGET, HEADER + content);
});
// HOC are not supported by react-docgen. This means, styled-components will not
// work. This is why we implement our own parser to information from these HOCs.
function parseHOC(name, file) {
try {
const ast = babylon.parse(file.toString(), {
sourceType: 'module',
plugins: ['typescript', 'objectRestSpread', 'classProperties'],
});
// find the default export from the file
const exportDeclaration = ast.program.body.find(
node => node.type === 'ExportDefaultDeclaration',
);
if (exportDeclaration) {
// find doc comment right before the export
const comment = ast.comments.find(
c => c.end + 1 === exportDeclaration.start,
);
if (comment) {
return {
// use the file's name as name for the component
displayName: name
.split('/')
.reverse()[0]
.replace(/\.js$/, ''),
description: docblockParser.parse(comment.value).text,
};
}
}
} catch (e) {}
return null;
}
function generateMarkdown(component) {
let props;
if (component.props && Object.keys(component.props).length > 0) {
props = '| Property | Type | Description |\n';
props += '|---------|------|-------------|\n';
Object.keys(component.props).forEach(prop => {
let {tsType, description} = component.props[prop];
let type = '';
if (tsType) {
if (tsType.nullable) {
type += '?';
}
type +=
tsType.name === 'signature' ||
tsType.name === 'union' ||
tsType.name === 'Array'
? tsType.raw
: tsType.name;
}
// escape pipes and new lines because they will break tables
type = type.replace(/\n/g, ' ').replace(/\|/g, '⎮');
description = description
? description.replace(/\n/g, ' ').replace(/\|/g, '⎮')
: '';
props += `| \`${prop}\` | \`${type}\` | ${description} |\n`;
});
}
return `
## ${component.displayName}
${component.description || ''}
${props || ''}
`;
}