UNPKG

@mapbox/react-native-mapbox-gl

Version:

A Mapbox GL react native module for creating custom maps

154 lines (125 loc) 4.33 kB
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;