puppeteer/test/doclint/MDOutline.js
Andrey Lushnikov a69bed30d9 Simplify documentation linter
This patch simplifies documentation linter, basically
addressing the comments from #47.

References #14.
2017-07-07 11:15:29 -07:00

82 lines
2.5 KiB
JavaScript

const Documentation = require('./Documentation');
const commonmark = require('commonmark');
const Browser = require('../../lib/Browser');
class MDOutline {
/**
* @return {!MDOutline}
*/
static async create(text) {
// Render markdown as HTML.
const reader = new commonmark.Parser();
const parsed = reader.parse(text);
const writer = new commonmark.HtmlRenderer();
const html = writer.render(parsed);
// Extract headings.
const browser = new Browser({args: ['--no-sandbox']});
const page = await browser.newPage();
await page.setContent(html);
const headings = await page.evaluate(() => {
let headings = {};
let methods = [];
for (let header of document.body.querySelectorAll('h3,h4')) {
if (header.matches('h3')) {
methods = [];
headings[header.textContent] = methods;
} else {
methods.push(header.textContent);
}
}
return headings;
});
await browser.close();
return new MDOutline(headings);
}
constructor(headings) {
this.classes = [];
const classHeading = /^class: (\w+)$/;
const constructorRegex = /^new (\w+)\((.*)\)$/;
const methodRegex = /^(\w+)\.(\w+)\((.*)\)$/;
let currentClassName = null;
let currentClassMethods = [];
for (const heading of Object.keys(headings)) {
let match = heading.match(classHeading);
currentClassName = match[1];
for (const title of headings[heading]) {
let className = null;
let methodName = null;
if (constructorRegex.test(title)) {
let match = title.match(constructorRegex);
className = match[1];
methodName = 'constructor';
} else if (methodRegex.test(title)) {
let match = title.match(methodRegex);
className = match[1];
methodName = match[2];
}
if (!currentClassName || !className || !methodName || className.toLowerCase() !== currentClassName.toLowerCase()) {
console.warn('failed to process header as method: ' + heading);
continue;
}
let method = new Documentation.Method(methodName);
currentClassMethods.push(method);
}
flushClassIfNeeded.call(this);
}
function flushClassIfNeeded() {
if (currentClassName === null)
return;
this.classes.push(new Documentation.Class(currentClassName, currentClassMethods));
currentClassName = null;
currentClassMethods = [];
}
}
}
module.exports = MDOutline;