53 lines
1.5 KiB
JavaScript
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;
|