electron-docs-linter/index.js

112 строки
3.4 KiB
JavaScript
Executable File

const path = require('path')
const API = require('./lib/api')
const fetchDocs = require('electron-docs')
const promisify = require('pify')
const semver = require('semver')
const exists = require('path-exists').sync
const keyedArray = require('keyed-array')
function remapTouchBar (apis) {
const newApis = []
const touchBarApis = []
var touchBarApi
apis.forEach((api) => {
if (api.name.substr(0, 8) === 'TouchBar' && api.name !== 'TouchBar') {
touchBarApis.push(api)
} else if (api.name === 'TouchBar') {
touchBarApi = api
newApis.push(touchBarApi)
} else {
newApis.push(api)
}
})
if (touchBarApi) touchBarApi.staticProperties = touchBarApis
return newApis
}
function lint (docsPath, targetVersion, callback) {
if (typeof callback !== 'function') {
throw new TypeError('Expected a callback function as third argument')
}
if (!semver.valid(targetVersion)) {
throw new TypeError(`\`targetVersion\` must be a valid version number. Got: ${targetVersion}`)
}
if (!exists(docsPath)) {
throw new TypeError(`\`path\` must be an existing path on the filesystem. Got: ${docsPath}`)
}
// traverse into docs directory if given the electron repo path
if (path.basename(docsPath) === 'electron') {
docsPath = path.join(docsPath, 'docs')
}
return fetchDocs(docsPath)
.then(function (docs) {
const seeds = deriveSeeds(docs)
var apis = seeds.map(seed => {
seed.version = targetVersion
return new API(seed, docs)
})
apis = remapTouchBar(apis)
// Attach named keys to collection arrays for easier access
// apis.app.events.login
// apis.app.methods.quit
// apis.BrowserWindow.instanceMethods.isFocused
apis = keyedArray(apis)
return callback(null, apis)
})
.catch(function (err) {
console.error(err)
return callback(err)
})
}
function deriveSeeds (docs) {
const seeds = []
docs
// Ignore files that aren't real APIs or data structures
// TODO: remove this if we ever move the non-API files out of the api dir
.filter(doc => doc.markdown_content.match(/^Process: \[/m) || doc.filename.match('structures'))
.forEach(doc => {
// H1 headings define modules and structures
const moduleHeading = /^# (.*)/
const moduleHeadingMatch = doc.markdown_content.match(moduleHeading)
if (moduleHeadingMatch) {
var name = moduleHeadingMatch[1].replace(/ Object/, '').replace(/ extends .+/, '')
// Special case for '<webview> Tag' heading
if (name.match(/webview/i)) name = 'webviewTag'
seeds.push({
name: name,
moduleLevelHeading: moduleHeadingMatch[1],
structure: !!doc.filename.match('structures')
})
}
// H2 headings define classes
// TODO: revise/simplify this if we ever change class headings from ## to #
const classHeading = /^## Class: (.*)/m
const classHeadingMatch = doc.markdown_content.match(classHeading)
if (classHeadingMatch && !(moduleHeadingMatch && moduleHeadingMatch[1] === classHeadingMatch[1])) {
// Only add seed if it's not a duplicate,
// e.g. `web-contents` has `# WebContents` and `## Class: WebContents`
seeds.push({
name: classHeadingMatch[1],
structure: false
})
}
})
return seeds
.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()))
}
module.exports = promisify(lint)