@mapbox/react-native-mapbox-gl
Version:
A Mapbox GL react native module for creating custom maps
154 lines (125 loc) • 4.33 kB
JavaScript
const docgen = require('react-docgen');
const dir = require('node-dir');
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
const JSDocNodeTree = require('./JSDocNodeTree');
const COMPONENT_PATH = path.join(__dirname, '..', '..', 'javascript', 'components');
const MODULES_PATH = path.join(__dirname, '..', '..', 'javascript', 'modules');
const OUTPUT_PATH = path.join(__dirname, '..', '..', 'docs', 'docs.json');
const IGNORE_FILES = ['AbstractLayer'];
class DocJSONBuilder {
constructor (styledLayers) {
this._styledLayers = {};
for (let styleLayer of styledLayers) {
const ComponentName = pascelCase(styleLayer.name);
this._styledLayers[ComponentName + (ComponentName === 'Light' ? '' : 'Layer')] = styleLayer;
}
}
get options () {
return {
match: /.js$/,
shortName: true,
};
}
isPrivateMethod (methodName = '') {
return !methodName || methodName.charAt(0) === '_';
}
postprocess (component, name) {
// Remove all private methods and parse examples from docblock
if (!Array.isArray(component.methods)) {
return;
}
component.name = name;
// styles
if (this._styledLayers[name] && this._styledLayers[name].properties) {
component.styles = [];
for (let prop of this._styledLayers[name].properties) {
component.styles.push({
name: prop.name,
type: prop.type,
description: prop.doc.description,
requires: prop.doc.requires,
disabledBy: prop.doc.disabledBy,
});
}
}
// props
component.props = Object.keys(component.props).map((propName) => {
const propMeta = component.props[propName];
return {
name: propName || 'FIX ME NO NAME',
required: propMeta.required || false,
type: propMeta.type.name || 'FIX ME UNKNOWN TYPE',
default: !propMeta.defaultValue ? 'none' : propMeta.defaultValue.value.replace(/\n/g, ''),
description: propMeta.description || 'FIX ME NO DESCRIPTION',
};
});
// methods
const privateMethods = [];
for (let method of component.methods) {
if (this.isPrivateMethod(method.name)) {
privateMethods.push(method.name);
continue;
}
if (method.docblock) {
const examples = method.docblock.split('@').filter((block) => block.startsWith('example'));
method.examples = examples.map((example) => example.substring('example'.length));
}
}
component.methods = component.methods.filter((method) => !privateMethods.includes(method.name));
}
generateReactComponentsTask (results, filePath) {
return new Promise((resolve, reject) => {
dir.readFiles(filePath, this.options, (err, content, fileName, next) => {
if (err) {
return reject(err);
}
fileName = fileName.replace('.js', '');
if (IGNORE_FILES.includes(fileName)) {
next();
return;
}
results[fileName] = docgen.parse(content);
this.postprocess(results[fileName], fileName);
next();
}, () => resolve());
});
}
generateModulesTask (results, filePath) {
return new Promise((resolve, reject) => {
exec(`documentation build ${MODULES_PATH} -f json`, (err, stdout, stderr) => {
if (err || stderr) {
reject(err || stderr);
return;
}
const modules = JSON.parse(stdout);
for (let module of modules) {
const node = new JSDocNodeTree(module);
const name = `${module.name.charAt(0).toLowerCase()}${module.name.substring(1)}`;
results[name] = {
name: name,
description: node.getText(),
props: [],
styles: [],
methods: node.getMethods(),
};
}
resolve();
});
});
}
generate () {
this.generateModulesTask({}, MODULES_PATH);
let results = {};
const tasks = [
this.generateReactComponentsTask(results, COMPONENT_PATH),
this.generateModulesTask(results, MODULES_PATH),
];
return Promise.all(tasks).then(() => {
fs.writeFileSync(OUTPUT_PATH, JSON.stringify(results, null, 2));
return true;
});
}
}
module.exports = DocJSONBuilder;