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.
|
Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout.
|
||||||
The default value can be changed by using the
|
The default value can be changed by using the
|
||||||
[`method: BrowserContext.setDefaultNavigationTimeout`](),
|
[`method: BrowserContext.setDefaultNavigationTimeout`],
|
||||||
[`method: BrowserContext.setDefaultTimeout`](),
|
[`method: BrowserContext.setDefaultTimeout`],
|
||||||
[`method: Page.setDefaultNavigationTimeout`]() or
|
[`method: Page.setDefaultNavigationTimeout`] or
|
||||||
[`method: Page.setDefaultTimeout`]() methods.
|
[`method: Page.setDefaultTimeout`] methods.
|
||||||
|
|
||||||
## wait-for-timeout
|
## wait-for-timeout
|
||||||
- `timeout` <[number]>
|
- `timeout` <[number]>
|
||||||
|
|
||||||
maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default
|
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
|
## input-timeout
|
||||||
- `timeout` <[number]>
|
- `timeout` <[number]>
|
||||||
|
|
||||||
Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
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
|
using the [`method: BrowserContext.setDefaultTimeout`] or
|
||||||
[`method: Page.setDefaultTimeout`]() methods.
|
[`method: Page.setDefaultTimeout`] methods.
|
||||||
|
|
||||||
## input-no-wait-after
|
## input-no-wait-after
|
||||||
- `noWaitAfter` <[boolean]>
|
- `noWaitAfter` <[boolean]>
|
||||||
|
|
@ -117,7 +117,7 @@ Defaults to `'visible'`. Can be either:
|
||||||
- `value` <[string]>
|
- `value` <[string]>
|
||||||
|
|
||||||
Populates context with given storage state. This method can be used to initialize context with logged-in information
|
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
|
## context-option-acceptdownloads
|
||||||
- `acceptDownloads` <[boolean]>
|
- `acceptDownloads` <[boolean]>
|
||||||
|
|
@ -189,7 +189,7 @@ request header value as well as number and date formatting rules.
|
||||||
- `permissions` <[Array]<[string]>>
|
- `permissions` <[Array]<[string]>>
|
||||||
|
|
||||||
A list of permissions to grant to all pages in this context. See
|
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
|
## context-option-extrahttpheaders
|
||||||
- `extraHTTPHeaders` <[Object]<[string], [string]>>
|
- `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">
|
- `colorScheme` <"light"|"dark"|"no-preference">
|
||||||
|
|
||||||
Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See
|
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
|
## context-option-logger
|
||||||
- `logger` <[Logger]>
|
- `logger` <[Logger]>
|
||||||
|
|
@ -222,17 +222,16 @@ Logger sink for Playwright logging.
|
||||||
## context-option-videospath
|
## context-option-videospath
|
||||||
- `videosPath` <[string]>
|
- `videosPath` <[string]>
|
||||||
|
|
||||||
**NOTE** Use [`param: recordVideo`]() instead, it takes precedence over `videosPath`. Enables video recording for all pages to
|
**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
|
||||||
`videosPath` directory. If not specified, videos are not recorded. Make sure to await
|
[`method: BrowserContext.close`] for videos to be saved.
|
||||||
[`method: BrowserContext.close`]() for videos to be saved.
|
|
||||||
|
|
||||||
## context-option-videosize
|
## context-option-videosize
|
||||||
- `videoSize` <[Object]>
|
- `videoSize` <[Object]>
|
||||||
- `width` <[number]> Video frame width.
|
- `width` <[number]> Video frame width.
|
||||||
- `height` <[number]> Video frame height.
|
- `height` <[number]> Video frame height.
|
||||||
|
|
||||||
**NOTE** Use [`param: recordVideo`]() instead, it takes precedence over `videoSize`. Specifies dimensions of the automatically
|
**NOTE** Use [`option: recordVideo`] instead, it takes precedence over [`option: 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
|
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
|
`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.
|
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.
|
- `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
|
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.
|
saved.
|
||||||
|
|
||||||
## context-option-recordvideo
|
## context-option-recordvideo
|
||||||
|
|
@ -256,7 +255,7 @@ saved.
|
||||||
- `height` <[number]> Video frame height.
|
- `height` <[number]> Video frame height.
|
||||||
|
|
||||||
Enables video recording for all pages into `recordVideo.dir` directory. If not specified videos are not recorded. Make
|
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
|
## context-option-proxy
|
||||||
- `proxy` <[Object]>
|
- `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)`.
|
- `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.
|
- `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.
|
- `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: <[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.
|
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)`.
|
- `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.
|
- `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.
|
- `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: <[Promise]<[Object]>>
|
||||||
|
|
||||||
Returns the event data value.
|
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)`.
|
- `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.
|
- `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.
|
- `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: <[Promise]<[Object]>>
|
||||||
|
|
||||||
Returns the event data value.
|
Returns the event data value.
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ Documentation.Class = class {
|
||||||
this.templates = templates;
|
this.templates = templates;
|
||||||
this.comment = '';
|
this.comment = '';
|
||||||
this.index();
|
this.index();
|
||||||
|
const match = name.match(/(JS|CDP|[A-Z])(.*)/);
|
||||||
|
this.varName = match[1].toLowerCase() + match[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
index() {
|
index() {
|
||||||
|
|
@ -77,6 +79,7 @@ Documentation.Class = class {
|
||||||
this.events.set(member.name, member);
|
this.events.set(member.name, member);
|
||||||
this.eventsArray.push(member);
|
this.eventsArray.push(member);
|
||||||
}
|
}
|
||||||
|
member.clazz = this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,6 +164,13 @@ Documentation.Member = class {
|
||||||
this.args = new Map();
|
this.args = new Map();
|
||||||
for (const arg of argsArray)
|
for (const arg of argsArray)
|
||||||
this.args.set(arg.name, arg);
|
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)
|
for (const arg of this.argsArray)
|
||||||
arg.visit(visitor);
|
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 {
|
Documentation.Type = class {
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,19 @@ const Documentation = require('./Documentation');
|
||||||
|
|
||||||
/** @typedef {import('../markdown').MarkdownNode} MarkdownNode */
|
/** @typedef {import('../markdown').MarkdownNode} MarkdownNode */
|
||||||
|
|
||||||
|
/** @typedef {function({
|
||||||
|
* clazz?: Documentation.Class,
|
||||||
|
* member?: Documentation.Member,
|
||||||
|
* param?: string,
|
||||||
|
* option?: string
|
||||||
|
* }): string} Renderer */
|
||||||
|
|
||||||
class MDOutline {
|
class MDOutline {
|
||||||
/**
|
/**
|
||||||
* @param {string} bodyPath
|
* @param {string} bodyPath
|
||||||
* @param {string=} paramsPath
|
* @param {string=} paramsPath
|
||||||
* @param {string=} links
|
|
||||||
*/
|
*/
|
||||||
constructor(bodyPath, paramsPath, links = '') {
|
constructor(bodyPath, paramsPath) {
|
||||||
const body = md.parse(fs.readFileSync(bodyPath).toString());
|
const body = md.parse(fs.readFileSync(bodyPath).toString());
|
||||||
const params = paramsPath ? md.parse(fs.readFileSync(paramsPath).toString()) : null;
|
const params = paramsPath ? md.parse(fs.readFileSync(paramsPath).toString()) : null;
|
||||||
const api = params ? applyTemplates(body, params) : body;
|
const api = params ? applyTemplates(body, params) : body;
|
||||||
|
|
@ -39,14 +45,6 @@ class MDOutline {
|
||||||
this.classesArray.push(c);
|
this.classesArray.push(c);
|
||||||
this.classes.set(c.name, 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);
|
this.documentation = new Documentation(this.classesArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,51 +67,33 @@ class MDOutline {
|
||||||
errors.push(`Member documentation overrides base: ${name}.${memberName} over ${clazz.extends}.${memberName}`);
|
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();
|
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 clazz of this.classesArray) {
|
||||||
for (const method of clazz.methodsArray) {
|
classesMap.set(clazz.name, clazz);
|
||||||
const tokens = [];
|
for (const member of clazz.membersArray)
|
||||||
let hasOptional = false;
|
membersMap.set(`${member.kind}: ${clazz.name}.${member.name}`, member);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const clazz of this.classesArray)
|
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)
|
for (const clazz of this.classesArray)
|
||||||
clazz.visit(item => item.comment = renderCommentsForSourceCode(item.spec, linksMap));
|
clazz.visit(item => item.comment = renderLinksForSourceCode(item.spec));
|
||||||
return signatures;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,20 +126,10 @@ function extractComments(item) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode[]} spec
|
* @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));
|
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 => {
|
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')
|
if (node.liType === 'bullet')
|
||||||
node.liType = 'default';
|
node.liType = 'default';
|
||||||
});
|
});
|
||||||
|
|
@ -167,47 +137,39 @@ function renderCommentsForSourceCode(spec, linksMap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {Documentation.Class|Documentation.Member} item
|
||||||
* @param {MarkdownNode[]} spec
|
* @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) {
|
function patchLinks(item, spec, classesMap, membersMap, linkRenderer) {
|
||||||
for (const node of spec || []) {
|
if (!spec)
|
||||||
if (node.type === 'text')
|
return;
|
||||||
node.text = patchLinksInText(node.text, signatures);
|
md.visitAll(spec, node => {
|
||||||
if (node.type === 'li') {
|
if (!node.text)
|
||||||
node.text = patchLinksInText(node.text, signatures);
|
return;
|
||||||
patchLinks(node.children, signatures);
|
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 = {
|
||||||
* @param {string} text
|
clazz: item instanceof Documentation.Class ? item : undefined,
|
||||||
* @returns {string}
|
member: item instanceof Documentation.Member ? item : undefined,
|
||||||
*/
|
};
|
||||||
function createLink(text) {
|
if (p1 === 'param')
|
||||||
const anchor = text.toLowerCase().split(',').map(c => c.replace(/[^a-z]/g, '')).join('-');
|
return linkRenderer({ ...context, param: p2 });
|
||||||
return `[\`${text}\`](#${anchor})`;
|
if (p1 === 'option')
|
||||||
}
|
return linkRenderer({ ...context, option: p2 });
|
||||||
|
});
|
||||||
/**
|
node.text = node.text.replace(/\[([\w]+)\]/, (match, p1) => {
|
||||||
* @param {string} comment
|
const clazz = classesMap.get(p1);
|
||||||
* @param {Map<string, string>} signatures
|
if (clazz)
|
||||||
*/
|
return linkRenderer({ clazz });
|
||||||
function patchLinksInText(comment, signatures) {
|
return match;
|
||||||
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}`);
|
|
||||||
});
|
});
|
||||||
return comment.replace(/\[`(?:param|option):\s([^`]+)`\]\(\)/g, '`$1`');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -216,7 +178,7 @@ function patchLinksInText(comment, signatures) {
|
||||||
*/
|
*/
|
||||||
function parseMember(member) {
|
function parseMember(member) {
|
||||||
const args = [];
|
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];
|
const name = match[4];
|
||||||
let returnType = null;
|
let returnType = null;
|
||||||
const options = [];
|
const options = [];
|
||||||
|
|
@ -261,7 +223,7 @@ function parseProperty(spec) {
|
||||||
const text = param.text;
|
const text = param.text;
|
||||||
const name = text.substring(0, text.indexOf('<')).replace(/\`/g, '').trim();
|
const name = text.substring(0, text.indexOf('<')).replace(/\`/g, '').trim();
|
||||||
const comments = extractComments(spec);
|
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
|
// 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 comment = '<!-- THIS FILE IS NOW GENERATED -->';
|
||||||
{
|
{
|
||||||
const signatures = outline.signatures;
|
|
||||||
/** @type {MarkdownNode[]} */
|
/** @type {MarkdownNode[]} */
|
||||||
const result = [];
|
const result = [];
|
||||||
for (const clazz of outline.classesArray) {
|
for (const clazz of outline.classesArray) {
|
||||||
// Iterate over classes, create header node.
|
// Iterate over classes, create header node.
|
||||||
/** @type {MarkdownNode} */
|
/** @type {MarkdownNode} */
|
||||||
const classNode = { type: 'h3', text: `class: ${clazz.name}` };
|
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);
|
result.push(classNode);
|
||||||
// Append link shortcut to resolve text like [Browser]
|
// Append link shortcut to resolve text like [Browser]
|
||||||
result.push({
|
result.push({
|
||||||
|
|
@ -88,13 +107,12 @@ async function run() {
|
||||||
/** @type {MarkdownNode} */
|
/** @type {MarkdownNode} */
|
||||||
const memberNode = { type: 'h4', children: [] };
|
const memberNode = { type: 'h4', children: [] };
|
||||||
if (member.kind === 'event') {
|
if (member.kind === 'event') {
|
||||||
memberNode.text = `${varName}.on('${member.name}')`;
|
memberNode.text = `${clazz.varName}.on('${member.name}')`;
|
||||||
} else if (member.kind === 'property') {
|
} else if (member.kind === 'property') {
|
||||||
memberNode.text = `${varName}.${member.name}`;
|
memberNode.text = `${clazz.varName}.${member.name}`;
|
||||||
} else if (member.kind === 'method') {
|
} else if (member.kind === 'method') {
|
||||||
// Patch method signatures
|
// Patch method signatures
|
||||||
const signature = signatures.get(clazz.name + '.' + member.name);
|
memberNode.text = `${clazz.varName}.${member.name}(${member.signature})`;
|
||||||
memberNode.text = `${varName}.${member.name}(${signature})`;
|
|
||||||
for (const arg of member.argsArray) {
|
for (const arg of member.argsArray) {
|
||||||
if (arg.type)
|
if (arg.type)
|
||||||
memberNode.children.push(renderProperty(`\`${arg.name}\``, arg.type, arg.spec));
|
memberNode.children.push(renderProperty(`\`${arg.name}\``, arg.type, arg.spec));
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ function serializeMember(member) {
|
||||||
const result = { ...member };
|
const result = { ...member };
|
||||||
sanitize(result);
|
sanitize(result);
|
||||||
result.args = {};
|
result.args = {};
|
||||||
|
delete member.clazz;
|
||||||
for (const arg of member.argsArray)
|
for (const arg of member.argsArray)
|
||||||
result.args[arg.name] = serializeProperty(arg);
|
result.args[arg.name] = serializeProperty(arg);
|
||||||
if (member.type)
|
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'));
|
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'));
|
const outline = new MDOutline(path.join(PROJECT_DIR, 'docs-src', 'api-body.md'), path.join(PROJECT_DIR, 'docs-src', 'api-params.md'));
|
||||||
outline.copyDocsFromSuperclasses([]);
|
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;
|
documentation = outline.documentation;
|
||||||
|
|
||||||
// Root module types are overridden.
|
// Root module types are overridden.
|
||||||
|
|
@ -239,6 +260,12 @@ function parentClass(classDesc) {
|
||||||
|
|
||||||
function writeComment(comment, indent = '') {
|
function writeComment(comment, indent = '') {
|
||||||
const parts = [];
|
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(indent + '/**');
|
||||||
parts.push(...comment.split('\n').map(line => indent + ' * ' + line.replace(/\*\//g, '*\\/')));
|
parts.push(...comment.split('\n').map(line => indent + ' * ' + line.replace(/\*\//g, '*\\/')));
|
||||||
parts.push(indent + ' */');
|
parts.push(indent + ' */');
|
||||||
|
|
@ -411,18 +438,6 @@ function memberJSDOC(member, indent) {
|
||||||
return writeComment(lines.join('\n'), indent) + '\n' + 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() {
|
function generateDevicesTypes() {
|
||||||
const namedDevices =
|
const namedDevices =
|
||||||
Object.keys(devices)
|
Object.keys(devices)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue