chore(doclint): support classes inheritance (#935)
This patch: - gives meaningful names to doclint tests - supports classes inheritance in documentation linter. When class A extends class B, all methods of class B are added to documentation of class A. This is a prerequisite for Object Handles: ElementHandle will be extending ObjectHandle. References #382
This commit is contained in:
parent
8bcf550bb6
commit
6c9a99477b
@ -21,6 +21,8 @@ const Documentation = require('./Documentation');
|
|||||||
class JSOutline {
|
class JSOutline {
|
||||||
constructor(text) {
|
constructor(text) {
|
||||||
this.classes = [];
|
this.classes = [];
|
||||||
|
/** @type {!Map<string, string>} */
|
||||||
|
this.inheritance = new Map();
|
||||||
this.errors = [];
|
this.errors = [];
|
||||||
this._eventsByClassName = new Map();
|
this._eventsByClassName = new Map();
|
||||||
this._currentClassName = null;
|
this._currentClassName = null;
|
||||||
@ -44,6 +46,9 @@ class JSOutline {
|
|||||||
_onClassDeclaration(node) {
|
_onClassDeclaration(node) {
|
||||||
this._flushClassIfNeeded();
|
this._flushClassIfNeeded();
|
||||||
this._currentClassName = this._extractText(node.id);
|
this._currentClassName = this._extractText(node.id);
|
||||||
|
const superClass = this._extractText(node.superClass);
|
||||||
|
if (superClass)
|
||||||
|
this.inheritance.set(this._currentClassName, superClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMethodDefinition(node) {
|
_onMethodDefinition(node) {
|
||||||
@ -140,6 +145,31 @@ class JSOutline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Array<!Documentation.Class>} classes
|
||||||
|
* @param {!Map<string, string>} inheritance
|
||||||
|
* @return {!Array<!Documentation.Class>}
|
||||||
|
*/
|
||||||
|
function recreateClassesWithInheritance(classes, inheritance) {
|
||||||
|
const classesByName = new Map(classes.map(cls => [cls.name, cls]));
|
||||||
|
return classes.map(cls => {
|
||||||
|
const membersMap = new Map();
|
||||||
|
for (let wp = cls; wp; wp = classesByName.get(inheritance.get(wp.name))) {
|
||||||
|
for (const member of wp.membersArray) {
|
||||||
|
// Member was overridden.
|
||||||
|
const memberId = member.type + ':' + member.name;
|
||||||
|
if (membersMap.has(memberId))
|
||||||
|
continue;
|
||||||
|
// Do not inherit constructors
|
||||||
|
if (wp !== cls && member.name === 'constructor' && member.type === 'method')
|
||||||
|
continue;
|
||||||
|
membersMap.set(memberId, member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Documentation.Class(cls.name, Array.from(membersMap.values()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {!Array<!Source>} sources
|
* @param {!Array<!Source>} sources
|
||||||
* @return {!Promise<{documentation: !Documentation, errors: !Array<string>}>}
|
* @return {!Promise<{documentation: !Documentation, errors: !Array<string>}>}
|
||||||
@ -147,12 +177,15 @@ class JSOutline {
|
|||||||
module.exports = async function(sources) {
|
module.exports = async function(sources) {
|
||||||
const classes = [];
|
const classes = [];
|
||||||
const errors = [];
|
const errors = [];
|
||||||
|
const inheritance = new Map();
|
||||||
for (const source of sources) {
|
for (const source of sources) {
|
||||||
const outline = new JSOutline(source.text());
|
const outline = new JSOutline(source.text());
|
||||||
classes.push(...outline.classes);
|
classes.push(...outline.classes);
|
||||||
errors.push(...outline.errors);
|
errors.push(...outline.errors);
|
||||||
|
for (const entry of outline.inheritance)
|
||||||
|
inheritance.set(entry[0], entry[1]);
|
||||||
}
|
}
|
||||||
const documentation = new Documentation(classes);
|
const documentation = new Documentation(recreateClassesWithInheritance(classes, inheritance));
|
||||||
return { documentation, errors };
|
return { documentation, errors };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
class A {
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
foo(a) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bar() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
bar(override) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
B.Events = {
|
||||||
|
// Event with the same name as a super class method.
|
||||||
|
foo: 'foo'
|
||||||
|
};
|
@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"classes": [
|
||||||
|
{
|
||||||
|
"name": "A",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"name": "constructor",
|
||||||
|
"type": "method",
|
||||||
|
"hasReturn": false,
|
||||||
|
"async": false,
|
||||||
|
"args": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"type": "method",
|
||||||
|
"hasReturn": false,
|
||||||
|
"async": false,
|
||||||
|
"args": [
|
||||||
|
"a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bar",
|
||||||
|
"type": "method",
|
||||||
|
"hasReturn": false,
|
||||||
|
"async": false,
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "B",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"name": "bar",
|
||||||
|
"type": "method",
|
||||||
|
"hasReturn": false,
|
||||||
|
"async": false,
|
||||||
|
"args": [
|
||||||
|
"override"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"type": "event",
|
||||||
|
"hasReturn": false,
|
||||||
|
"async": false,
|
||||||
|
"args": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"type": "method",
|
||||||
|
"hasReturn": false,
|
||||||
|
"async": false,
|
||||||
|
"args": [
|
||||||
|
"a"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -47,16 +47,17 @@ afterAll(SX(async function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
describe('checkPublicAPI', function() {
|
describe('checkPublicAPI', function() {
|
||||||
it('01-class-errors', SX(testLint));
|
it('diff-classes', SX(testLint));
|
||||||
it('02-method-errors', SX(testLint));
|
it('diff-methods', SX(testLint));
|
||||||
it('03-property-errors', SX(testLint));
|
it('diff-properties', SX(testLint));
|
||||||
it('04-bad-arguments', SX(testLint));
|
it('diff-arguments', SX(testLint));
|
||||||
it('05-event-errors', SX(testLint));
|
it('diff-events', SX(testLint));
|
||||||
it('06-duplicates', SX(testLint));
|
it('check-duplicates', SX(testLint));
|
||||||
it('07-sorting', SX(testLint));
|
it('check-sorting', SX(testLint));
|
||||||
it('08-return', SX(testLint));
|
it('check-returns', SX(testLint));
|
||||||
it('09-js-builder', SX(testJSBuilder));
|
it('js-builder-common', SX(testJSBuilder));
|
||||||
it('10-md-builder', SX(testMDBuilder));
|
it('js-builder-inheritance', SX(testJSBuilder));
|
||||||
|
it('md-builder-common', SX(testMDBuilder));
|
||||||
});
|
});
|
||||||
|
|
||||||
async function testLint() {
|
async function testLint() {
|
||||||
|
Loading…
Reference in New Issue
Block a user