Skip to content

Commit

Permalink
doc: further align docs w/ playwright.dev (3) (#4884)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman committed Jan 5, 2021
1 parent 5215add commit 80f8a0f
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 195 deletions.
4 changes: 2 additions & 2 deletions docs/out/api/class-accessibility.md
Expand Up @@ -36,8 +36,8 @@ Most of the accessibility tree gets filtered out when converting from Blink AX T
- `readonly` <[boolean]> Whether the node is read only, if applicable.
- `required` <[boolean]> Whether the node is required, if applicable.
- `selected` <[boolean]> Whether the node is selected in its parent node, if applicable.
- `checked` <boolean|"mixed"> Whether the checkbox is checked, or "mixed", if applicable.
- `pressed` <boolean|"mixed"> Whether the toggle button is checked, or "mixed", if applicable.
- `checked` <[boolean]|"mixed"> Whether the checkbox is checked, or "mixed", if applicable.
- `pressed` <[boolean]|"mixed"> Whether the toggle button is checked, or "mixed", if applicable.
- `level` <[number]> The level of a heading, if applicable.
- `valuemin` <[number]> The minimum value in a node, if applicable.
- `valuemax` <[number]> The maximum value in a node, if applicable.
Expand Down
188 changes: 183 additions & 5 deletions utils/doclint/Documentation.js
Expand Up @@ -18,6 +18,17 @@

/** @typedef {import('../markdown').MarkdownNode} MarkdownNode */

/**
* @typedef {{
* name: string,
* args: ParsedType | null,
* retType: ParsedType | null,
* template: ParsedType | null,
* union: ParsedType | null,
* next: ParsedType | null,
* }} ParsedType
*/

class Documentation {
/**
* @param {!Array<!Documentation.Class>} classesArray
Expand Down Expand Up @@ -242,19 +253,186 @@ Documentation.Member = class {
};

Documentation.Type = class {
/**
* @param {string} expression
* @param {!Array<!Documentation.Member>=} properties
* @return {Documentation.Type}
*/
static parse(expression, properties = []) {
expression = expression.replace(/\\\(/g, '(').replace(/\\\)/g, ')');
const type = Documentation.Type.fromParsedType(parseTypeExpression(expression));
if (!properties.length)
return type;
const types = [];
type._collectAllTypes(types);
let success = false;
for (const t of types) {
if (t.name === 'Object') {
t.properties = properties;
success = true;
}
}
if (!success)
throw new Error('Nested properties given, but there are no objects in type expression: ' + expression);
return type;
}

/**
* @param {ParsedType} parsedType
* @return {Documentation.Type}
*/
static fromParsedType(parsedType, inUnion = false) {
if (!inUnion && parsedType.union) {
const type = new Documentation.Type('union');
type.union = [];
for (let t = parsedType; t; t = t.union)
type.union.push(Documentation.Type.fromParsedType(t, true));
return type;
}

if (parsedType.args) {
const type = new Documentation.Type('function');
type.args = [];
for (let t = parsedType.args; t; t = t.next)
type.args.push(Documentation.Type.fromParsedType(t));
type.returnType = parsedType.retType ? Documentation.Type.fromParsedType(parsedType.retType) : null;
return type;
}

if (parsedType.template) {
const type = new Documentation.Type(parsedType.name);
type.templates = [];
for (let t = parsedType.template; t; t = t.next)
type.templates.push(Documentation.Type.fromParsedType(t));
return type;
}
return new Documentation.Type(parsedType.name);
}

/**
* @param {string} name
* @param {!Array<!Documentation.Member>=} properties
*/
constructor(name, properties = []) {
this.name = name;
this.properties = properties;
constructor(name, properties) {
this.name = name.replace(/^\[/, '').replace(/\]$/, '');
this.properties = this.name === 'Object' ? properties : undefined;
/** @type {Documentation.Type[]} | undefined */
this.union;
/** @type {Documentation.Type[]} | undefined */
this.args;
/** @type {Documentation.Type} | undefined */
this.returnType;
/** @type {Documentation.Type[]} | undefined */
this.templates;
}

visit(visitor) {
for (const p of this.properties || [])
p.visit(visitor);
const types = [];
this._collectAllTypes(types);
for (const type of types) {
for (const p of type.properties || [])
p.visit(visitor);
}
}

/**
* @returns {Documentation.Member[]}
*/
deepProperties() {
const types = [];
this._collectAllTypes(types);
for (const type of types) {
if (type.properties && type.properties.length)
return type.properties;
}
return [];
}

/**
* @param {Documentation.Type[]} result
*/
_collectAllTypes(result) {
result.push(this);
for (const t of this.union || [])
t._collectAllTypes(result);
for (const t of this.args || [])
t._collectAllTypes(result);
for (const t of this.templates || [])
t._collectAllTypes(result);
if (this.returnType)
this.returnType._collectAllTypes(result);
}
};

/**
* @param {string} type
* @returns {ParsedType}
*/
function parseTypeExpression(type) {
type = type.trim();
let name = type;
let next = null;
let template = null;
let args = null;
let retType = null;
let firstTypeLength = type.length;

for (let i = 0; i < type.length; i++) {
if (type[i] === '<') {
name = type.substring(0, i);
const matching = matchingBracket(type.substring(i), '<', '>');
template = parseTypeExpression(type.substring(i + 1, i + matching - 1));
firstTypeLength = i + matching;
break;
}
if (type[i] === '(') {
name = type.substring(0, i);
const matching = matchingBracket(type.substring(i), '(', ')');
args = parseTypeExpression(type.substring(i + 1, i + matching - 1));
i = i + matching;
if (type[i] === ':') {
retType = parseTypeExpression(type.substring(i + 1));
next = retType.next;
retType.next = null;
break;
}
}
if (type[i] === '|' || type[i] === ',') {
name = type.substring(0, i);
firstTypeLength = i;
break;
}
}
let union = null;
if (type[firstTypeLength] === '|')
union = parseTypeExpression(type.substring(firstTypeLength + 1));
else if (type[firstTypeLength] === ',')
next = parseTypeExpression(type.substring(firstTypeLength + 1));
return {
name,
args,
retType,
template,
union,
next
};
}

/**
* @param {string} str
* @param {any} open
* @param {any} close
*/
function matchingBracket(str, open, close) {
let count = 1;
let i = 1;
for (; i < str.length && count; i++) {
if (str[i] === open)
count++;
else if (str[i] === close)
count--;
}
return i;
}

module.exports = Documentation;
47 changes: 20 additions & 27 deletions utils/doclint/MDBuilder.js
Expand Up @@ -22,12 +22,14 @@ const Documentation = require('./Documentation');

/** @typedef {import('../markdown').MarkdownNode} MarkdownNode */

/** @typedef {function({
* clazz?: Documentation.Class,
* member?: Documentation.Member,
* param?: string,
* option?: string
* }): string} Renderer */
/**
* @typedef {function({
* clazz?: Documentation.Class,
* member?: Documentation.Member,
* param?: string,
* option?: string
* }): string} Renderer
*/

class MDOutline {
/**
Expand Down Expand Up @@ -192,8 +194,12 @@ function parseMember(member) {
}
if (!returnType)
returnType = new Documentation.Type('void');
if (match[1] === 'async method')
returnType.name = `Promise<${returnType.name}>`;

if (match[1] === 'async method') {
const templates = [ returnType ];
returnType = new Documentation.Type('Promise');
returnType.templates = templates;
}

if (match[1] === 'event')
return Documentation.Member.createEvent(name, returnType, extractComments(member));
Expand Down Expand Up @@ -234,27 +240,14 @@ function parseProperty(spec) {
* @return {Documentation.Type}
*/
function parseType(spec) {
const { type } = parseArgument(spec.text);
let typeName = type.replace(/[\[\]\\]/g, '');
const literals = typeName.match(/("[^"]+"(\|"[^"]+")*)/);
if (literals) {
const assorted = literals[1];
typeName = typeName.substring(0, literals.index) + assorted + typeName.substring(literals.index + literals[0].length);
}
const arg = parseArgument(spec.text);
const properties = [];
const hasNonEnumProperties = typeName.split('|').some(part => {
const basicTypes = new Set(['string', 'number', 'boolean']);
const arrayTypes = new Set([...basicTypes].map(type => `Array<${type}>`));
return !basicTypes.has(part) && !arrayTypes.has(part) && !(part.startsWith('"') && part.endsWith('"'));
});
if (hasNonEnumProperties && spec) {
for (const child of spec.children || []) {
const { name, text } = parseArgument(child.text);
const comments = /** @type {MarkdownNode[]} */ ([{ type: 'text', text }]);
properties.push(Documentation.Member.createProperty(name, parseType(child), comments, guessRequired(text)));
}
for (const child of spec.children || []) {
const { name, text } = parseArgument(child.text);
const comments = /** @type {MarkdownNode[]} */ ([{ type: 'text', text }]);
properties.push(Documentation.Member.createProperty(name, parseType(child), comments, guessRequired(text)));
}
return new Documentation.Type(typeName, properties);
return Documentation.Type.parse(arg.type, properties);
}

/**
Expand Down
28 changes: 18 additions & 10 deletions utils/doclint/cli.js
Expand Up @@ -268,29 +268,37 @@ function renderProperty(name, type, spec) {
if (spec && spec.length)
comment = spec[0].text;
let children;
if (type.properties && type.properties.length)
children = type.properties.map(p => renderProperty(`\`${p.name}\``, p.type, p.spec))
const properties = type.deepProperties();
if (properties && properties.length)
children = properties.map(p => renderProperty(`\`${p.name}\``, p.type, p.spec))
else if (spec && spec.length > 1)
children = spec.slice(1).map(s => md.clone(s));

let typeText = renderType(type);
if (typeText === '[Promise]<[void]>')
typeText = '[Promise]';

/** @type {MarkdownNode} */
const result = {
type: 'li',
liType: 'default',
text: `${name} <${renderType(type.name)}>${comment ? ' ' + comment : ''}`,
text: `${name} <${typeText}>${comment ? ' ' + comment : ''}`,
children
};
return result;
}

/**
* @param {string} type
* @param {Documentation.Type} type
*/
function renderType(type) {
if (type.includes('"'))
return type.replace(/,/g, '|').replace(/Array/, "[Array]").replace(/null/, "[null]").replace(/number/, "[number]");
const result = type.replace(/([\w]+)/g, '[$1]');
if (result === '[Promise]<[void]>')
return '[Promise]';
return result.replace(/[(]/g, '\\(').replace(/[)]/g, '\\)');
if (type.union)
return type.union.map(l => renderType(l)).join('|');
if (type.templates)
return `[${type.name}]<${type.templates.map(l => renderType(l)).join(', ')}>`;
if (type.args)
return `[function]\\(${type.args.map(l => renderType(l)).join(', ')}\\)${type.returnType ? ':' + renderType(type.returnType) : ''}`;
if (type.name.startsWith('"'))
return type.name;
return `[${type.name}]`;
}

0 comments on commit 80f8a0f

Please sign in to comment.