feat: support inner types for things like Promise<Boolean>
This commit is contained in:
Родитель
a6444d7682
Коммит
3ba4721268
|
@ -4,20 +4,39 @@ const cheerio = require('cheerio')
|
|||
const cleanDeep = require('clean-deep')
|
||||
const entities = require('entities')
|
||||
|
||||
const parameterPattern = /<code>((?:...)?\w+?)<\/code>\s*(\(?(?:(?:(?:<a href.*?>)?[a-zA-Z0-9[\]]+(?:<\/a>)?(?: \| )?)+)\)?(?:\[])?)(?: - )?([\s\S]*)/m
|
||||
const parameterPattern = /<code>((?:...)?\w+?)<\/code>\s*(\(?(?:(?:(?:<a href.*?>)?[a-zA-Z0-9[\]]+(?:<(?:[a-zA-Z[\]]+(?: \| )?)+>)?(?:<\/a>)?(?: \| )?)+)\)?(?:\[])?)(?: - )?([\s\S]*)/m
|
||||
const methodReturnPattern = /^Returns (<a.+?>)?<code>(.*?)<\/code>(<\/a>)?/g
|
||||
const multiTypePattern = /(?:<a href.*?>)?([a-zA-Z0-9[\]]+)(?:<\/a>)?(?: \| )?/mg
|
||||
const multiTypePattern = /(?:<a href.*?>)?([a-zA-Z0-9[\]]+(?:<(?:[a-zA-Z[\]]+(?: \| )?)+>)?)(?:<\/a>)?(?: \| )?/mg
|
||||
const innerTypePattern = /([a-zA-Z0-9]+)(?:<(.+)>)?/g
|
||||
|
||||
const stripArrTags = (type) => {
|
||||
if (Array.isArray(type)) {
|
||||
return type.map(typeName => ({
|
||||
typeName: stripArrTags(typeName),
|
||||
collection: typeName.endsWith('[]') || (typeof multitypify(typeName) === 'string' && multitypify(typeName).endsWith('[]'))
|
||||
}))
|
||||
return type.map(typeName => {
|
||||
const typeInfo = getInnerType(stripArrTags(typeName))
|
||||
return {
|
||||
typeName: typeInfo.outer,
|
||||
collection: typeName.endsWith('[]') || (typeof multitypify(typeName) === 'string' && multitypify(typeName).endsWith('[]')),
|
||||
innerType: typeInfo.inner
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return type.endsWith('[]') ? type.substr(0, type.length - 2) : type
|
||||
}
|
||||
}
|
||||
const getInnerType = (type) => {
|
||||
if (typeof type === 'string') {
|
||||
innerTypePattern.lastIndex = 0
|
||||
const execResult = innerTypePattern.exec(type)
|
||||
const outer = execResult[1]
|
||||
if (!outer) throw new Error('Outer type should never be null but it was for: ' + type)
|
||||
var inner = execResult[2]
|
||||
if (inner) {
|
||||
inner = stripArrTags(multitypify(inner))
|
||||
}
|
||||
return { outer, inner }
|
||||
}
|
||||
return { outer: type, inner: undefined }
|
||||
}
|
||||
const multitypify = (fullTypeString) => {
|
||||
let typeString = fullTypeString
|
||||
if (typeString.startsWith('(') && typeString.endsWith(')')) {
|
||||
|
@ -97,7 +116,7 @@ const getPossibleValues = ($, el, description, api) => {
|
|||
const generateObjectProps = ($, topUL, api) => {
|
||||
return topUL.find('> li')
|
||||
.map((i, el) => {
|
||||
var match = $(el).html().match(parameterPattern)
|
||||
var match = entities.decodeHTML($(el).html()).match(parameterPattern)
|
||||
if (!match) {
|
||||
console.error('parameter subproperties')
|
||||
console.error(`parameterPattern: ${parameterPattern}`)
|
||||
|
@ -115,10 +134,12 @@ const generateObjectProps = ($, topUL, api) => {
|
|||
.filter(function () { return this.type === 'text' || (this.type === 'tag' && this.name === 'code') }) // avoid nested ULs
|
||||
.text()
|
||||
|
||||
const typeInfo = getInnerType(stripArrTags(multitypify(match[2])))
|
||||
const ret = {
|
||||
name: match[1],
|
||||
type: stripArrTags(multitypify(match[2])),
|
||||
type: typeInfo.outer,
|
||||
collection: match[2].endsWith('[]') || (typeof multitypify(match[2]) === 'string' && multitypify(match[2]).endsWith('[]')),
|
||||
innerType: typeInfo.inner,
|
||||
description: sanitizeDescription(description),
|
||||
required: !description.match(/\(optional\)/i)
|
||||
}
|
||||
|
@ -157,6 +178,7 @@ const generateObjectProps = ($, topUL, api) => {
|
|||
module.exports = {
|
||||
stripArrTags,
|
||||
generateObjectProps,
|
||||
getInnerType,
|
||||
// Find all paragraphs in a swath
|
||||
description: ($, openingHeadingElement) =>
|
||||
textify($, swath($, openingHeadingElement)
|
||||
|
@ -176,7 +198,7 @@ module.exports = {
|
|||
let properties
|
||||
|
||||
if (returnText) {
|
||||
type = methodReturnPattern.exec(returnHTML)[2]
|
||||
type = entities.decodeHTML(methodReturnPattern.exec(returnHTML)[2])
|
||||
description = returnText.split(`Returns ${type}`)[1].replace(/^ - /g, '').replace(/^:/g, '').trim()
|
||||
}
|
||||
if (type === 'Object') {
|
||||
|
@ -195,9 +217,11 @@ module.exports = {
|
|||
if (type === 'String') {
|
||||
possibleValues = getPossibleValues($, returnPara, sanitizeDescription(preserveBackTicks($(returnPara).html())), api)
|
||||
}
|
||||
const typeInfo = getInnerType(stripArrTags(multitypify(type)))
|
||||
const ret = {
|
||||
type: stripArrTags(multitypify(type)),
|
||||
type: typeInfo.outer,
|
||||
collection: type.endsWith('[]') || (typeof multitypify(type) === 'string' && multitypify(type).endsWith('[]')),
|
||||
innerType: typeInfo.inner,
|
||||
description,
|
||||
properties,
|
||||
possibleValues
|
||||
|
@ -229,7 +253,7 @@ module.exports = {
|
|||
.first()
|
||||
.find('> li')
|
||||
.map((i, el) => {
|
||||
var match = $(el).html()
|
||||
var match = entities.decodeHTML($(el).html())
|
||||
.match(parameterPattern)
|
||||
|
||||
// Parsing error
|
||||
|
@ -249,10 +273,12 @@ module.exports = {
|
|||
.filter(function () { return this.type === 'text' }) // avoid nested ULs
|
||||
.text()
|
||||
|
||||
const typeInfo = getInnerType(stripArrTags(multitypify(match[2])))
|
||||
var arg = {
|
||||
name: match[1],
|
||||
type: stripArrTags(multitypify(match[2])),
|
||||
type: typeInfo.outer,
|
||||
collection: match[2].endsWith('[]') || (typeof multitypify(match[2]) === 'string' && multitypify(match[2]).endsWith('[]')),
|
||||
innerType: typeInfo.inner,
|
||||
description: sanitizeDescription(description),
|
||||
required: !description.match(/\(optional\)/i)
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ const CollectionItem = require('./collection-item')
|
|||
const parsers = require('./parsers')
|
||||
|
||||
const pattern = /<code>.*?\.(?:(\w+)\.)?(\w+)<\/code>/
|
||||
const typePattern = /An? ([a-zA-Z]+(?:\[])?) ?/
|
||||
const props = ['name', 'description', 'type', 'collection', '_superObject']
|
||||
const typePattern = /An? ([a-zA-Z]+(?:<[a-zA-Z[\]]+>)?(?:\[])?) ?/
|
||||
const props = ['name', 'description', 'type', 'innerType', 'collection', '_superObject']
|
||||
|
||||
module.exports = class Property extends CollectionItem {
|
||||
constructor (api, el) {
|
||||
|
@ -18,7 +18,9 @@ module.exports = class Property extends CollectionItem {
|
|||
this.type = null
|
||||
const typeMatch = typePattern.exec(this.description)
|
||||
if (typeMatch) {
|
||||
this.type = parsers.stripArrTags(typeMatch[1])
|
||||
const typeInfo = parsers.getInnerType(parsers.stripArrTags(typeMatch[1]))
|
||||
this.type = typeInfo.outer
|
||||
this.innerType = typeInfo.inner
|
||||
this.collection = typeMatch[1].endsWith('[]')
|
||||
}
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -517,7 +517,7 @@ The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally
|
|||
* `path` String (optional) _Windows_ - Defaults to `process.execPath`
|
||||
* `args` String[] (optional) _Windows_ - Defaults to an empty array
|
||||
|
||||
Returns `Boolean` - Whether the call succeeded.
|
||||
Returns `Promise<Boolean | null | Point | Rect[]>` - Whether the call succeeded.
|
||||
|
||||
This method checks if the current executable as the default handler for a
|
||||
protocol (aka URI scheme). If so, it will remove the app as the default handler.
|
||||
|
@ -525,11 +525,11 @@ protocol (aka URI scheme). If so, it will remove the app as the default handler.
|
|||
|
||||
### `app.isDefaultProtocolClient(protocol[, path, args])` _macOS_ _Windows_
|
||||
|
||||
* `protocol` String - The name of your protocol, without `://`.
|
||||
* `protocol` Promise<String> - The name of your protocol, without `://`.
|
||||
* `path` String (optional) _Windows_ - Defaults to `process.execPath`
|
||||
* `args` String[] (optional) _Windows_ - Defaults to an empty array
|
||||
|
||||
Returns `Boolean`
|
||||
Returns `Promise<boolean>`
|
||||
|
||||
This method checks if the current executable is the default handler for a protocol
|
||||
(aka URI scheme). If so, it will return true. Otherwise, it will return false.
|
||||
|
|
|
@ -573,7 +573,7 @@ events.
|
|||
|
||||
#### `win.id`
|
||||
|
||||
A `Integer` representing the unique ID of the window.
|
||||
A `Promise<Integer>` representing the unique ID of the window.
|
||||
|
||||
### Instance Methods
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ The `screen` module has the following methods:
|
|||
|
||||
Returns `Object`:
|
||||
|
||||
* `x` Integer
|
||||
* `x` Promise<Integer>
|
||||
* `y` Integer
|
||||
|
||||
The current absolute position of the mouse pointer.
|
||||
|
|
|
@ -159,6 +159,39 @@ describe('APIs', function () {
|
|||
expect(method.description).to.exist
|
||||
})
|
||||
})
|
||||
|
||||
they('can return promises with inner types', function () {
|
||||
expect(apis.app.methods.isDefaultProtocolClient).to.exist
|
||||
expect(apis.app.methods.isDefaultProtocolClient.returns.type).to.eq('Promise')
|
||||
expect(apis.app.methods.isDefaultProtocolClient.returns.innerType).to.eq('boolean')
|
||||
})
|
||||
|
||||
they('can return promises with complex inner types', function () {
|
||||
expect(apis.app.methods.removeAsDefaultProtocolClient).to.exist
|
||||
expect(apis.app.methods.removeAsDefaultProtocolClient.returns.type).to.eq('Promise')
|
||||
expect(apis.app.methods.removeAsDefaultProtocolClient.returns.innerType).to.deep.eq([
|
||||
{
|
||||
collection: false,
|
||||
innerType: undefined,
|
||||
typeName: 'Boolean'
|
||||
},
|
||||
{
|
||||
collection: false,
|
||||
innerType: undefined,
|
||||
typeName: 'null'
|
||||
},
|
||||
{
|
||||
collection: false,
|
||||
innerType: undefined,
|
||||
typeName: 'Point'
|
||||
},
|
||||
{
|
||||
collection: true,
|
||||
innerType: undefined,
|
||||
typeName: 'Rect'
|
||||
}
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Parameters', function () {
|
||||
|
@ -255,9 +288,11 @@ describe('APIs', function () {
|
|||
expect(param.type).to.be.an('array')
|
||||
expect(param.type).to.deep.equal([{
|
||||
typeName: 'String',
|
||||
innerType: undefined,
|
||||
collection: false
|
||||
}, {
|
||||
typeName: 'Buffer',
|
||||
innerType: undefined,
|
||||
collection: false
|
||||
}])
|
||||
})
|
||||
|
@ -269,6 +304,12 @@ describe('APIs', function () {
|
|||
expect(param.type[1].typeName).to.equal('null')
|
||||
expect(param, 'should have function parameters').to.have.property('parameters')
|
||||
})
|
||||
|
||||
they('can be promises with inner types', function () {
|
||||
var param = apis.app.methods.isDefaultProtocolClient.parameters[0]
|
||||
expect(param.type).to.eq('Promise')
|
||||
expect(param.innerType).to.eq('String')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Static Methods', function () {
|
||||
|
@ -360,6 +401,12 @@ describe('APIs', function () {
|
|||
they('are marked `required` for super objects', function () {
|
||||
apis.app.properties.forEach(prop => expect(prop.required).to.equal(true))
|
||||
})
|
||||
|
||||
they('can be promises with inner types', function () {
|
||||
var prop = apis.BrowserWindow.instanceProperties.id
|
||||
expect(prop.type).to.eq('Promise')
|
||||
expect(prop.innerType).to.eq('Integer')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Instance Properties', function () {
|
||||
|
@ -393,8 +440,8 @@ describe('APIs', function () {
|
|||
expect(props[0].description).to.include('object this window owns')
|
||||
expect(props[0].type).to.equal('WebContents')
|
||||
expect(props[1].name).to.equal('id')
|
||||
expect(props[1].description).to.equal('A Integer representing the unique ID of the window.')
|
||||
expect(props[1].type).to.equal('Integer')
|
||||
expect(props[1].description).to.equal('A Promise<Integer> representing the unique ID of the window.')
|
||||
expect(props[1].type).to.equal('Promise')
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -500,6 +547,16 @@ describe('APIs', function () {
|
|||
expect(method.returns.properties[1].type).to.equal('JumpListItem')
|
||||
expect(method.returns.properties[1].collection).to.equal(true)
|
||||
})
|
||||
|
||||
it('resolve promises in deep objects as return values', function () {
|
||||
const method = apis.screen.methods.getCursorScreenPoint
|
||||
expect(method.returns.type).to.equal('Object')
|
||||
expect(method.returns.properties.length).to.equal(2)
|
||||
const prop = method.returns.properties[0]
|
||||
expect(prop.name).to.eq('x')
|
||||
expect(prop.type).to.eq('Promise')
|
||||
expect(prop.innerType).to.eq('Integer')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Returns', function () {
|
||||
|
|
Загрузка…
Ссылка в новой задаче