puppeteer/test/doclint/JSOutline.js
Andrey Lushnikov 62cacbe5f5 Implement documentation linter (#47)
This patch implements documentation linter, which leaves under `test/doclint`
folder.

The documentation linter works like this:
1. Parse javascript source code with esprima and construct a "documentation" out of source code
2. Generate HTML out of `api.md` and traverse the HTML with puppeteer.
3. Make sure javascript aligns nicely with HTML

The documentation linter adds the following commands:
- `yarn doc` - to test that documentation covers all the relevant apis
- `yarn generate-toc` - to update the table-of-contents for the `api.md`
2017-07-07 19:36:45 +03:00

53 lines
1.5 KiB
JavaScript

const esprima = require('esprima');
const ESTreeWalker = require('../../third_party/chromium/ESTreeWalker');
const Documentation = require('./Documentation');
class JSOutline {
constructor(text) {
this.classes = [];
this._currentClassName = null;
this._currentClassMethods = [];
this._text = text;
let ast = esprima.parseScript(this._text, {loc: true, range: true});
let walker = new ESTreeWalker(node => {
if (node.type === 'ClassDeclaration')
this._onClassDeclaration(node);
else if (node.type === 'MethodDefinition')
this._onMethodDefinition(node);
});
walker.walk(ast);
this._flushClassIfNeeded();
}
_onClassDeclaration(node) {
this._flushClassIfNeeded();
this._currentClassName = this._getIdentifier(node.id);
}
_onMethodDefinition(node) {
console.assert(this._currentClassName !== null);
let methodName = this._getIdentifier(node.key);
let method = new Documentation.Method(methodName);
this._currentClassMethods.push(method);
}
_flushClassIfNeeded() {
if (this._currentClassName === null)
return;
let jsClass = new Documentation.Class(this._currentClassName, this._currentClassMethods);
this.classes.push(jsClass);
this._currentClassName = null;
this._currentClassMethods = [];
}
_getIdentifier(node) {
if (!node)
return null;
let text = this._text.substring(node.range[0], node.range[1]).trim();
return /^[$A-Z_][0-9A-Z_$]*$/i.test(text) ? text : null;
}
}
module.exports = JSOutline;