mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore(types): generate our own d.ts file from api.md (#3744)
Generate `//index.d.ts` file with precise typescript definitions for all of the Puppeteer API.
This commit is contained in:
parent
63d9ac4df8
commit
f2c968fdb8
@ -11,7 +11,8 @@ install:
|
|||||||
- if "%nodejs_version%" == "8.11.3" (
|
- if "%nodejs_version%" == "8.11.3" (
|
||||||
npm run lint &&
|
npm run lint &&
|
||||||
npm run coverage &&
|
npm run coverage &&
|
||||||
npm run test-doclint
|
npm run test-doclint &&
|
||||||
|
npm run test-types
|
||||||
) else (
|
) else (
|
||||||
npm run unit-node6
|
npm run unit-node6
|
||||||
)
|
)
|
||||||
|
@ -20,6 +20,7 @@ task:
|
|||||||
lint_script: npm run lint
|
lint_script: npm run lint
|
||||||
coverage_script: npm run coverage
|
coverage_script: npm run coverage
|
||||||
test_doclint_script: npm run test-doclint
|
test_doclint_script: npm run test-doclint
|
||||||
|
test_types_script: npm run test-types
|
||||||
|
|
||||||
task:
|
task:
|
||||||
osx_instance:
|
osx_instance:
|
||||||
@ -34,3 +35,4 @@ task:
|
|||||||
lint_script: npm run lint
|
lint_script: npm run lint
|
||||||
coverage_script: npm run coverage
|
coverage_script: npm run coverage
|
||||||
test_doclint_script: npm run test-doclint
|
test_doclint_script: npm run test-doclint
|
||||||
|
test_types_script: npm run test-types
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,3 +12,4 @@ yarn.lock
|
|||||||
/node6
|
/node6
|
||||||
/lib/protocol.d.ts
|
/lib/protocol.d.ts
|
||||||
/utils/browser/puppeteer-web.js
|
/utils/browser/puppeteer-web.js
|
||||||
|
/index.d.ts
|
||||||
|
@ -19,6 +19,7 @@ script:
|
|||||||
- 'if [ "$NODE8" = "true" ]; then npm run lint; fi'
|
- 'if [ "$NODE8" = "true" ]; then npm run lint; fi'
|
||||||
- 'if [ "$NODE8" = "true" ]; then npm run coverage; fi'
|
- 'if [ "$NODE8" = "true" ]; then npm run coverage; fi'
|
||||||
- 'if [ "$NODE8" = "true" ]; then npm run test-doclint; fi'
|
- 'if [ "$NODE8" = "true" ]; then npm run test-doclint; fi'
|
||||||
|
- 'if [ "$NODE8" = "true" ]; then npm run test-types; fi'
|
||||||
- 'if [ "$NODE8" = "true" ]; then npm run bundle; fi'
|
- 'if [ "$NODE8" = "true" ]; then npm run bundle; fi'
|
||||||
- 'if [ "$NODE8" = "true" ]; then npm run unit-bundle; fi'
|
- 'if [ "$NODE8" = "true" ]; then npm run unit-bundle; fi'
|
||||||
- 'if [ "$NODE6" = "true" ]; then npm run unit-node6; fi'
|
- 'if [ "$NODE6" = "true" ]; then npm run unit-node6; fi'
|
||||||
|
39
docs/api.md
39
docs/api.md
@ -565,7 +565,7 @@ The method initiates a GET request to download the revision from the host.
|
|||||||
- returns: <[Promise]<[Array]<[string]>>> A list of all revisions available locally on disk.
|
- returns: <[Promise]<[Array]<[string]>>> A list of all revisions available locally on disk.
|
||||||
|
|
||||||
#### browserFetcher.platform()
|
#### browserFetcher.platform()
|
||||||
- returns: <[string]> Returns one of `mac`, `linux`, `win32` or `win64`.
|
- returns: <[string]> One of `mac`, `linux`, `win32` or `win64`.
|
||||||
|
|
||||||
#### browserFetcher.remove(revision)
|
#### browserFetcher.remove(revision)
|
||||||
- `revision` <[string]> a revision to remove. The method will throw if the revision has not been downloaded.
|
- `revision` <[string]> a revision to remove. The method will throw if the revision has not been downloaded.
|
||||||
@ -582,7 +582,7 @@ The method initiates a GET request to download the revision from the host.
|
|||||||
|
|
||||||
### class: Browser
|
### class: Browser
|
||||||
|
|
||||||
* extends: [`EventEmitter`](https://nodejs.org/api/events.html#events_class_eventemitter)
|
* extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
|
||||||
|
|
||||||
A Browser is created when Puppeteer connects to a Chromium instance, either through [`puppeteer.launch`](#puppeteerlaunchoptions) or [`puppeteer.connect`](#puppeteerconnectoptions).
|
A Browser is created when Puppeteer connects to a Chromium instance, either through [`puppeteer.launch`](#puppeteerlaunchoptions) or [`puppeteer.connect`](#puppeteerconnectoptions).
|
||||||
|
|
||||||
@ -734,7 +734,7 @@ You can find the `webSocketDebuggerUrl` from `http://${host}:${port}/json/versio
|
|||||||
|
|
||||||
### class: BrowserContext
|
### class: BrowserContext
|
||||||
|
|
||||||
* extends: [`EventEmitter`](https://nodejs.org/api/events.html#events_class_eventemitter)
|
* extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
|
||||||
|
|
||||||
BrowserContexts provide a way to operate multiple independent browser sessions. When a browser is launched, it has
|
BrowserContexts provide a way to operate multiple independent browser sessions. When a browser is launched, it has
|
||||||
a single BrowserContext used by default. The method `browser.newPage()` creates a page in the default browser context.
|
a single BrowserContext used by default. The method `browser.newPage()` creates a page in the default browser context.
|
||||||
@ -864,7 +864,7 @@ const newWindowTarget = await browserContext.waitForTarget(target => target.url(
|
|||||||
|
|
||||||
### class: Page
|
### class: Page
|
||||||
|
|
||||||
* extends: [`EventEmitter`](https://nodejs.org/api/events.html#events_class_eventemitter)
|
* extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
|
||||||
|
|
||||||
Page provides methods to interact with a single tab or [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. One [Browser] instance might have multiple [Page] instances.
|
Page provides methods to interact with a single tab or [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. One [Browser] instance might have multiple [Page] instances.
|
||||||
|
|
||||||
@ -1035,7 +1035,7 @@ Shortcut for [page.mainFrame().$$(selector)](#frameselector-1).
|
|||||||
|
|
||||||
#### page.$$eval(selector, pageFunction[, ...args])
|
#### page.$$eval(selector, pageFunction[, ...args])
|
||||||
- `selector` <[string]> A [selector] to query page for
|
- `selector` <[string]> A [selector] to query page for
|
||||||
- `pageFunction` <[function]> Function to be evaluated in browser context
|
- `pageFunction` <[function]\([Array]<[Element]>\)> Function to be evaluated in browser context
|
||||||
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
||||||
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
||||||
|
|
||||||
@ -1050,7 +1050,7 @@ const divsCounts = await page.$$eval('div', divs => divs.length);
|
|||||||
|
|
||||||
#### page.$eval(selector, pageFunction[, ...args])
|
#### page.$eval(selector, pageFunction[, ...args])
|
||||||
- `selector` <[string]> A [selector] to query page for
|
- `selector` <[string]> A [selector] to query page for
|
||||||
- `pageFunction` <[function]> Function to be evaluated in browser context
|
- `pageFunction` <[function]\([Element]\)> Function to be evaluated in browser context
|
||||||
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
||||||
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
||||||
|
|
||||||
@ -1464,7 +1464,7 @@ Indicates that the page has been closed.
|
|||||||
- returns: <[Keyboard]>
|
- returns: <[Keyboard]>
|
||||||
|
|
||||||
#### page.mainFrame()
|
#### page.mainFrame()
|
||||||
- returns: <[Frame]> returns page's main frame.
|
- returns: <[Frame]> The page's main frame.
|
||||||
|
|
||||||
Page is guaranteed to have a main frame which persists during navigations.
|
Page is guaranteed to have a main frame which persists during navigations.
|
||||||
|
|
||||||
@ -1609,7 +1609,7 @@ Shortcut for [page.mainFrame().executionContext().queryObjects(prototypeHandle)]
|
|||||||
#### page.select(selector, ...values)
|
#### page.select(selector, ...values)
|
||||||
- `selector` <[string]> A [selector] to query page for
|
- `selector` <[string]> A [selector] to query page for
|
||||||
- `...values` <...[string]> Values of options to select. If the `<select>` has the `multiple` attribute, all values are considered, otherwise only the first one is taken into account.
|
- `...values` <...[string]> Values of options to select. If the `<select>` has the `multiple` attribute, all values are considered, otherwise only the first one is taken into account.
|
||||||
- returns: <[Promise]<[Array]<[string]>>> Returns an array of option values that have been successfully selected.
|
- returns: <[Promise]<[Array]<[string]>>> An array of option values that have been successfully selected.
|
||||||
|
|
||||||
Triggers a `change` and `input` event once all the provided options have been selected.
|
Triggers a `change` and `input` event once all the provided options have been selected.
|
||||||
If there's no `<select>` element matching `selector`, the method throws an error.
|
If there's no `<select>` element matching `selector`, the method throws an error.
|
||||||
@ -1767,7 +1767,7 @@ Shortcut for [page.mainFrame().tap(selector)](#frametapselector).
|
|||||||
- returns: <[Target]> a target this page was created from.
|
- returns: <[Target]> a target this page was created from.
|
||||||
|
|
||||||
#### page.title()
|
#### page.title()
|
||||||
- returns: <[Promise]<[string]>> Returns page's title.
|
- returns: <[Promise]<[string]>> The page's title.
|
||||||
|
|
||||||
Shortcut for [page.mainFrame().title()](#frametitle).
|
Shortcut for [page.mainFrame().title()](#frametitle).
|
||||||
|
|
||||||
@ -2042,7 +2042,7 @@ Most of the accessibility tree gets filtered out when converting from Blink AX T
|
|||||||
#### accessibility.snapshot([options])
|
#### accessibility.snapshot([options])
|
||||||
- `options` <[Object]>
|
- `options` <[Object]>
|
||||||
- `interestingOnly` <[boolean]> Prune uninteresting nodes from the tree. Defaults to `true`.
|
- `interestingOnly` <[boolean]> Prune uninteresting nodes from the tree. Defaults to `true`.
|
||||||
- returns: <[Promise]<[Object]>> Returns an [AXNode] object with the following properties:
|
- returns: <[Promise]<[Object]>> An [AXNode] object with the following properties:
|
||||||
- `role` <[string]> The [role](https://www.w3.org/TR/wai-aria/#usage_intro).
|
- `role` <[string]> The [role](https://www.w3.org/TR/wai-aria/#usage_intro).
|
||||||
- `name` <[string]> A human readable name for the node.
|
- `name` <[string]> A human readable name for the node.
|
||||||
- `value` <[string]|[number]> The current value of the node.
|
- `value` <[string]|[number]> The current value of the node.
|
||||||
@ -2382,7 +2382,7 @@ The method runs `document.querySelectorAll` within the frame. If no elements mat
|
|||||||
|
|
||||||
#### frame.$$eval(selector, pageFunction[, ...args])
|
#### frame.$$eval(selector, pageFunction[, ...args])
|
||||||
- `selector` <[string]> A [selector] to query frame for
|
- `selector` <[string]> A [selector] to query frame for
|
||||||
- `pageFunction` <[function]> Function to be evaluated in browser context
|
- `pageFunction` <[function]\([Array]<[Element]>\)> Function to be evaluated in browser context
|
||||||
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
||||||
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
||||||
|
|
||||||
@ -2397,7 +2397,7 @@ const divsCounts = await frame.$$eval('div', divs => divs.length);
|
|||||||
|
|
||||||
#### frame.$eval(selector, pageFunction[, ...args])
|
#### frame.$eval(selector, pageFunction[, ...args])
|
||||||
- `selector` <[string]> A [selector] to query frame for
|
- `selector` <[string]> A [selector] to query frame for
|
||||||
- `pageFunction` <[function]> Function to be evaluated in browser context
|
- `pageFunction` <[function]\([Element]\)> Function to be evaluated in browser context
|
||||||
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
||||||
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
||||||
|
|
||||||
@ -2580,12 +2580,12 @@ If the name is empty, returns the id attribute instead.
|
|||||||
> **NOTE** This value is calculated once when the frame is created, and will not update if the attribute is changed later.
|
> **NOTE** This value is calculated once when the frame is created, and will not update if the attribute is changed later.
|
||||||
|
|
||||||
#### frame.parentFrame()
|
#### frame.parentFrame()
|
||||||
- returns: <?[Frame]> Returns parent frame, if any. Detached frames and main frames return `null`.
|
- returns: <?[Frame]> Parent frame, if any. Detached frames and main frames return `null`.
|
||||||
|
|
||||||
#### frame.select(selector, ...values)
|
#### frame.select(selector, ...values)
|
||||||
- `selector` <[string]> A [selector] to query frame for
|
- `selector` <[string]> A [selector] to query frame for
|
||||||
- `...values` <...[string]> Values of options to select. If the `<select>` has the `multiple` attribute, all values are considered, otherwise only the first one is taken into account.
|
- `...values` <...[string]> Values of options to select. If the `<select>` has the `multiple` attribute, all values are considered, otherwise only the first one is taken into account.
|
||||||
- returns: <[Promise]<[Array]<[string]>>> Returns an array of option values that have been successfully selected.
|
- returns: <[Promise]<[Array]<[string]>>> An array of option values that have been successfully selected.
|
||||||
|
|
||||||
Triggers a `change` and `input` event once all the provided options have been selected.
|
Triggers a `change` and `input` event once all the provided options have been selected.
|
||||||
If there's no `<select>` element matching `selector`, the method throws an error.
|
If there's no `<select>` element matching `selector`, the method throws an error.
|
||||||
@ -2614,7 +2614,7 @@ This method fetches an element with `selector`, scrolls it into view if needed,
|
|||||||
If there's no element matching `selector`, the method throws an error.
|
If there's no element matching `selector`, the method throws an error.
|
||||||
|
|
||||||
#### frame.title()
|
#### frame.title()
|
||||||
- returns: <[Promise]<[string]>> Returns page's title.
|
- returns: <[Promise]<[string]>> The page's title.
|
||||||
|
|
||||||
#### frame.type(selector, text[, options])
|
#### frame.type(selector, text[, options])
|
||||||
- `selector` <[string]> A [selector] of an element to type into. If there are multiple elements satisfying the selector, the first will be used.
|
- `selector` <[string]> A [selector] of an element to type into. If there are multiple elements satisfying the selector, the first will be used.
|
||||||
@ -2925,8 +2925,7 @@ function, it **will not be called**.
|
|||||||
> **NOTE** The method will return an empty JSON object if the referenced object is not stringifiable. It will throw an error if the object has circular references.
|
> **NOTE** The method will return an empty JSON object if the referenced object is not stringifiable. It will throw an error if the object has circular references.
|
||||||
|
|
||||||
### class: ElementHandle
|
### class: ElementHandle
|
||||||
|
* extends: [JSHandle]
|
||||||
> **NOTE** Class [ElementHandle] extends [JSHandle].
|
|
||||||
|
|
||||||
ElementHandle represents an in-page DOM element. ElementHandles can be created with the [page.$](#pageselector) method.
|
ElementHandle represents an in-page DOM element. ElementHandles can be created with the [page.$](#pageselector) method.
|
||||||
|
|
||||||
@ -2960,7 +2959,7 @@ The method runs `element.querySelectorAll` within the page. If no elements match
|
|||||||
|
|
||||||
#### elementHandle.$$eval(selector, pageFunction[, ...args])
|
#### elementHandle.$$eval(selector, pageFunction[, ...args])
|
||||||
- `selector` <[string]> A [selector] to query page for
|
- `selector` <[string]> A [selector] to query page for
|
||||||
- `pageFunction` <[function]> Function to be evaluated in browser context
|
- `pageFunction` <[function]\([Array]<[Element]>\)> Function to be evaluated in browser context
|
||||||
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
||||||
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
||||||
|
|
||||||
@ -2982,7 +2981,7 @@ expect(await feedHandle.$$eval('.tweet', nodes => nodes.map(n => n.innerText))).
|
|||||||
|
|
||||||
#### elementHandle.$eval(selector, pageFunction[, ...args])
|
#### elementHandle.$eval(selector, pageFunction[, ...args])
|
||||||
- `selector` <[string]> A [selector] to query page for
|
- `selector` <[string]> A [selector] to query page for
|
||||||
- `pageFunction` <[function]> Function to be evaluated in browser context
|
- `pageFunction` <[function]\([Element]\)> Function to be evaluated in browser context
|
||||||
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
||||||
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
|
||||||
|
|
||||||
@ -3432,7 +3431,7 @@ Identifies what kind of target this is. Can be `"page"`, [`"background_page"`](h
|
|||||||
|
|
||||||
### class: CDPSession
|
### class: CDPSession
|
||||||
|
|
||||||
* extends: [`EventEmitter`](https://nodejs.org/api/events.html#events_class_eventemitter)
|
* extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
|
||||||
|
|
||||||
The `CDPSession` instances are used to talk raw Chrome Devtools Protocol:
|
The `CDPSession` instances are used to talk raw Chrome Devtools Protocol:
|
||||||
- protocol methods can be called with `session.send` method.
|
- protocol methods can be called with `session.send` method.
|
||||||
|
@ -46,7 +46,6 @@ class Page extends EventEmitter {
|
|||||||
await client.send('Page.enable');
|
await client.send('Page.enable');
|
||||||
const {frameTree} = await client.send('Page.getFrameTree');
|
const {frameTree} = await client.send('Page.getFrameTree');
|
||||||
const page = new Page(client, target, frameTree, ignoreHTTPSErrors, screenshotTaskQueue);
|
const page = new Page(client, target, frameTree, ignoreHTTPSErrors, screenshotTaskQueue);
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false, flatten: true}),
|
client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false, flatten: true}),
|
||||||
client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
|
client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
|
||||||
|
@ -14,18 +14,19 @@
|
|||||||
"unit": "node test/test.js",
|
"unit": "node test/test.js",
|
||||||
"debug-unit": "node --inspect-brk test/test.js",
|
"debug-unit": "node --inspect-brk test/test.js",
|
||||||
"test-doclint": "node utils/doclint/check_public_api/test/test.js && node utils/doclint/preprocessor/test.js",
|
"test-doclint": "node utils/doclint/check_public_api/test/test.js && node utils/doclint/preprocessor/test.js",
|
||||||
"test": "npm run lint --silent && npm run coverage && npm run test-doclint && npm run test-node6-transformer",
|
"test": "npm run lint --silent && npm run coverage && npm run test-doclint && npm run test-node6-transformer && npm run test-types",
|
||||||
"install": "node install.js",
|
"install": "node install.js",
|
||||||
"lint": "([ \"$CI\" = true ] && eslint --quiet -f codeframe . || eslint .) && npm run tsc && npm run doc",
|
"lint": "([ \"$CI\" = true ] && eslint --quiet -f codeframe . || eslint .) && npm run tsc && npm run doc",
|
||||||
"doc": "node utils/doclint/cli.js",
|
"doc": "node utils/doclint/cli.js",
|
||||||
"coverage": "cross-env COVERAGE=true npm run unit",
|
"coverage": "cross-env COVERAGE=true npm run unit",
|
||||||
"test-node6-transformer": "node utils/node6-transform/test/test.js",
|
"test-node6-transformer": "node utils/node6-transform/test/test.js",
|
||||||
"build": "node utils/node6-transform/index.js",
|
"build": "node utils/node6-transform/index.js && node utils/doclint/generate_types",
|
||||||
"unit-node6": "node node6/test/test.js",
|
"unit-node6": "node node6/test/test.js",
|
||||||
"tsc": "tsc -p .",
|
"tsc": "tsc -p .",
|
||||||
"prepublishOnly": "npm run build",
|
"prepublishOnly": "npm run build",
|
||||||
"apply-next-version": "node utils/apply_next_version.js",
|
"apply-next-version": "node utils/apply_next_version.js",
|
||||||
"bundle": "npx browserify -r ./index.js:puppeteer -o utils/browser/puppeteer-web.js",
|
"bundle": "npx browserify -r ./index.js:puppeteer -o utils/browser/puppeteer-web.js",
|
||||||
|
"test-types": "node utils/doclint/generate_types && npx -p typescript@2.1 tsc -p utils/doclint/generate_types/test/",
|
||||||
"unit-bundle": "node utils/browser/test.js"
|
"unit-bundle": "node utils/browser/test.js"
|
||||||
},
|
},
|
||||||
"author": "The Chromium Authors",
|
"author": "The Chromium Authors",
|
||||||
|
@ -31,8 +31,10 @@ Documentation.Class = class {
|
|||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @param {!Array<!Documentation.Member>} membersArray
|
* @param {!Array<!Documentation.Member>} membersArray
|
||||||
|
* @param {?string=} extendsName
|
||||||
|
* @param {string=} comment
|
||||||
*/
|
*/
|
||||||
constructor(name, membersArray) {
|
constructor(name, membersArray, extendsName = null, comment = '') {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.membersArray = membersArray;
|
this.membersArray = membersArray;
|
||||||
/** @type {!Map<string, !Documentation.Member>} */
|
/** @type {!Map<string, !Documentation.Member>} */
|
||||||
@ -43,6 +45,8 @@ Documentation.Class = class {
|
|||||||
this.methods = new Map();
|
this.methods = new Map();
|
||||||
/** @type {!Map<string, !Documentation.Member>} */
|
/** @type {!Map<string, !Documentation.Member>} */
|
||||||
this.events = new Map();
|
this.events = new Map();
|
||||||
|
this.comment = comment;
|
||||||
|
this.extends = extendsName;
|
||||||
for (const member of membersArray) {
|
for (const member of membersArray) {
|
||||||
this.members.set(member.name, member);
|
this.members.set(member.name, member);
|
||||||
if (member.kind === 'method')
|
if (member.kind === 'method')
|
||||||
@ -59,14 +63,17 @@ Documentation.Member = class {
|
|||||||
/**
|
/**
|
||||||
* @param {string} kind
|
* @param {string} kind
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @param {!Documentation.Type} type
|
* @param {?Documentation.Type} type
|
||||||
* @param {!Array<!Documentation.Member>} argsArray
|
* @param {!Array<!Documentation.Member>} argsArray
|
||||||
*/
|
*/
|
||||||
constructor(kind, name, type, argsArray) {
|
constructor(kind, name, type, argsArray, comment = '', returnComment = '', required = true) {
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.comment = comment;
|
||||||
|
this.returnComment = returnComment;
|
||||||
this.argsArray = argsArray;
|
this.argsArray = argsArray;
|
||||||
|
this.required = required;
|
||||||
/** @type {!Map<string, !Documentation.Member>} */
|
/** @type {!Map<string, !Documentation.Member>} */
|
||||||
this.args = new Map();
|
this.args = new Map();
|
||||||
for (const arg of argsArray)
|
for (const arg of argsArray)
|
||||||
@ -79,25 +86,29 @@ Documentation.Member = class {
|
|||||||
* @param {?Documentation.Type} returnType
|
* @param {?Documentation.Type} returnType
|
||||||
* @return {!Documentation.Member}
|
* @return {!Documentation.Member}
|
||||||
*/
|
*/
|
||||||
static createMethod(name, argsArray, returnType) {
|
static createMethod(name, argsArray, returnType, returnComment, comment) {
|
||||||
return new Documentation.Member('method', name, returnType, argsArray,);
|
return new Documentation.Member('method', name, returnType, argsArray, comment, returnComment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @param {!Documentation.Type}
|
* @param {!Documentation.Type} type
|
||||||
|
* @param {string=} comment
|
||||||
|
* @param {boolean=} required
|
||||||
* @return {!Documentation.Member}
|
* @return {!Documentation.Member}
|
||||||
*/
|
*/
|
||||||
static createProperty(name, type) {
|
static createProperty(name, type, comment, required) {
|
||||||
return new Documentation.Member('property', name, type, []);
|
return new Documentation.Member('property', name, type, [], comment, undefined, required);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
|
* @param {?Documentation.Type=} type
|
||||||
|
* @param {string=} comment
|
||||||
* @return {!Documentation.Member}
|
* @return {!Documentation.Member}
|
||||||
*/
|
*/
|
||||||
static createEvent(name) {
|
static createEvent(name, type = null, comment) {
|
||||||
return new Documentation.Member('event', name, null, []);
|
return new Documentation.Member('event', name, type, [], comment);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,57 +30,44 @@ class MDOutline {
|
|||||||
const writer = new commonmark.HtmlRenderer();
|
const writer = new commonmark.HtmlRenderer();
|
||||||
const html = writer.render(parsed);
|
const html = writer.render(parsed);
|
||||||
|
|
||||||
|
page.on('console', msg => {
|
||||||
|
console.log(msg.text());
|
||||||
|
});
|
||||||
// Extract headings.
|
// Extract headings.
|
||||||
await page.setContent(html);
|
await page.setContent(html);
|
||||||
const {classes, errors} = await page.evaluate(() => {
|
const {classes, errors} = await page.evaluate(() => {
|
||||||
const classes = [];
|
const classes = [];
|
||||||
let currentClass = {};
|
|
||||||
let member = {};
|
|
||||||
const errors = [];
|
const errors = [];
|
||||||
for (const element of document.body.querySelectorAll('h3, h4, h4 + ul > li')) {
|
const headers = document.body.querySelectorAll('h3');
|
||||||
if (element.matches('h3')) {
|
for (let i = 0; i < headers.length; i++) {
|
||||||
currentClass = {
|
const fragment = extractSiblingsIntoFragment(headers[i], headers[i + 1]);
|
||||||
name: element.textContent,
|
classes.push(parseClass(fragment));
|
||||||
members: [],
|
|
||||||
};
|
|
||||||
classes.push(currentClass);
|
|
||||||
} else if (element.matches('h4')) {
|
|
||||||
member = {
|
|
||||||
name: element.textContent,
|
|
||||||
args: [],
|
|
||||||
returnType: null
|
|
||||||
};
|
|
||||||
currentClass.members.push(member);
|
|
||||||
} else if (element.matches('li') && element.firstChild.matches && element.firstChild.matches('code')) {
|
|
||||||
member.args.push(parseProperty(element));
|
|
||||||
} else if (element.matches('li') && element.firstChild.nodeType === Element.TEXT_NODE && element.firstChild.textContent.toLowerCase().startsWith('return')) {
|
|
||||||
member.returnType = parseProperty(element);
|
|
||||||
const expectedText = 'returns: ';
|
|
||||||
let actualText = element.firstChild.textContent;
|
|
||||||
let angleIndex = actualText.indexOf('<');
|
|
||||||
let spaceIndex = actualText.indexOf(' ');
|
|
||||||
angleIndex = angleIndex === -1 ? actualText.length : angleIndex;
|
|
||||||
spaceIndex = spaceIndex === -1 ? actualText.length : spaceIndex + 1;
|
|
||||||
actualText = actualText.substring(0, Math.min(angleIndex, spaceIndex));
|
|
||||||
if (actualText !== expectedText)
|
|
||||||
errors.push(`${member.name} has mistyped 'return' type declaration: expected exactly '${expectedText}', found '${actualText}'.`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return {classes, errors};
|
return {classes, errors};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {HTMLLIElement} element
|
||||||
|
*/
|
||||||
function parseProperty(element) {
|
function parseProperty(element) {
|
||||||
const str = element.textContent;
|
const clone = element.cloneNode(true);
|
||||||
const name = str.substring(0, str.indexOf('<')).trim();
|
const ul = clone.querySelector(':scope > ul');
|
||||||
|
const str = parseComment(extractSiblingsIntoFragment(clone.firstChild, ul));
|
||||||
|
const name = str.substring(0, str.indexOf('<')).replace(/\`/g, '').trim();
|
||||||
const type = findType(str);
|
const type = findType(str);
|
||||||
const properties = [];
|
const properties = [];
|
||||||
|
const comment = str.substring(str.indexOf('<') + type.length + 2).trim();
|
||||||
// Strings have enum values instead of properties
|
// Strings have enum values instead of properties
|
||||||
if (!type.includes('string')) {
|
if (!type.includes('string')) {
|
||||||
for (const childElement of element.querySelectorAll(':scope > ul > li'))
|
for (const childElement of element.querySelectorAll(':scope > ul > li')) {
|
||||||
properties.push(parseProperty(childElement));
|
const property = parseProperty(childElement);
|
||||||
|
property.required = property.comment.includes('***required***');
|
||||||
|
properties.push(property);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
|
comment,
|
||||||
properties
|
properties
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -100,6 +87,107 @@ class MDOutline {
|
|||||||
}
|
}
|
||||||
return 'unknown';
|
return 'unknown';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {DocumentFragment} content
|
||||||
|
*/
|
||||||
|
function parseClass(content) {
|
||||||
|
const members = [];
|
||||||
|
const headers = content.querySelectorAll('h4');
|
||||||
|
const name = content.firstChild.textContent;
|
||||||
|
let extendsName = null;
|
||||||
|
let commentStart = content.firstChild.nextSibling;
|
||||||
|
const extendsElement = content.querySelector('ul');
|
||||||
|
if (extendsElement && extendsElement.textContent.trim().startsWith('extends:')) {
|
||||||
|
commentStart = extendsElement.nextSibling;
|
||||||
|
extendsName = extendsElement.querySelector('a').textContent;
|
||||||
|
}
|
||||||
|
const comment = parseComment(extractSiblingsIntoFragment(commentStart, headers[0]));
|
||||||
|
for (let i = 0; i < headers.length; i++) {
|
||||||
|
const fragment = extractSiblingsIntoFragment(headers[i], headers[i + 1]);
|
||||||
|
members.push(parseMember(fragment));
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
comment,
|
||||||
|
extendsName,
|
||||||
|
members
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Node} content
|
||||||
|
*/
|
||||||
|
function parseComment(content) {
|
||||||
|
for (const code of content.querySelectorAll('pre > code'))
|
||||||
|
code.replaceWith('```' + code.className.substring('language-'.length) + '\n' + code.textContent + '```');
|
||||||
|
for (const code of content.querySelectorAll('code'))
|
||||||
|
code.replaceWith('`' + code.textContent + '`');
|
||||||
|
for (const strong of content.querySelectorAll('strong'))
|
||||||
|
strong.replaceWith('**' + parseComment(strong) + '**');
|
||||||
|
return content.textContent.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
* @param {DocumentFragment} content
|
||||||
|
*/
|
||||||
|
function parseMember(content) {
|
||||||
|
const name = content.firstChild.textContent;
|
||||||
|
const args = [];
|
||||||
|
let returnType = null;
|
||||||
|
|
||||||
|
const paramRegex = /^\w+\.[\w$]+\((.*)\)$/;
|
||||||
|
const matches = paramRegex.exec(name) || ['', ''];
|
||||||
|
const parameters = matches[1];
|
||||||
|
const optionalStartIndex = parameters.indexOf('[');
|
||||||
|
const optinalParamsStr = optionalStartIndex !== -1 ? parameters.substring(optionalStartIndex).replace(/[\[\]]/g, '') : '';
|
||||||
|
const optionalparams = new Set(optinalParamsStr.split(',').filter(x => x).map(x => x.trim()));
|
||||||
|
const ul = content.querySelector('ul');
|
||||||
|
for (const element of content.querySelectorAll('h4 + ul > li')) {
|
||||||
|
if (element.matches('li') && element.textContent.trim().startsWith('<')) {
|
||||||
|
returnType = parseProperty(element);
|
||||||
|
} else if (element.matches('li') && element.firstChild.matches && element.firstChild.matches('code')) {
|
||||||
|
const property = parseProperty(element);
|
||||||
|
property.required = !optionalparams.has(property.name);
|
||||||
|
args.push(property);
|
||||||
|
} else if (element.matches('li') && element.firstChild.nodeType === Element.TEXT_NODE && element.firstChild.textContent.toLowerCase().startsWith('return')) {
|
||||||
|
returnType = parseProperty(element);
|
||||||
|
const expectedText = 'returns: ';
|
||||||
|
let actualText = element.firstChild.textContent;
|
||||||
|
let angleIndex = actualText.indexOf('<');
|
||||||
|
let spaceIndex = actualText.indexOf(' ');
|
||||||
|
angleIndex = angleIndex === -1 ? actualText.length : angleIndex;
|
||||||
|
spaceIndex = spaceIndex === -1 ? actualText.length : spaceIndex + 1;
|
||||||
|
actualText = actualText.substring(0, Math.min(angleIndex, spaceIndex));
|
||||||
|
if (actualText !== expectedText)
|
||||||
|
errors.push(`${name} has mistyped 'return' type declaration: expected exactly '${expectedText}', found '${actualText}'.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const comment = parseComment(extractSiblingsIntoFragment(ul ? ul.nextSibling : content));
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
args,
|
||||||
|
returnType,
|
||||||
|
comment
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Node} fromInclusive
|
||||||
|
* @param {!Node} toExclusive
|
||||||
|
* @return {!DocumentFragment}
|
||||||
|
*/
|
||||||
|
function extractSiblingsIntoFragment(fromInclusive, toExclusive) {
|
||||||
|
const fragment = document.createDocumentFragment();
|
||||||
|
let node = fromInclusive;
|
||||||
|
while (node && node !== toExclusive) {
|
||||||
|
const next = node.nextSibling;
|
||||||
|
fragment.appendChild(node);
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return new MDOutline(classes, errors);
|
return new MDOutline(classes, errors);
|
||||||
}
|
}
|
||||||
@ -114,11 +202,15 @@ class MDOutline {
|
|||||||
const eventRegex = /^event: '(\w+)'$/;
|
const eventRegex = /^event: '(\w+)'$/;
|
||||||
let currentClassName = null;
|
let currentClassName = null;
|
||||||
let currentClassMembers = [];
|
let currentClassMembers = [];
|
||||||
|
let currentClassComment = '';
|
||||||
|
let currentClassExtends = null;
|
||||||
for (const cls of classes) {
|
for (const cls of classes) {
|
||||||
const match = cls.name.match(classHeading);
|
const match = cls.name.match(classHeading);
|
||||||
if (!match)
|
if (!match)
|
||||||
continue;
|
continue;
|
||||||
currentClassName = match[1];
|
currentClassName = match[1];
|
||||||
|
currentClassComment = cls.comment;
|
||||||
|
currentClassExtends = cls.extendsName;
|
||||||
for (const member of cls.members) {
|
for (const member of cls.members) {
|
||||||
if (constructorRegex.test(member.name)) {
|
if (constructorRegex.test(member.name)) {
|
||||||
const match = member.name.match(constructorRegex);
|
const match = member.name.match(constructorRegex);
|
||||||
@ -147,15 +239,20 @@ class MDOutline {
|
|||||||
this.errors.push(`Heading arguments for "${member.name}" do not match described ones, i.e. "${parameters}" != "${member.args.map(a => a.name).join(', ')}"`);
|
this.errors.push(`Heading arguments for "${member.name}" do not match described ones, i.e. "${parameters}" != "${member.args.map(a => a.name).join(', ')}"`);
|
||||||
const args = member.args.map(createPropertyFromJSON);
|
const args = member.args.map(createPropertyFromJSON);
|
||||||
let returnType = null;
|
let returnType = null;
|
||||||
if (member.returnType)
|
let returnComment = '';
|
||||||
returnType = createPropertyFromJSON(member.returnType).type;
|
if (member.returnType) {
|
||||||
const method = Documentation.Member.createMethod(methodName, args, returnType);
|
const returnProperty = createPropertyFromJSON(member.returnType);
|
||||||
|
returnType = returnProperty.type;
|
||||||
|
returnComment = returnProperty.comment;
|
||||||
|
}
|
||||||
|
const method = Documentation.Member.createMethod(methodName, args, returnType, returnComment, member.comment);
|
||||||
currentClassMembers.push(method);
|
currentClassMembers.push(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPropertyFromJSON(payload) {
|
function createPropertyFromJSON(payload) {
|
||||||
const type = new Documentation.Type(payload.type, payload.properties.map(createPropertyFromJSON));
|
const type = new Documentation.Type(payload.type, payload.properties.map(createPropertyFromJSON));
|
||||||
return Documentation.Member.createProperty(payload.name, type);
|
const required = payload.required;
|
||||||
|
return Documentation.Member.createProperty(payload.name, type, payload.comment, required);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleProperty(member, className, propertyName) {
|
function handleProperty(member, className, propertyName) {
|
||||||
@ -163,7 +260,9 @@ 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;
|
||||||
}
|
}
|
||||||
currentClassMembers.push(Documentation.Member.createProperty(propertyName));
|
const type = member.returnType ? member.returnType.type : null;
|
||||||
|
const properties = member.returnType ? member.returnType.properties : [];
|
||||||
|
currentClassMembers.push(createPropertyFromJSON({type, name: propertyName, properties, comment: member.comment}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleEvent(member, eventName) {
|
function handleEvent(member, eventName) {
|
||||||
@ -171,13 +270,13 @@ class MDOutline {
|
|||||||
this.errors.push(`Failed to process header as event: ${member.name}`);
|
this.errors.push(`Failed to process header as event: ${member.name}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentClassMembers.push(Documentation.Member.createEvent(eventName));
|
currentClassMembers.push(Documentation.Member.createEvent(eventName, member.returnType && createPropertyFromJSON(member.returnType).type, member.comment));
|
||||||
}
|
}
|
||||||
|
|
||||||
function flushClassIfNeeded() {
|
function flushClassIfNeeded() {
|
||||||
if (currentClassName === null)
|
if (currentClassName === null)
|
||||||
return;
|
return;
|
||||||
this.classes.push(new Documentation.Class(currentClassName, currentClassMembers));
|
this.classes.push(new Documentation.Class(currentClassName, currentClassMembers, currentClassExtends, currentClassComment));
|
||||||
currentClassName = null;
|
currentClassName = null;
|
||||||
currentClassMembers = [];
|
currentClassMembers = [];
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
"name": "frame",
|
"name": "frame",
|
||||||
|
"type": {
|
||||||
|
"name": "[Frame]"
|
||||||
|
},
|
||||||
"kind": "event"
|
"kind": "event"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -25,6 +28,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "url",
|
"name": "url",
|
||||||
|
"type": {
|
||||||
|
"name": "string"
|
||||||
|
},
|
||||||
"kind": "property"
|
"kind": "property"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
217
utils/doclint/generate_types/index.js
Normal file
217
utils/doclint/generate_types/index.js
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const Source = require('../Source');
|
||||||
|
const puppeteer = require('../../..');
|
||||||
|
const PROJECT_DIR = path.join(__dirname, '..', '..', '..');
|
||||||
|
const fs = require('fs');
|
||||||
|
const objectDefinitions = [];
|
||||||
|
(async function() {
|
||||||
|
const browser = await puppeteer.launch();
|
||||||
|
const page = (await browser.pages())[0];
|
||||||
|
const api = await Source.readFile(path.join(PROJECT_DIR, 'docs', 'api.md'));
|
||||||
|
const {documentation} = await require('../check_public_api/MDBuilder')(page, [api]);
|
||||||
|
await browser.close();
|
||||||
|
const classes = documentation.classesArray.slice(1);
|
||||||
|
const root = documentation.classesArray[0];
|
||||||
|
const output = `// This file is generated by ${__filename.substring(path.join(__dirname, '..', '..').length)}
|
||||||
|
import { ChildProcess } from 'child_process';
|
||||||
|
import { EventEmitter } from 'events';
|
||||||
|
/**
|
||||||
|
* Can be converted to JSON
|
||||||
|
*/
|
||||||
|
interface Serializable {}
|
||||||
|
interface ConnectionTransport {}
|
||||||
|
|
||||||
|
${root.membersArray.map(member => `
|
||||||
|
${memberJSDOC(member, '')}export function ${member.name}${argsFromMember(member)} : ${typeToString(member.type, member.name)};
|
||||||
|
`).join('')}
|
||||||
|
${classes.map(classDesc => classToString(classDesc)).join('\n')}
|
||||||
|
${objectDefinitionsToString()}
|
||||||
|
`;
|
||||||
|
fs.writeFileSync(path.join(PROJECT_DIR, 'index.d.ts'), output, 'utf8');
|
||||||
|
})();
|
||||||
|
|
||||||
|
function objectDefinitionsToString() {
|
||||||
|
let definition;
|
||||||
|
const parts = [];
|
||||||
|
while ((definition = objectDefinitions.pop())) {
|
||||||
|
const {name, properties} = definition;
|
||||||
|
parts.push(`interface ${name} {`);
|
||||||
|
parts.push(properties.map(member => ` ${memberJSDOC(member, ' ')}${nameForProperty(member)}${argsFromMember(member, name)}: ${typeToString(member.type, name, member.name)};`).join('\n\n'));
|
||||||
|
parts.push('}\n');
|
||||||
|
}
|
||||||
|
return parts.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
function nameForProperty(member) {
|
||||||
|
return (member.required || member.name.startsWith('...')) ? member.name : member.name + '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('./check_public_api/Documentation').Class} classDesc
|
||||||
|
*/
|
||||||
|
function classToString(classDesc) {
|
||||||
|
const parts = [];
|
||||||
|
if (classDesc.comment) {
|
||||||
|
parts.push(`/**
|
||||||
|
* ${classDesc.comment.split('\n').join('\n * ')}
|
||||||
|
*/`);
|
||||||
|
}
|
||||||
|
parts.push(`export interface ${classDesc.name} ${classDesc.extends ? `extends ${classDesc.extends} ` : ''}{`);
|
||||||
|
for (const method of ['on', 'once', 'addListener']) {
|
||||||
|
for (const [eventName, value] of classDesc.events) {
|
||||||
|
if (value.comment) {
|
||||||
|
parts.push(' /**');
|
||||||
|
parts.push(...value.comment.split('\n').map(line => ' * ' + line));
|
||||||
|
parts.push(' */');
|
||||||
|
}
|
||||||
|
parts.push(` ${method}(event: '${eventName}', listener: (arg0 : ${typeToString(value && value.type, classDesc.name, eventName, 'payload')}) => void): this;\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parts.push(classDesc.membersArray.map(member => ` ${memberJSDOC(member, ' ')}${member.name}${argsFromMember(member, classDesc.name)}: ${typeToString(member.type, classDesc.name, member.name)};`).join('\n\n'));
|
||||||
|
parts.push('}\n');
|
||||||
|
return parts.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('./check_public_api/Documentation').Type} type
|
||||||
|
*/
|
||||||
|
function typeToString(type, ...namespace) {
|
||||||
|
if (!type)
|
||||||
|
return 'void';
|
||||||
|
let typeString = stringifyType(parseType(type.name));
|
||||||
|
for (let i = 0; i < type.properties.length; i++)
|
||||||
|
typeString = typeString.replace('arg' + i, type.properties[i].name);
|
||||||
|
if (type.properties.length && typeString.indexOf('Object') !== -1) {
|
||||||
|
const name = namespace.map(n => n[0].toUpperCase() + n.substring(1)).join('');
|
||||||
|
typeString = typeString.replace('Object', name);
|
||||||
|
objectDefinitions.push({name, properties: type.properties});
|
||||||
|
}
|
||||||
|
return typeString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} type
|
||||||
|
*/
|
||||||
|
function parseType(type) {
|
||||||
|
type = type.trim();
|
||||||
|
if (type.startsWith('?')) {
|
||||||
|
const parsed = parseType(type.substring(1));
|
||||||
|
parsed.nullable = true;
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
if (type.startsWith('...'))
|
||||||
|
return parseType('Array<' + type.substring(3) + '>');
|
||||||
|
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 = parseType(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 = parseType(type.substring(i + 1, i + matching - 1));
|
||||||
|
i = i + matching;
|
||||||
|
if (type[i] === ':') {
|
||||||
|
retType = parseType(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 pipe = null;
|
||||||
|
if (type[firstTypeLength] === '|')
|
||||||
|
pipe = parseType(type.substring(firstTypeLength + 1));
|
||||||
|
else if (type[firstTypeLength] === ',')
|
||||||
|
next = parseType(type.substring(firstTypeLength + 1));
|
||||||
|
if (name === 'Promise' && !template)
|
||||||
|
template = parseType('void');
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
args,
|
||||||
|
retType,
|
||||||
|
template,
|
||||||
|
pipe,
|
||||||
|
next
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyType(parsedType) {
|
||||||
|
if (!parsedType)
|
||||||
|
return 'void';
|
||||||
|
let out = parsedType.name;
|
||||||
|
if (parsedType.args) {
|
||||||
|
let args = parsedType.args;
|
||||||
|
const stringArgs = [];
|
||||||
|
while (args) {
|
||||||
|
const arg = args;
|
||||||
|
args = args.next;
|
||||||
|
arg.next = null;
|
||||||
|
stringArgs.push(stringifyType(arg));
|
||||||
|
}
|
||||||
|
out = `(${stringArgs.map((type, index) => `arg${index} : ${type}`).join(', ')}, ...args: any[]) => ${stringifyType(parsedType.retType)}`;
|
||||||
|
} else if (parsedType.name === 'function') {
|
||||||
|
out = 'Function';
|
||||||
|
}
|
||||||
|
if (parsedType.nullable)
|
||||||
|
out = 'null|' + out;
|
||||||
|
if (parsedType.template)
|
||||||
|
out += '<' + stringifyType(parsedType.template) + '>';
|
||||||
|
if (parsedType.pipe)
|
||||||
|
out += '|' + stringifyType(parsedType.pipe);
|
||||||
|
if (parsedType.next)
|
||||||
|
out += ', ' + stringifyType(parsedType.next);
|
||||||
|
return out.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('./check_public_api/Documentation').Member} member
|
||||||
|
*/
|
||||||
|
function argsFromMember(member, ...namespace) {
|
||||||
|
if (member.kind === 'property')
|
||||||
|
return '';
|
||||||
|
return '(' + member.argsArray.map(arg => `${nameForProperty(arg)}: ${typeToString(arg.type, ...namespace, member.name, 'options')}`).join(', ') + ')';
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {import('./check_public_api/Documentation').Member} member
|
||||||
|
*/
|
||||||
|
function memberJSDOC(member, indent) {
|
||||||
|
const lines = [];
|
||||||
|
if (member.comment)
|
||||||
|
lines.push(...member.comment.split('\n'));
|
||||||
|
lines.push(...member.argsArray.map(arg => `@param ${arg.name.replace(/\./g, '')} ${arg.comment.replace('\n', ' ')}`));
|
||||||
|
if (member.returnComment)
|
||||||
|
lines.push(`@returns ${member.returnComment}`);
|
||||||
|
if (!lines.length)
|
||||||
|
return '';
|
||||||
|
return `/**
|
||||||
|
${indent} * ${lines.join('\n' + indent + ' * ')}
|
||||||
|
${indent} */
|
||||||
|
${indent}`;
|
||||||
|
}
|
283
utils/doclint/generate_types/test/test.ts
Normal file
283
utils/doclint/generate_types/test/test.ts
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
import * as puppeteer from "../../../../index";
|
||||||
|
|
||||||
|
// Examples taken from README
|
||||||
|
(async () => {
|
||||||
|
const browser = await puppeteer.launch();
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.goto("https://example.com");
|
||||||
|
await page.screenshot({ path: "example.png" });
|
||||||
|
|
||||||
|
browser.close();
|
||||||
|
})();
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const browser = await puppeteer.launch();
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.goto("https://news.ycombinator.com", { waitUntil: "networkidle0" });
|
||||||
|
await page.pdf({ path: "hn.pdf", format: "A4" });
|
||||||
|
|
||||||
|
browser.close();
|
||||||
|
})();
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const browser = await puppeteer.launch();
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.goto("https://example.com");
|
||||||
|
|
||||||
|
// Get the "viewport" of the page, as reported by the page.
|
||||||
|
const dimensions = await page.evaluate(() => {
|
||||||
|
return {
|
||||||
|
width: document.documentElement.clientWidth,
|
||||||
|
height: document.documentElement.clientHeight,
|
||||||
|
deviceScaleFactor: window.devicePixelRatio
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Dimensions:", dimensions);
|
||||||
|
|
||||||
|
browser.close();
|
||||||
|
})();
|
||||||
|
|
||||||
|
// The following examples are taken from the docs itself
|
||||||
|
puppeteer.launch().then(async browser => {
|
||||||
|
const page = await browser.newPage();
|
||||||
|
page.on("console", (...args: any[]) => {
|
||||||
|
for (let i = 0; i < args.length; ++i) console.log(`${i}: ${args[i]}`);
|
||||||
|
});
|
||||||
|
page.evaluate(() => console.log(5, "hello", { foo: "bar" }));
|
||||||
|
|
||||||
|
const result = await page.evaluate(() => {
|
||||||
|
return Promise.resolve(8 * 7);
|
||||||
|
});
|
||||||
|
console.log(await page.evaluate("1 + 2"));
|
||||||
|
|
||||||
|
const bodyHandle = await page.$("body");
|
||||||
|
|
||||||
|
// Typings for this are really difficult since they depend on internal state
|
||||||
|
// of the page class.
|
||||||
|
const html = await page.evaluate(
|
||||||
|
(body: HTMLElement) => body.innerHTML,
|
||||||
|
bodyHandle
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
import * as crypto from "crypto";
|
||||||
|
import * as fs from "fs";
|
||||||
|
|
||||||
|
puppeteer.launch().then(async browser => {
|
||||||
|
const page = await browser.newPage();
|
||||||
|
page.on("console", console.log);
|
||||||
|
await page.exposeFunction("md5", (text: string) =>
|
||||||
|
crypto
|
||||||
|
.createHash("md5")
|
||||||
|
.update(text)
|
||||||
|
.digest("hex")
|
||||||
|
);
|
||||||
|
await page.evaluate(async () => {
|
||||||
|
// use window.md5 to compute hashes
|
||||||
|
const myString = "PUPPETEER";
|
||||||
|
const myHash = await (window as any).md5(myString);
|
||||||
|
console.log(`md5 of ${myString} is ${myHash}`);
|
||||||
|
});
|
||||||
|
browser.close();
|
||||||
|
|
||||||
|
page.on("console", console.log);
|
||||||
|
await page.exposeFunction("readfile", async (filePath: string) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fs.readFile(filePath, "utf8", (err, text) => {
|
||||||
|
if (err) reject(err);
|
||||||
|
else resolve(text);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
await page.evaluate(async () => {
|
||||||
|
// use window.readfile to read contents of a file
|
||||||
|
const content = await (window as any).readfile("/etc/hosts");
|
||||||
|
console.log(content);
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.emulateMedia("screen");
|
||||||
|
await page.pdf({ path: "page.pdf" });
|
||||||
|
|
||||||
|
await page.setRequestInterception(true);
|
||||||
|
page.on("request", interceptedRequest => {
|
||||||
|
if (
|
||||||
|
interceptedRequest.url().endsWith(".png") ||
|
||||||
|
interceptedRequest.url().endsWith(".jpg")
|
||||||
|
)
|
||||||
|
interceptedRequest.abort();
|
||||||
|
else interceptedRequest.continue();
|
||||||
|
});
|
||||||
|
|
||||||
|
page.keyboard.type("Hello"); // Types instantly
|
||||||
|
page.keyboard.type("World", { delay: 100 }); // Types slower, like a user
|
||||||
|
|
||||||
|
const watchDog = page.waitForFunction("window.innerWidth < 100");
|
||||||
|
page.setViewport({ width: 50, height: 50 });
|
||||||
|
await watchDog;
|
||||||
|
|
||||||
|
let currentURL: string;
|
||||||
|
page
|
||||||
|
.waitForSelector("img", { visible: true })
|
||||||
|
.then(() => console.log("First URL with image: " + currentURL));
|
||||||
|
for (currentURL of [
|
||||||
|
"https://example.com",
|
||||||
|
"https://google.com",
|
||||||
|
"https://bbc.com"
|
||||||
|
]) {
|
||||||
|
await page.goto(currentURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
page.keyboard.type("Hello World!");
|
||||||
|
page.keyboard.press("ArrowLeft");
|
||||||
|
|
||||||
|
page.keyboard.down("Shift");
|
||||||
|
// tslint:disable-next-line prefer-for-of
|
||||||
|
for (let i = 0; i < " World".length; i++) {
|
||||||
|
page.keyboard.press("ArrowLeft");
|
||||||
|
}
|
||||||
|
page.keyboard.up("Shift");
|
||||||
|
page.keyboard.press("Backspace");
|
||||||
|
page.keyboard.sendCharacter("嗨");
|
||||||
|
|
||||||
|
await page.tracing.start({ path: "trace.json" });
|
||||||
|
await page.goto("https://www.google.com");
|
||||||
|
await page.tracing.stop();
|
||||||
|
|
||||||
|
page.on("dialog", async dialog => {
|
||||||
|
console.log(dialog.message());
|
||||||
|
await dialog.dismiss();
|
||||||
|
browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
const inputElement = (await page.$("input[type=submit]"))!;
|
||||||
|
await inputElement.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Example with launch options
|
||||||
|
(async () => {
|
||||||
|
const browser = await puppeteer.launch({
|
||||||
|
args: [
|
||||||
|
'--no-sandbox',
|
||||||
|
'--disable-setuid-sandbox',
|
||||||
|
],
|
||||||
|
handleSIGINT: true,
|
||||||
|
handleSIGHUP: true,
|
||||||
|
handleSIGTERM: true,
|
||||||
|
});
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.goto("https://example.com");
|
||||||
|
await page.screenshot({ path: "example.png" });
|
||||||
|
|
||||||
|
browser.close();
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Test v0.12 features
|
||||||
|
(async () => {
|
||||||
|
const browser = await puppeteer.launch({
|
||||||
|
devtools: true,
|
||||||
|
env: {
|
||||||
|
JEST_TEST: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const page = await browser.newPage();
|
||||||
|
const button = (await page.$("#myButton"))!;
|
||||||
|
const div = (await page.$("#myDiv"))!;
|
||||||
|
const input = (await page.$("#myInput"))!;
|
||||||
|
|
||||||
|
if (!button)
|
||||||
|
throw new Error('Unable to select myButton');
|
||||||
|
|
||||||
|
if (!input)
|
||||||
|
throw new Error('Unable to select myInput');
|
||||||
|
|
||||||
|
await page.addStyleTag({
|
||||||
|
url: "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(page.url());
|
||||||
|
|
||||||
|
page.type("#myInput", "Hello World!");
|
||||||
|
|
||||||
|
page.on("console", (event: puppeteer.ConsoleMessage, ...args: any[]) => {
|
||||||
|
console.log(event.text, event.type);
|
||||||
|
for (let i = 0; i < args.length; ++i) console.log(`${i}: ${args[i]}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
await button.focus();
|
||||||
|
await button.press("Enter");
|
||||||
|
await button.screenshot({
|
||||||
|
type: "jpeg",
|
||||||
|
omitBackground: true,
|
||||||
|
clip: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 200,
|
||||||
|
height: 100
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(button.toString());
|
||||||
|
input.type("Hello World", { delay: 10 });
|
||||||
|
|
||||||
|
const buttonText = await (await button.getProperty('textContent')).jsonValue();
|
||||||
|
|
||||||
|
await page.deleteCookie(...await page.cookies());
|
||||||
|
|
||||||
|
const metrics = await page.metrics();
|
||||||
|
console.log(metrics.Documents, metrics.Frames, metrics.JSEventListeners);
|
||||||
|
|
||||||
|
const navResponse = await page.waitForNavigation({
|
||||||
|
timeout: 1000
|
||||||
|
});
|
||||||
|
console.log(navResponse.ok, navResponse.status, navResponse.url, navResponse.headers);
|
||||||
|
|
||||||
|
// evaluate example
|
||||||
|
const bodyHandle = (await page.$('body'))!;
|
||||||
|
const html = await page.evaluate((body : HTMLBodyElement) => body.innerHTML, bodyHandle);
|
||||||
|
await bodyHandle.dispose();
|
||||||
|
|
||||||
|
// getProperties example
|
||||||
|
const handle = await page.evaluateHandle(() => ({ window, document }));
|
||||||
|
const properties = await handle.getProperties();
|
||||||
|
const windowHandle = properties.get('window');
|
||||||
|
const documentHandle = properties.get('document');
|
||||||
|
await handle.dispose();
|
||||||
|
|
||||||
|
// queryObjects example
|
||||||
|
// Create a Map object
|
||||||
|
await page.evaluate(() => (window as any).map = new Map());
|
||||||
|
// Get a handle to the Map object prototype
|
||||||
|
const mapPrototype = await page.evaluateHandle(() => Map.prototype);
|
||||||
|
// Query all map instances into an array
|
||||||
|
const mapInstances = await page.queryObjects(mapPrototype);
|
||||||
|
// Count amount of map objects in heap
|
||||||
|
const count = await page.evaluate((maps: Map<any, any>[]) => maps.length, mapInstances);
|
||||||
|
await mapInstances.dispose();
|
||||||
|
await mapPrototype.dispose();
|
||||||
|
|
||||||
|
// evaluateHandle example
|
||||||
|
const aHandle = await page.evaluateHandle(() => document.body);
|
||||||
|
const resultHandle = await page.evaluateHandle((body: Element) => body.innerHTML, aHandle);
|
||||||
|
console.log(await resultHandle.jsonValue());
|
||||||
|
await resultHandle.dispose();
|
||||||
|
|
||||||
|
browser.close();
|
||||||
|
})();
|
||||||
|
|
||||||
|
// test $eval and $$eval
|
||||||
|
(async () => {
|
||||||
|
const browser = await puppeteer.launch();
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.goto("https://example.com");
|
||||||
|
await page.$eval('#someElement', (element, text: string) => {
|
||||||
|
return element.innerHTML = text;
|
||||||
|
}, 'hey');
|
||||||
|
|
||||||
|
let elementText = await page.$$eval('.someClassName', (elements) => {
|
||||||
|
console.log(elements.length);
|
||||||
|
console.log(elements.map(x => x)[0].textContent);
|
||||||
|
return elements[3].innerHTML;
|
||||||
|
});
|
||||||
|
|
||||||
|
browser.close();
|
||||||
|
})();
|
11
utils/doclint/generate_types/test/tsconfig.json
Normal file
11
utils/doclint/generate_types/test/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"target": "es2015",
|
||||||
|
"noEmit": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"test.ts",
|
||||||
|
"../../../../index.d.ts"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user