[doclint] introduce class members
This patch unifies Documentation.Method with Documentation.Property, making it possible to verify sorting order across methods and properties. References #14.
This commit is contained in:
parent
880575c71d
commit
45c20c7dad
49
docs/api.md
49
docs/api.md
@ -9,9 +9,9 @@
|
|||||||
* [browser.close()](#browserclose)
|
* [browser.close()](#browserclose)
|
||||||
* [browser.closePage(page)](#browserclosepagepage)
|
* [browser.closePage(page)](#browserclosepagepage)
|
||||||
* [browser.newPage()](#browsernewpage)
|
* [browser.newPage()](#browsernewpage)
|
||||||
* [browser.version()](#browserversion)
|
|
||||||
* [browser.stderr](#browserstderr)
|
* [browser.stderr](#browserstderr)
|
||||||
* [browser.stdout](#browserstdout)
|
* [browser.stdout](#browserstdout)
|
||||||
|
* [browser.version()](#browserversion)
|
||||||
- [class: Page](#class-page)
|
- [class: Page](#class-page)
|
||||||
* [page.addScriptTag(url)](#pageaddscripttagurl)
|
* [page.addScriptTag(url)](#pageaddscripttagurl)
|
||||||
* [page.click(selector)](#pageclickselector)
|
* [page.click(selector)](#pageclickselector)
|
||||||
@ -56,25 +56,25 @@
|
|||||||
* [frame.url()](#frameurl)
|
* [frame.url()](#frameurl)
|
||||||
* [frame.waitFor(selector)](#framewaitforselector)
|
* [frame.waitFor(selector)](#framewaitforselector)
|
||||||
- [class: Request](#class-request)
|
- [class: Request](#class-request)
|
||||||
* [request.response()](#requestresponse)
|
|
||||||
* [request.headers](#requestheaders)
|
* [request.headers](#requestheaders)
|
||||||
* [request.method](#requestmethod)
|
* [request.method](#requestmethod)
|
||||||
|
* [request.response()](#requestresponse)
|
||||||
* [request.url](#requesturl)
|
* [request.url](#requesturl)
|
||||||
- [class: Response](#class-response)
|
- [class: Response](#class-response)
|
||||||
* [response.headers](#responseheaders)
|
* [response.headers](#responseheaders)
|
||||||
* [response.ok](#responseok)
|
* [response.ok](#responseok)
|
||||||
|
* [response.request()](#responserequest)
|
||||||
* [response.status](#responsestatus)
|
* [response.status](#responsestatus)
|
||||||
* [response.statusText](#responsestatustext)
|
* [response.statusText](#responsestatustext)
|
||||||
* [response.url](#responseurl)
|
* [response.url](#responseurl)
|
||||||
* [response.request()](#responserequest)
|
|
||||||
- [class: InterceptedRequest](#class-interceptedrequest)
|
- [class: InterceptedRequest](#class-interceptedrequest)
|
||||||
* [interceptedRequest.headers](#interceptedrequestheaders)
|
|
||||||
* [interceptedRequest.method](#interceptedrequestmethod)
|
|
||||||
* [interceptedRequest.url](#interceptedrequesturl)
|
|
||||||
* [interceptedRequest.postData](#interceptedrequestpostdata)
|
|
||||||
* [interceptedRequest.abort()](#interceptedrequestabort)
|
* [interceptedRequest.abort()](#interceptedrequestabort)
|
||||||
* [interceptedRequest.continue()](#interceptedrequestcontinue)
|
* [interceptedRequest.continue()](#interceptedrequestcontinue)
|
||||||
|
* [interceptedRequest.headers](#interceptedrequestheaders)
|
||||||
* [interceptedRequest.isHandled()](#interceptedrequestishandled)
|
* [interceptedRequest.isHandled()](#interceptedrequestishandled)
|
||||||
|
* [interceptedRequest.method](#interceptedrequestmethod)
|
||||||
|
* [interceptedRequest.postData](#interceptedrequestpostdata)
|
||||||
|
* [interceptedRequest.url](#interceptedrequesturl)
|
||||||
- [class: Headers](#class-headers)
|
- [class: Headers](#class-headers)
|
||||||
* [headers.append(name, value)](#headersappendname-value)
|
* [headers.append(name, value)](#headersappendname-value)
|
||||||
* [headers.delete(name)](#headersdeletename)
|
* [headers.delete(name)](#headersdeletename)
|
||||||
@ -122,10 +122,6 @@ Closes chromium application with all the pages (if any were opened). The browser
|
|||||||
|
|
||||||
Create a new page in browser and returns a promise which gets resolved with a Page object.
|
Create a new page in browser and returns a promise which gets resolved with a Page object.
|
||||||
|
|
||||||
#### browser.version()
|
|
||||||
- returns: <[Promise]<[string]>>
|
|
||||||
|
|
||||||
|
|
||||||
#### browser.stderr
|
#### browser.stderr
|
||||||
- <[stream.Readable]>
|
- <[stream.Readable]>
|
||||||
|
|
||||||
@ -136,6 +132,9 @@ A Readable Stream that represents the browser process's stderr.
|
|||||||
|
|
||||||
A Readable Stream that represents the browser process's stdout.
|
A Readable Stream that represents the browser process's stdout.
|
||||||
|
|
||||||
|
#### browser.version()
|
||||||
|
- returns: <[Promise]<[string]>>
|
||||||
|
|
||||||
### class: Page
|
### class: Page
|
||||||
|
|
||||||
Page provides interface to interact with a tab in a browser. Pages are created by browser:
|
Page provides interface to interact with a tab in a browser. Pages are created by browser:
|
||||||
@ -339,7 +338,6 @@ Dialog's type, could be one of the `alert`, `beforeunload`, `confirm` and `promp
|
|||||||
|
|
||||||
|
|
||||||
### class: Request
|
### class: Request
|
||||||
#### request.response()
|
|
||||||
#### request.headers
|
#### request.headers
|
||||||
- <[Headers]>
|
- <[Headers]>
|
||||||
|
|
||||||
@ -350,6 +348,9 @@ Contains the associated [Headers] object of the request.
|
|||||||
|
|
||||||
Contains the request's method (GET, POST, etc.)
|
Contains the request's method (GET, POST, etc.)
|
||||||
|
|
||||||
|
|
||||||
|
#### request.response()
|
||||||
|
|
||||||
#### request.url
|
#### request.url
|
||||||
- <[string]>
|
- <[string]>
|
||||||
|
|
||||||
@ -367,6 +368,7 @@ Contains the [Headers] object associated with the response.
|
|||||||
|
|
||||||
Contains a boolean stating whether the response was successful (status in the range 200-299) or not.
|
Contains a boolean stating whether the response was successful (status in the range 200-299) or not.
|
||||||
|
|
||||||
|
#### response.request()
|
||||||
#### response.status
|
#### response.status
|
||||||
- <[number]>
|
- <[number]>
|
||||||
|
|
||||||
@ -378,39 +380,44 @@ Contains the status code of the response (e.g., 200 for a success).
|
|||||||
|
|
||||||
Contains the status message corresponding to the status code (e.g., OK for 200).
|
Contains the status message corresponding to the status code (e.g., OK for 200).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### response.url
|
#### response.url
|
||||||
- <[string]>
|
- <[string]>
|
||||||
|
|
||||||
Contains the URL of the response.
|
Contains the URL of the response.
|
||||||
|
|
||||||
#### response.request()
|
|
||||||
|
|
||||||
### class: InterceptedRequest
|
### class: InterceptedRequest
|
||||||
|
|
||||||
|
#### interceptedRequest.abort()
|
||||||
|
#### interceptedRequest.continue()
|
||||||
#### interceptedRequest.headers
|
#### interceptedRequest.headers
|
||||||
- <[Headers]>
|
- <[Headers]>
|
||||||
|
|
||||||
Contains the [Headers] object associated with the request.
|
Contains the [Headers] object associated with the request.
|
||||||
|
|
||||||
|
#### interceptedRequest.isHandled()
|
||||||
|
|
||||||
#### interceptedRequest.method
|
#### interceptedRequest.method
|
||||||
- <[string]>
|
- <[string]>
|
||||||
|
|
||||||
Contains the request's method (GET, POST, etc.)
|
Contains the request's method (GET, POST, etc.)
|
||||||
|
|
||||||
#### interceptedRequest.url
|
|
||||||
- <[string]>
|
|
||||||
|
|
||||||
Contains the URL of the request.
|
|
||||||
|
|
||||||
|
|
||||||
#### interceptedRequest.postData
|
#### interceptedRequest.postData
|
||||||
- <[string]>
|
- <[string]>
|
||||||
|
|
||||||
In case of a `POST` request, contains `POST` data.
|
In case of a `POST` request, contains `POST` data.
|
||||||
|
|
||||||
#### interceptedRequest.abort()
|
#### interceptedRequest.url
|
||||||
#### interceptedRequest.continue()
|
- <[string]>
|
||||||
#### interceptedRequest.isHandled()
|
|
||||||
|
Contains the URL of the request.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### class: Headers
|
### class: Headers
|
||||||
#### headers.append(name, value)
|
#### headers.append(name, value)
|
||||||
|
@ -74,15 +74,15 @@ class Documentation {
|
|||||||
if (classes.has(cls.name))
|
if (classes.has(cls.name))
|
||||||
errors.push(`Duplicate declaration of class ${cls.name}`);
|
errors.push(`Duplicate declaration of class ${cls.name}`);
|
||||||
classes.add(cls.name);
|
classes.add(cls.name);
|
||||||
let methods = new Set();
|
let members = new Set();
|
||||||
for (let method of cls.methodsArray) {
|
for (let member of cls.membersArray) {
|
||||||
if (methods.has(method.name))
|
if (members.has(member.name))
|
||||||
errors.push(`Duplicate declaration of method ${cls.name}.${method.name}()`);
|
errors.push(`Duplicate declaration of method ${cls.name}.${member.name}()`);
|
||||||
methods.add(method.name);
|
members.add(member.name);
|
||||||
let args = new Set();
|
let args = new Set();
|
||||||
for (let arg of method.argsArray) {
|
for (let arg of member.argsArray) {
|
||||||
if (args.has(arg.name))
|
if (args.has(arg.name))
|
||||||
errors.push(`Duplicate declaration of argument ${cls.name}.${method.name} "${arg.name}"`);
|
errors.push(`Duplicate declaration of argument ${cls.name}.${member.name} "${arg.name}"`);
|
||||||
args.add(arg.name);
|
args.add(arg.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,32 +94,55 @@ class Documentation {
|
|||||||
Documentation.Class = class {
|
Documentation.Class = class {
|
||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @param {!Array<!Documentation.Method>} methodsArray
|
* @param {!Array<!Documentation.Member>} membersArray
|
||||||
* @param {!Array<string>} propertiesArray
|
|
||||||
*/
|
*/
|
||||||
constructor(name, methodsArray, propertiesArray) {
|
constructor(name, membersArray) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.methodsArray = methodsArray;
|
this.membersArray = membersArray;
|
||||||
|
this.members = new Map();
|
||||||
|
this.properties = new Map();
|
||||||
this.methods = new Map();
|
this.methods = new Map();
|
||||||
for (let method of methodsArray)
|
for (let member of membersArray) {
|
||||||
this.methods.set(method.name, method);
|
this.members.set(member.name, member);
|
||||||
this.propertiesArray = propertiesArray;
|
if (member.type === 'method')
|
||||||
this.properties = new Set(propertiesArray);
|
this.methods.set(member.name, member);
|
||||||
|
else if (member.type === 'property')
|
||||||
|
this.properties.set(member.name, member);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Documentation.Method = class {
|
Documentation.Member = class {
|
||||||
/**
|
/**
|
||||||
|
* @param {string} type
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @param {!Array<!Documentation.Argument>} argsArray
|
* @param {!Array<!Documentation.Argument>} argsArray
|
||||||
*/
|
*/
|
||||||
constructor(name, argsArray) {
|
constructor(type, name, argsArray) {
|
||||||
|
this.type = type;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.argsArray = argsArray;
|
this.argsArray = argsArray;
|
||||||
this.args = new Map();
|
this.args = new Map();
|
||||||
for (let arg of argsArray)
|
for (let arg of argsArray)
|
||||||
this.args.set(arg.name, arg);
|
this.args.set(arg.name, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
* @param {!Array<!Documentation.Argument>} argsArray
|
||||||
|
* @return {!Documentation.Member}
|
||||||
|
*/
|
||||||
|
static createMethod(name, argsArray) {
|
||||||
|
return new Documentation.Member('method', name, argsArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
* @return {!Documentation.Member}
|
||||||
|
*/
|
||||||
|
static createProperty(name) {
|
||||||
|
return new Documentation.Member('property', name, []);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Documentation.Argument = class {
|
Documentation.Argument = class {
|
||||||
|
@ -8,8 +8,7 @@ class JSOutline {
|
|||||||
constructor(text) {
|
constructor(text) {
|
||||||
this.classes = [];
|
this.classes = [];
|
||||||
this._currentClassName = null;
|
this._currentClassName = null;
|
||||||
this._currentClassMethods = [];
|
this._currentClassMembers = [];
|
||||||
this._currentClassProperties = [];
|
|
||||||
|
|
||||||
this._text = text;
|
this._text = text;
|
||||||
let ast = esprima.parseScript(this._text, {loc: true, range: true});
|
let ast = esprima.parseScript(this._text, {loc: true, range: true});
|
||||||
@ -35,8 +34,8 @@ class JSOutline {
|
|||||||
for (let param of node.value.params)
|
for (let param of node.value.params)
|
||||||
args.push(new Documentation.Argument(this._extractText(param)));
|
args.push(new Documentation.Argument(this._extractText(param)));
|
||||||
let methodName = this._extractText(node.key);
|
let methodName = this._extractText(node.key);
|
||||||
let method = new Documentation.Method(methodName, args);
|
let method = Documentation.Member.createMethod(methodName, args);
|
||||||
this._currentClassMethods.push(method);
|
this._currentClassMembers.push(method);
|
||||||
// Extract properties from constructor.
|
// Extract properties from constructor.
|
||||||
if (node.kind === 'constructor') {
|
if (node.kind === 'constructor') {
|
||||||
let walker = new ESTreeWalker(node => {
|
let walker = new ESTreeWalker(node => {
|
||||||
@ -46,7 +45,7 @@ class JSOutline {
|
|||||||
if (node.type === 'MemberExpression' && node.object &&
|
if (node.type === 'MemberExpression' && node.object &&
|
||||||
node.object.type === 'ThisExpression' && node.property &&
|
node.object.type === 'ThisExpression' && node.property &&
|
||||||
node.property.type === 'Identifier')
|
node.property.type === 'Identifier')
|
||||||
this._currentClassProperties.push(node.property.name);
|
this._currentClassMembers.push(Documentation.Member.createProperty(node.property.name));
|
||||||
});
|
});
|
||||||
walker.walk(node);
|
walker.walk(node);
|
||||||
}
|
}
|
||||||
@ -60,11 +59,10 @@ class JSOutline {
|
|||||||
_flushClassIfNeeded() {
|
_flushClassIfNeeded() {
|
||||||
if (this._currentClassName === null)
|
if (this._currentClassName === null)
|
||||||
return;
|
return;
|
||||||
let jsClass = new Documentation.Class(this._currentClassName, this._currentClassMethods, this._currentClassProperties);
|
let jsClass = new Documentation.Class(this._currentClassName, this._currentClassMembers);
|
||||||
this.classes.push(jsClass);
|
this.classes.push(jsClass);
|
||||||
this._currentClassName = null;
|
this._currentClassName = null;
|
||||||
this._currentClassMethods = [];
|
this._currentClassMembers = [];
|
||||||
this._currentClassProperties = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_extractText(node) {
|
_extractText(node) {
|
||||||
|
@ -53,8 +53,7 @@ class MDOutline {
|
|||||||
const methodRegex = /^(\w+)\.(\w+)\((.*)\)$/;
|
const methodRegex = /^(\w+)\.(\w+)\((.*)\)$/;
|
||||||
const propertyRegex = /^(\w+)\.(\w+)$/;
|
const propertyRegex = /^(\w+)\.(\w+)$/;
|
||||||
let currentClassName = null;
|
let currentClassName = null;
|
||||||
let currentClassMethods = [];
|
let currentClassMembers = [];
|
||||||
let currentClassProperties = [];
|
|
||||||
for (const cls of classes) {
|
for (const cls of classes) {
|
||||||
let match = cls.name.match(classHeading);
|
let match = cls.name.match(classHeading);
|
||||||
if (!match)
|
if (!match)
|
||||||
@ -84,8 +83,8 @@ class MDOutline {
|
|||||||
if (parameters !== member.args.join(', '))
|
if (parameters !== member.args.join(', '))
|
||||||
this.errors.push(`Heading arguments for "${member.name}" do not match described ones, i.e. "${parameters}" != "${member.args.join(', ')}"`);
|
this.errors.push(`Heading arguments for "${member.name}" do not match described ones, i.e. "${parameters}" != "${member.args.join(', ')}"`);
|
||||||
let args = member.args.map(arg => new Documentation.Argument(arg));
|
let args = member.args.map(arg => new Documentation.Argument(arg));
|
||||||
let method = new Documentation.Method(methodName, args);
|
let method = Documentation.Member.createMethod(methodName, args);
|
||||||
currentClassMethods.push(method);
|
currentClassMembers.push(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleProperty(member, className, propertyName) {
|
function handleProperty(member, className, propertyName) {
|
||||||
@ -93,16 +92,15 @@ class MDOutline {
|
|||||||
this.errors.push(`Failed to process header as property: ${member.name}`);
|
this.errors.push(`Failed to process header as property: ${member.name}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentClassProperties.push(propertyName);
|
currentClassMembers.push(Documentation.Member.createProperty(propertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
function flushClassIfNeeded() {
|
function flushClassIfNeeded() {
|
||||||
if (currentClassName === null)
|
if (currentClassName === null)
|
||||||
return;
|
return;
|
||||||
this.classes.push(new Documentation.Class(currentClassName, currentClassMethods, currentClassProperties));
|
this.classes.push(new Documentation.Class(currentClassName, currentClassMembers));
|
||||||
currentClassName = null;
|
currentClassName = null;
|
||||||
currentClassMethods = [];
|
currentClassMembers = [];
|
||||||
currentClassProperties = [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,17 +63,19 @@ function lintMarkdown(doc) {
|
|||||||
const errors = [];
|
const errors = [];
|
||||||
// Methods should be sorted alphabetically.
|
// Methods should be sorted alphabetically.
|
||||||
for (let cls of doc.classesArray) {
|
for (let cls of doc.classesArray) {
|
||||||
for (let i = 0; i < cls.methodsArray.length - 1; ++i) {
|
for (let i = 0; i < cls.membersArray.length - 1; ++i) {
|
||||||
// Constructor always goes first.
|
// Constructor always goes first.
|
||||||
if (cls.methodsArray[i].name === 'constructor') {
|
if (cls.membersArray[i].name === 'constructor') {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
errors.push(`Constructor of ${cls.name} should go before other methods`);
|
errors.push(`Constructor of ${cls.name} should go before other methods`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let method1 = cls.methodsArray[i];
|
let member1 = cls.membersArray[i];
|
||||||
let method2 = cls.methodsArray[i + 1];
|
let member2 = cls.membersArray[i + 1];
|
||||||
if (method1.name > method2.name)
|
if (member1.name > member2.name) {
|
||||||
errors.push(`${cls.name}.${method1.name} breaks alphabetic methods sorting inside class ${cls.name}`);
|
let memberName = `${cls.name}.${member1.name}` + (member1.type === 'method' ? '()' : '');
|
||||||
|
errors.push(`${memberName} breaks alphabetic member sorting inside class ${cls.name}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return errors;
|
return errors;
|
||||||
@ -89,13 +91,12 @@ function filterJSDocumentation(jsDocumentation) {
|
|||||||
for (let cls of jsDocumentation.classesArray) {
|
for (let cls of jsDocumentation.classesArray) {
|
||||||
if (EXCLUDE_CLASSES.has(cls.name))
|
if (EXCLUDE_CLASSES.has(cls.name))
|
||||||
continue;
|
continue;
|
||||||
let methods = cls.methodsArray.filter(method => {
|
let members = cls.membersArray.filter(member => {
|
||||||
if (method.name.startsWith('_'))
|
if (member.name.startsWith('_'))
|
||||||
return false;
|
return false;
|
||||||
return !EXCLUDE_METHODS.has(`${cls.name}.${method.name}`);
|
return !EXCLUDE_METHODS.has(`${cls.name}.${member.name}`);
|
||||||
});
|
});
|
||||||
let properties = cls.propertiesArray.filter(property => !property.startsWith('_'));
|
classes.push(new Documentation.Class(cls.name, members));
|
||||||
classes.push(new Documentation.Class(cls.name, methods, properties));
|
|
||||||
}
|
}
|
||||||
return new Documentation(classes);
|
return new Documentation(classes);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#### new Foo()
|
#### new Foo()
|
||||||
|
|
||||||
|
#### foo.ddd
|
||||||
|
|
||||||
#### foo.ccc()
|
#### foo.ccc()
|
||||||
|
|
||||||
#### foo.bbb()
|
#### foo.bbb()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
class Foo {
|
class Foo {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this.ddd = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
aaa() {}
|
aaa() {}
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
[MarkDown] Constructor of Foo should go before other methods
|
[MarkDown] Constructor of Foo should go before other methods
|
||||||
[MarkDown] Foo.ccc breaks alphabetic methods sorting inside class Foo
|
[MarkDown] Foo.ddd breaks alphabetic member sorting inside class Foo
|
||||||
|
[MarkDown] Foo.ccc() breaks alphabetic member sorting inside class Foo
|
Loading…
Reference in New Issue
Block a user