doc: generator code health (2) (#4843)
This commit is contained in:
parent
8fbb984f64
commit
722db85e1c
File diff suppressed because it is too large
Load diff
|
|
@ -11,23 +11,23 @@ When to consider operation succeeded, defaults to `load`. Events can be either:
|
|||
|
||||
Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout.
|
||||
The default value can be changed by using the
|
||||
[`method: BrowserContext.setDefaultNavigationTimeout`](),
|
||||
[`method: BrowserContext.setDefaultTimeout`](),
|
||||
[`method: Page.setDefaultNavigationTimeout`]() or
|
||||
[`method: Page.setDefaultTimeout`]() methods.
|
||||
[`method: BrowserContext.setDefaultNavigationTimeout`],
|
||||
[`method: BrowserContext.setDefaultTimeout`],
|
||||
[`method: Page.setDefaultNavigationTimeout`] or
|
||||
[`method: Page.setDefaultTimeout`] methods.
|
||||
|
||||
## wait-for-timeout
|
||||
- `timeout` <[number]>
|
||||
|
||||
maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default
|
||||
value can be changed by using the [`method: BrowserContext.setDefaultTimeout`]().
|
||||
value can be changed by using the [`method: BrowserContext.setDefaultTimeout`].
|
||||
|
||||
## input-timeout
|
||||
- `timeout` <[number]>
|
||||
|
||||
Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
using the [`method: BrowserContext.setDefaultTimeout`]() or
|
||||
[`method: Page.setDefaultTimeout`]() methods.
|
||||
using the [`method: BrowserContext.setDefaultTimeout`] or
|
||||
[`method: Page.setDefaultTimeout`] methods.
|
||||
|
||||
## input-no-wait-after
|
||||
- `noWaitAfter` <[boolean]>
|
||||
|
|
@ -117,7 +117,7 @@ Defaults to `'visible'`. Can be either:
|
|||
- `value` <[string]>
|
||||
|
||||
Populates context with given storage state. This method can be used to initialize context with logged-in information
|
||||
obtained via [`method: BrowserContext.storageState`](). Either a path to the file with saved storage, or an object with the following fields:
|
||||
obtained via [`method: BrowserContext.storageState`]. Either a path to the file with saved storage, or an object with the following fields:
|
||||
|
||||
## context-option-acceptdownloads
|
||||
- `acceptDownloads` <[boolean]>
|
||||
|
|
@ -189,7 +189,7 @@ request header value as well as number and date formatting rules.
|
|||
- `permissions` <[Array]<[string]>>
|
||||
|
||||
A list of permissions to grant to all pages in this context. See
|
||||
[`method: BrowserContext.grantPermissions`]() for more details.
|
||||
[`method: BrowserContext.grantPermissions`] for more details.
|
||||
|
||||
## context-option-extrahttpheaders
|
||||
- `extraHTTPHeaders` <[Object]<[string], [string]>>
|
||||
|
|
@ -212,7 +212,7 @@ Credentials for [HTTP authentication](https://developer.mozilla.org/en-US/docs/W
|
|||
- `colorScheme` <"light"|"dark"|"no-preference">
|
||||
|
||||
Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See
|
||||
[`method: Page.emulateMedia`]() for more details. Defaults to '`light`'.
|
||||
[`method: Page.emulateMedia`] for more details. Defaults to '`light`'.
|
||||
|
||||
## context-option-logger
|
||||
- `logger` <[Logger]>
|
||||
|
|
@ -222,17 +222,16 @@ Logger sink for Playwright logging.
|
|||
## context-option-videospath
|
||||
- `videosPath` <[string]>
|
||||
|
||||
**NOTE** Use [`param: recordVideo`]() instead, it takes precedence over `videosPath`. Enables video recording for all pages to
|
||||
`videosPath` directory. If not specified, videos are not recorded. Make sure to await
|
||||
[`method: BrowserContext.close`]() for videos to be saved.
|
||||
**NOTE** Use [`option: recordVideo`] instead, it takes precedence over [`option: videosPath`]. Enables video recording for all pages to [`option: videosPath`] directory. If not specified, videos are not recorded. Make sure to await
|
||||
[`method: BrowserContext.close`] for videos to be saved.
|
||||
|
||||
## context-option-videosize
|
||||
- `videoSize` <[Object]>
|
||||
- `width` <[number]> Video frame width.
|
||||
- `height` <[number]> Video frame height.
|
||||
|
||||
**NOTE** Use [`param: recordVideo`]() instead, it takes precedence over `videoSize`. Specifies dimensions of the automatically
|
||||
recorded video. Can only be used if `videosPath` is set. If not specified the size will be equal to `viewport`. If
|
||||
**NOTE** Use [`option: recordVideo`] instead, it takes precedence over [`option: videoSize`]. Specifies dimensions of the automatically
|
||||
recorded video. Can only be used if [`option: videosPath`] is set. If not specified the size will be equal to `viewport`. If
|
||||
`viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled
|
||||
down if necessary to fit specified size.
|
||||
|
||||
|
|
@ -243,7 +242,7 @@ down if necessary to fit specified size.
|
|||
- `path` <[string]> Path on the filesystem to write the HAR file to.
|
||||
|
||||
Enables [HAR](http://www.softwareishard.com/blog/har-12-spec) recording for all pages into `recordHar.path` file. If not
|
||||
specified, the HAR is not recorded. Make sure to await [`method: BrowserContext.close`]() for the HAR to be
|
||||
specified, the HAR is not recorded. Make sure to await [`method: BrowserContext.close`] for the HAR to be
|
||||
saved.
|
||||
|
||||
## context-option-recordvideo
|
||||
|
|
@ -256,7 +255,7 @@ saved.
|
|||
- `height` <[number]> Video frame height.
|
||||
|
||||
Enables video recording for all pages into `recordVideo.dir` directory. If not specified videos are not recorded. Make
|
||||
sure to await [`method: BrowserContext.close`]() for videos to be saved.
|
||||
sure to await [`method: BrowserContext.close`] for videos to be saved.
|
||||
|
||||
## context-option-proxy
|
||||
- `proxy` <[Object]>
|
||||
|
|
|
|||
|
|
@ -746,7 +746,7 @@ Removes a route created with [`browserContext.route(url, handler)`](#browsercont
|
|||
- `event` <[string]> Event name, same one would pass into `browserContext.on(event)`.
|
||||
- `optionsOrPredicate` <[Function]|[Object]> Either a predicate that receives an event or an options object. Optional.
|
||||
- `predicate` <[Function]> receives the event data and resolves to truthy value when the waiting should resolve.
|
||||
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout).
|
||||
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [`browserContext.setDefaultTimeout(timeout)`](#browsercontextsetdefaulttimeouttimeout).
|
||||
- returns: <[Promise]<[Object]>>
|
||||
|
||||
Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy value. Will throw an error if the context closes before the event is fired. Returns the event data value.
|
||||
|
|
@ -2041,7 +2041,7 @@ Video object associated with this page.
|
|||
- `event` <[string]> Event name, same one would pass into `page.on(event)`.
|
||||
- `optionsOrPredicate` <[Function]|[Object]> Either a predicate that receives an event or an options object. Optional.
|
||||
- `predicate` <[Function]> receives the event data and resolves to truthy value when the waiting should resolve.
|
||||
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout).
|
||||
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [`browserContext.setDefaultTimeout(timeout)`](#browsercontextsetdefaulttimeouttimeout).
|
||||
- returns: <[Promise]<[Object]>>
|
||||
|
||||
Returns the event data value.
|
||||
|
|
@ -4421,7 +4421,7 @@ Contains the URL of the WebSocket.
|
|||
- `event` <[string]> Event name, same one would pass into `webSocket.on(event)`.
|
||||
- `optionsOrPredicate` <[Function]|[Object]> Either a predicate that receives an event or an options object. Optional.
|
||||
- `predicate` <[Function]> receives the event data and resolves to truthy value when the waiting should resolve.
|
||||
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout).
|
||||
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [`browserContext.setDefaultTimeout(timeout)`](#browsercontextsetdefaulttimeouttimeout).
|
||||
- returns: <[Promise]<[Object]>>
|
||||
|
||||
Returns the event data value.
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ Documentation.Class = class {
|
|||
this.templates = templates;
|
||||
this.comment = '';
|
||||
this.index();
|
||||
const match = name.match(/(JS|CDP|[A-Z])(.*)/);
|
||||
this.varName = match[1].toLowerCase() + match[2];
|
||||
}
|
||||
|
||||
index() {
|
||||
|
|
@ -77,6 +79,7 @@ Documentation.Class = class {
|
|||
this.events.set(member.name, member);
|
||||
this.eventsArray.push(member);
|
||||
}
|
||||
member.clazz = this;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -161,6 +164,13 @@ Documentation.Member = class {
|
|||
this.args = new Map();
|
||||
for (const arg of argsArray)
|
||||
this.args.set(arg.name, arg);
|
||||
/** @type {!Documentation.Class} */
|
||||
this.clazz = null;
|
||||
this.signature = this._createSignature();
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new Documentation.Member(this.kind, this.name, this.type, this.argsArray, this.spec, this.required, this.templates);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -206,6 +216,29 @@ Documentation.Member = class {
|
|||
for (const arg of this.argsArray)
|
||||
arg.visit(visitor);
|
||||
}
|
||||
|
||||
_createSignature() {
|
||||
const tokens = [];
|
||||
let hasOptional = false;
|
||||
for (const arg of this.argsArray) {
|
||||
const optional = !arg.required;
|
||||
if (tokens.length) {
|
||||
if (optional && !hasOptional)
|
||||
tokens.push(`[, ${arg.name}`);
|
||||
else
|
||||
tokens.push(`, ${arg.name}`);
|
||||
} else {
|
||||
if (optional && !hasOptional)
|
||||
tokens.push(`[${arg.name}`);
|
||||
else
|
||||
tokens.push(`${arg.name}`);
|
||||
}
|
||||
hasOptional = hasOptional || optional;
|
||||
}
|
||||
if (hasOptional)
|
||||
tokens.push(']');
|
||||
return tokens.join('');
|
||||
}
|
||||
};
|
||||
|
||||
Documentation.Type = class {
|
||||
|
|
|
|||
|
|
@ -22,13 +22,19 @@ const Documentation = require('./Documentation');
|
|||
|
||||
/** @typedef {import('../markdown').MarkdownNode} MarkdownNode */
|
||||
|
||||
/** @typedef {function({
|
||||
* clazz?: Documentation.Class,
|
||||
* member?: Documentation.Member,
|
||||
* param?: string,
|
||||
* option?: string
|
||||
* }): string} Renderer */
|
||||
|
||||
class MDOutline {
|
||||
/**
|
||||
* @param {string} bodyPath
|
||||
* @param {string=} paramsPath
|
||||
* @param {string=} links
|
||||
*/
|
||||
constructor(bodyPath, paramsPath, links = '') {
|
||||
constructor(bodyPath, paramsPath) {
|
||||
const body = md.parse(fs.readFileSync(bodyPath).toString());
|
||||
const params = paramsPath ? md.parse(fs.readFileSync(paramsPath).toString()) : null;
|
||||
const api = params ? applyTemplates(body, params) : body;
|
||||
|
|
@ -39,14 +45,6 @@ class MDOutline {
|
|||
this.classesArray.push(c);
|
||||
this.classes.set(c.name, c);
|
||||
}
|
||||
const linksMap = new Map();
|
||||
for (const link of links.replace(/\r\n/g, '\n').split('\n')) {
|
||||
if (!link)
|
||||
continue;
|
||||
const match = link.match(/\[([^\]]+)\]: ([^"]+) "([^"]+)"/);
|
||||
linksMap.set(new RegExp('\\[' + match[1] + '\\]', 'g'), { href: match[2], label: match[3] });
|
||||
}
|
||||
this.signatures = this._generateComments(linksMap);
|
||||
this.documentation = new Documentation(this.classesArray);
|
||||
}
|
||||
|
||||
|
|
@ -69,51 +67,33 @@ class MDOutline {
|
|||
errors.push(`Member documentation overrides base: ${name}.${memberName} over ${clazz.extends}.${memberName}`);
|
||||
}
|
||||
|
||||
clazz.membersArray = [...clazz.membersArray, ...superClass.membersArray];
|
||||
clazz.membersArray = [...clazz.membersArray, ...superClass.membersArray.map(c => c.clone())];
|
||||
clazz.index();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {Map<string, { href: string, label: string}>} linksMap
|
||||
*/
|
||||
_generateComments(linksMap) {
|
||||
/**
|
||||
* @type {Map<string, string>}
|
||||
*/
|
||||
const signatures = new Map();
|
||||
|
||||
/**
|
||||
* @param {Renderer} linkRenderer
|
||||
*/
|
||||
renderLinks(linkRenderer) {
|
||||
const externalLinksMap = new Map();
|
||||
|
||||
// @type {Map<string, Documentation.Class>}
|
||||
const classesMap = new Map();
|
||||
const membersMap = new Map();
|
||||
for (const clazz of this.classesArray) {
|
||||
for (const method of clazz.methodsArray) {
|
||||
const tokens = [];
|
||||
let hasOptional = false;
|
||||
for (const arg of method.argsArray) {
|
||||
const optional = !arg.required;
|
||||
if (tokens.length) {
|
||||
if (optional && !hasOptional)
|
||||
tokens.push(`[, ${arg.name}`);
|
||||
else
|
||||
tokens.push(`, ${arg.name}`);
|
||||
} else {
|
||||
if (optional && !hasOptional)
|
||||
tokens.push(`[${arg.name}`);
|
||||
else
|
||||
tokens.push(`${arg.name}`);
|
||||
}
|
||||
hasOptional = hasOptional || optional;
|
||||
}
|
||||
if (hasOptional)
|
||||
tokens.push(']');
|
||||
const signature = tokens.join('');
|
||||
const methodName = `${clazz.name}.${method.name}`;
|
||||
signatures.set(methodName, signature);
|
||||
}
|
||||
classesMap.set(clazz.name, clazz);
|
||||
for (const member of clazz.membersArray)
|
||||
membersMap.set(`${member.kind}: ${clazz.name}.${member.name}`, member);
|
||||
}
|
||||
|
||||
for (const clazz of this.classesArray)
|
||||
clazz.visit(item => patchLinks(item.spec, signatures));
|
||||
clazz.visit(item => patchLinks(item, item.spec, classesMap, membersMap, linkRenderer));
|
||||
}
|
||||
|
||||
renderComments() {
|
||||
for (const clazz of this.classesArray)
|
||||
clazz.visit(item => item.comment = renderCommentsForSourceCode(item.spec, linksMap));
|
||||
return signatures;
|
||||
clazz.visit(item => item.comment = renderLinksForSourceCode(item.spec));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -146,20 +126,10 @@ function extractComments(item) {
|
|||
|
||||
/**
|
||||
* @param {MarkdownNode[]} spec
|
||||
* @param {Map<string, { href: string, label: string}>} linksMap
|
||||
*/
|
||||
function renderCommentsForSourceCode(spec, linksMap) {
|
||||
function renderLinksForSourceCode(spec) {
|
||||
const comments = (spec || []).filter(n => n.type !== 'gen' && !n.type.startsWith('h') && (n.type !== 'li' || n.liType !== 'default')).map(c => md.clone(c));
|
||||
md.visitAll(comments, node => {
|
||||
if (node.text) {
|
||||
for (const [regex, { href, label }] of linksMap)
|
||||
node.text = node.text.replace(regex, `[${label}](${href})`);
|
||||
// Those with in `` can have nested [], hence twice twice.
|
||||
node.text = node.text.replace(/\[`([^`]+)`\]\(#([^\)]+)\)/g, '[`$1`](https://github.com/microsoft/playwright/blob/master/docs/api.md#$2)');
|
||||
node.text = node.text.replace(/\[([^\]]+)\]\(#([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/api.md#$2)');
|
||||
node.text = node.text.replace(/\[`([^`]+)`\]\(\.\/([^\)]+)\)/g, '[`$1`](https://github.com/microsoft/playwright/blob/master/docs/$2)');
|
||||
node.text = node.text.replace(/\[([^\]]+)\]\(\.\/([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/$2)');
|
||||
}
|
||||
if (node.liType === 'bullet')
|
||||
node.liType = 'default';
|
||||
});
|
||||
|
|
@ -167,47 +137,39 @@ function renderCommentsForSourceCode(spec, linksMap) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {Documentation.Class|Documentation.Member} item
|
||||
* @param {MarkdownNode[]} spec
|
||||
* @param {Map<string, string>} [signatures]
|
||||
* @param {Map<string, Documentation.Class>} classesMap
|
||||
* @param {Map<string, Documentation.Member>} membersMap
|
||||
* @param {Renderer} linkRenderer
|
||||
*/
|
||||
function patchLinks(spec, signatures) {
|
||||
for (const node of spec || []) {
|
||||
if (node.type === 'text')
|
||||
node.text = patchLinksInText(node.text, signatures);
|
||||
if (node.type === 'li') {
|
||||
node.text = patchLinksInText(node.text, signatures);
|
||||
patchLinks(node.children, signatures);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @returns {string}
|
||||
*/
|
||||
function createLink(text) {
|
||||
const anchor = text.toLowerCase().split(',').map(c => c.replace(/[^a-z]/g, '')).join('-');
|
||||
return `[\`${text}\`](#${anchor})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} comment
|
||||
* @param {Map<string, string>} signatures
|
||||
*/
|
||||
function patchLinksInText(comment, signatures) {
|
||||
if (!signatures)
|
||||
return comment;
|
||||
comment = comment.replace(/\[`(event|method|property):\s(JS|CDP|[A-Z])([^.]+)\.([^`]+)`\]\(\)/g, (match, type, clazzPrefix, clazz, name) => {
|
||||
const className = `${clazzPrefix.toLowerCase()}${clazz}`;
|
||||
if (type === 'event')
|
||||
return createLink(`${className}.on('${name}')`);
|
||||
if (type === 'method') {
|
||||
const signature = signatures.get(`${clazzPrefix}${clazz}.${name}`) || '';
|
||||
return createLink(`${className}.${name}(${signature})`);
|
||||
}
|
||||
return createLink(`${className}.${name}`);
|
||||
function patchLinks(item, spec, classesMap, membersMap, linkRenderer) {
|
||||
if (!spec)
|
||||
return;
|
||||
md.visitAll(spec, node => {
|
||||
if (!node.text)
|
||||
return;
|
||||
node.text = node.text.replace(/\[`((?:event|method|property): [^\]]+)`\]/g, (_, p1) => {
|
||||
const member = membersMap.get(p1);
|
||||
return linkRenderer({ member });
|
||||
});
|
||||
node.text = node.text.replace(/\[`(param|option): ([^\]]+)`\]/g, (_, p1, p2) => {
|
||||
const context = {
|
||||
clazz: item instanceof Documentation.Class ? item : undefined,
|
||||
member: item instanceof Documentation.Member ? item : undefined,
|
||||
};
|
||||
if (p1 === 'param')
|
||||
return linkRenderer({ ...context, param: p2 });
|
||||
if (p1 === 'option')
|
||||
return linkRenderer({ ...context, option: p2 });
|
||||
});
|
||||
node.text = node.text.replace(/\[([\w]+)\]/, (match, p1) => {
|
||||
const clazz = classesMap.get(p1);
|
||||
if (clazz)
|
||||
return linkRenderer({ clazz });
|
||||
return match;
|
||||
});
|
||||
});
|
||||
return comment.replace(/\[`(?:param|option):\s([^`]+)`\]\(\)/g, '`$1`');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -216,7 +178,7 @@ function patchLinksInText(comment, signatures) {
|
|||
*/
|
||||
function parseMember(member) {
|
||||
const args = [];
|
||||
const match = member.text.match(/(event|method|property|async method|): (JS|CDP|[A-Z])([^.]+)\.(.*)/);
|
||||
const match = member.text.match(/(event|method|property|async method): (JS|CDP|[A-Z])([^.]+)\.(.*)/);
|
||||
const name = match[4];
|
||||
let returnType = null;
|
||||
const options = [];
|
||||
|
|
@ -261,7 +223,7 @@ function parseProperty(spec) {
|
|||
const text = param.text;
|
||||
const name = text.substring(0, text.indexOf('<')).replace(/\`/g, '').trim();
|
||||
const comments = extractComments(spec);
|
||||
return Documentation.Member.createProperty(name, parseType(param), comments, guessRequired(renderCommentsForSourceCode(comments, new Map())));
|
||||
return Documentation.Member.createProperty(name, parseType(param), comments, guessRequired(md.render(comments)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -63,17 +63,36 @@ async function run() {
|
|||
|
||||
// Produce api.md
|
||||
{
|
||||
const createMemberLink = (text) => {
|
||||
const anchor = text.toLowerCase().split(',').map(c => c.replace(/[^a-z]/g, '')).join('-');
|
||||
return `[\`${text}\`](#${anchor})`;
|
||||
};
|
||||
|
||||
outline.renderLinks(item => {
|
||||
const { clazz, member, param, option } = item;
|
||||
if (param)
|
||||
return `\`${param}\``;
|
||||
if (option)
|
||||
return `\`${option}\``;
|
||||
if (clazz)
|
||||
return `[${clazz.name}]`;
|
||||
if (member.kind === 'method')
|
||||
return createMemberLink(`${member.clazz.varName}.${member.name}(${member.signature})`);
|
||||
if (member.kind === 'event')
|
||||
return createMemberLink(`${member.clazz.varName}.on('${member.name}')`);
|
||||
if (member.kind === 'property')
|
||||
return createMemberLink(`${member.clazz.varName}.${member.name}`);
|
||||
throw new Error('Unknown member kind ' + member.kind);
|
||||
});
|
||||
|
||||
const comment = '<!-- THIS FILE IS NOW GENERATED -->';
|
||||
{
|
||||
const signatures = outline.signatures;
|
||||
/** @type {MarkdownNode[]} */
|
||||
const result = [];
|
||||
for (const clazz of outline.classesArray) {
|
||||
// Iterate over classes, create header node.
|
||||
/** @type {MarkdownNode} */
|
||||
const classNode = { type: 'h3', text: `class: ${clazz.name}` };
|
||||
const match = clazz.name.match(/(JS|CDP|[A-Z])(.*)/);
|
||||
const varName = match[1].toLocaleLowerCase() + match[2];
|
||||
result.push(classNode);
|
||||
// Append link shortcut to resolve text like [Browser]
|
||||
result.push({
|
||||
|
|
@ -88,13 +107,12 @@ async function run() {
|
|||
/** @type {MarkdownNode} */
|
||||
const memberNode = { type: 'h4', children: [] };
|
||||
if (member.kind === 'event') {
|
||||
memberNode.text = `${varName}.on('${member.name}')`;
|
||||
memberNode.text = `${clazz.varName}.on('${member.name}')`;
|
||||
} else if (member.kind === 'property') {
|
||||
memberNode.text = `${varName}.${member.name}`;
|
||||
memberNode.text = `${clazz.varName}.${member.name}`;
|
||||
} else if (member.kind === 'method') {
|
||||
// Patch method signatures
|
||||
const signature = signatures.get(clazz.name + '.' + member.name);
|
||||
memberNode.text = `${varName}.${member.name}(${signature})`;
|
||||
memberNode.text = `${clazz.varName}.${member.name}(${member.signature})`;
|
||||
for (const arg of member.argsArray) {
|
||||
if (arg.type)
|
||||
memberNode.children.push(renderProperty(`\`${arg.name}\``, arg.type, arg.spec));
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ function serializeMember(member) {
|
|||
const result = { ...member };
|
||||
sanitize(result);
|
||||
result.args = {};
|
||||
delete member.clazz;
|
||||
for (const arg of member.argsArray)
|
||||
result.args[arg.name] = serializeProperty(arg);
|
||||
if (member.type)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,27 @@ let hadChanges = false;
|
|||
writeFile(path.join(typesDir, 'trace.d.ts'), fs.readFileSync(path.join(PROJECT_DIR, 'src', 'trace', 'traceTypes.ts'), 'utf8'));
|
||||
const outline = new MDOutline(path.join(PROJECT_DIR, 'docs-src', 'api-body.md'), path.join(PROJECT_DIR, 'docs-src', 'api-params.md'));
|
||||
outline.copyDocsFromSuperclasses([]);
|
||||
const createMemberLink = (text) => {
|
||||
const anchor = text.toLowerCase().split(',').map(c => c.replace(/[^a-z]/g, '')).join('-');
|
||||
return `[\`${text}\`](https://github.com/microsoft/playwright/blob/master/docs/api.md#${anchor})`;
|
||||
};
|
||||
outline.renderLinks(item => {
|
||||
const { clazz, member, param, option } = item;
|
||||
if (param)
|
||||
return `\`${param}\``;
|
||||
if (option)
|
||||
return `\`${option}\``;
|
||||
if (clazz)
|
||||
return `[${clazz.name}]`;
|
||||
if (member.kind === 'method')
|
||||
return createMemberLink(`${member.clazz.varName}.${member.name}(${member.signature})`);
|
||||
if (member.kind === 'event')
|
||||
return createMemberLink(`${member.clazz.varName}.on('${member.name}')`);
|
||||
if (member.kind === 'property')
|
||||
return createMemberLink(`${member.clazz.varName}.${member.name}`);
|
||||
throw new Error('Unknown member kind ' + member.kind);
|
||||
});
|
||||
outline.renderComments();
|
||||
documentation = outline.documentation;
|
||||
|
||||
// Root module types are overridden.
|
||||
|
|
@ -239,6 +260,12 @@ function parentClass(classDesc) {
|
|||
|
||||
function writeComment(comment, indent = '') {
|
||||
const parts = [];
|
||||
|
||||
comment = comment.replace(/\[`([^`]+)`\]\(#([^\)]+)\)/g, '[`$1`](https://github.com/microsoft/playwright/blob/master/docs/api.md#$2)');
|
||||
comment = comment.replace(/\[([^\]]+)\]\(#([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/api.md#$2)');
|
||||
comment = comment.replace(/\[`([^`]+)`\]\(\.\/([^\)]+)\)/g, '[`$1`](https://github.com/microsoft/playwright/blob/master/docs/$2)');
|
||||
comment = comment.replace(/\[([^\]]+)\]\(\.\/([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/$2)');
|
||||
|
||||
parts.push(indent + '/**');
|
||||
parts.push(...comment.split('\n').map(line => indent + ' * ' + line.replace(/\*\//g, '*\\/')));
|
||||
parts.push(indent + ' */');
|
||||
|
|
@ -411,18 +438,6 @@ function memberJSDOC(member, indent) {
|
|||
return writeComment(lines.join('\n'), indent) + '\n' + indent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Documentation.Class} mdClass
|
||||
* @param {Documentation.Class} jsClass
|
||||
* @return {Documentation.Class}
|
||||
*/
|
||||
function mergeClasses(mdClass, jsClass) {
|
||||
mdClass.templates = jsClass.templates;
|
||||
for (const member of mdClass.membersArray)
|
||||
member.templates = jsClass.members.get(member.name).templates;
|
||||
return mdClass;
|
||||
}
|
||||
|
||||
function generateDevicesTypes() {
|
||||
const namedDevices =
|
||||
Object.keys(devices)
|
||||
|
|
|
|||
Loading…
Reference in a new issue