mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
[doclint] Move doclint under utils/
This patch: - moves doclint under utils/ folder - adds tests to verify doclint basic functionality This patch also drops the jasmine as a spec runner for the doclint checks. It turned out it's hard to customize jasmine's behavior, so instead this patch implements a dummy spec runner. The dummy spec runner allows us: - to format messages however we want (the custom jasmine reporter would also allow us to do this) - to avoid `beforeAll` functions which pollute global to pass initialized variables over to specs References #14
This commit is contained in:
93
utils/doclint/JSBuilder.js
Normal file
93
utils/doclint/JSBuilder.js
Normal file
@@ -0,0 +1,93 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
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._currentClassProperties = [];
|
||||
|
||||
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._extractText(node.id);
|
||||
}
|
||||
|
||||
_onMethodDefinition(node) {
|
||||
console.assert(this._currentClassName !== null);
|
||||
console.assert(node.value.type === 'FunctionExpression');
|
||||
const args = [];
|
||||
for (let param of node.value.params)
|
||||
args.push(new Documentation.Argument(this._extractText(param)));
|
||||
let methodName = this._extractText(node.key);
|
||||
let method = new Documentation.Method(methodName, args);
|
||||
this._currentClassMethods.push(method);
|
||||
// Extract properties from constructor.
|
||||
if (node.kind === 'constructor') {
|
||||
let walker = new ESTreeWalker(node => {
|
||||
if (node.type !== 'AssignmentExpression')
|
||||
return;
|
||||
node = node.left;
|
||||
if (node.type === 'MemberExpression' && node.object &&
|
||||
node.object.type === 'ThisExpression' && node.property &&
|
||||
node.property.type === 'Identifier')
|
||||
this._currentClassProperties.push(node.property.name);
|
||||
});
|
||||
walker.walk(node);
|
||||
}
|
||||
return ESTreeWalker.SkipSubtree;
|
||||
}
|
||||
|
||||
_onMemberExpression(node) {
|
||||
|
||||
}
|
||||
|
||||
_flushClassIfNeeded() {
|
||||
if (this._currentClassName === null)
|
||||
return;
|
||||
let jsClass = new Documentation.Class(this._currentClassName, this._currentClassMethods, this._currentClassProperties);
|
||||
this.classes.push(jsClass);
|
||||
this._currentClassName = null;
|
||||
this._currentClassMethods = [];
|
||||
this._currentClassProperties = [];
|
||||
}
|
||||
|
||||
_extractText(node) {
|
||||
if (!node)
|
||||
return null;
|
||||
let text = this._text.substring(node.range[0], node.range[1]).trim();
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array<string>} dirPath
|
||||
* @return {!Promise<!Documentation>}
|
||||
*/
|
||||
module.exports = async function(dirPath) {
|
||||
let filePaths = fs.readdirSync(dirPath)
|
||||
.filter(fileName => fileName.endsWith('.js'))
|
||||
.map(fileName => path.join(dirPath, fileName));
|
||||
let classes = [];
|
||||
for (let filePath of filePaths) {
|
||||
let outline = new JSOutline(fs.readFileSync(filePath, 'utf8'));
|
||||
classes.push(...outline.classes);
|
||||
}
|
||||
return new Documentation(classes);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user