/* eslint-disable @typescript-eslint/no-explicit-any */
import fs from 'node:fs'
import path from 'node:path'
import url from 'node:url'
import { Eta } from 'eta'
import { repoUrl } from '../constants.js'
import {
PROTOCOLS, PROTOCOL_NAMES, MOBILE_PROTOCOLS, VENDOR_PROTOCOLS,
PROTOCOL_API_DESCRIPTION
} from '../protocols.js'
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
const TEMPLATE_PATH = path.join(__dirname, '..', 'templates')
const category = 'api'
const PROJECT_ROOT_DIR = path.join(__dirname, '..', '..', 'website')
const API_DOCS_ROOT_DIR = path.join(PROJECT_ROOT_DIR, 'docs', category)
const eta = new Eta({
views: TEMPLATE_PATH,
autoEscape: false,
})
/**
* Generate Protocol docs
* @param {object} sidebars website/sidebars
*/
export function generateProtocolDocs (sidebars: any) {
fs.mkdir(API_DOCS_ROOT_DIR, { recursive: true }, (err) => console.error(err))
const protocolDocs: any = {}
const protocolDocEntry = {
type: 'category',
label: 'Protocols',
link: {
type: 'doc',
id: 'api/protocols'
},
items: [] as any[]
}
for (const [protocolName, definition] of Object.entries(PROTOCOLS)) {
const protocol = PROTOCOL_NAMES[protocolName as unknown as keyof typeof PROTOCOL_NAMES] as string
for (const [, methods] of Object.entries(definition)) {
for (const [, description] of Object.entries(methods) as any) {
description.paramTags = [...(description.variables || []).map((variable: any) => {
return Object.assign(variable, { required: true, type: 'String' })
}), ...description.parameters || []]
description.hasHeader = true
description.paramString = description.paramTags.map((param: any) => param.name).join(', ')
description.examples = (description.examples || []).map((example: any) => {
return {
code: Array.isArray(example) ? example.join('\n') : example,
format: 'js'
}
})
description.returnTags = [] // tbd
description.throwsTags = [] // tbd
description.exampleReferences = description.exampleReferences || []
description.isMobile = MOBILE_PROTOCOLS.includes(protocolName)
description.customEditUrl = `${repoUrl}/edit/main/packages/wdio-protocols/src/protocols/${protocolName}.ts`
let protocolNote
if (VENDOR_PROTOCOLS.includes(protocolName)) {
protocolNote = `Non official and undocumented ${protocol} command.`
if (description.ref) {
protocolNote += ` More about this command can be found [here](${description.ref}).`
}
} else {
protocolNote = `${protocol} command. More details can be found in the [official protocol docs](${description.ref}).`
}
if (description.description) {
description.description += `
${protocolNote}`
} else {
description.description = protocolNote
}
if (description.deprecated) {
description.deprecated = `This protocol command is deprecated
${description.deprecated}`
}
const markdown = eta.render('./template', { ...description, path })
if (!protocolDocs[protocolName]) {
protocolDocs[protocolName] = [[
'---',
`id: ${protocolName}`,
`title: ${protocol}`,
`custom_edit_url: https://github.com/webdriverio/webdriverio/edit/main/packages/wdio-protocols/src/protocols/${protocolName}.ts`,
'---\n',
].join('\n')]
/**
* include API description if existent
*/
if (Object.keys(PROTOCOL_API_DESCRIPTION).includes(protocolName)) {
protocolDocs[protocolName].push(PROTOCOL_API_DESCRIPTION[protocolName as keyof typeof PROTOCOL_API_DESCRIPTION])
}
}
protocolDocs[protocolName].push(markdown)
}
}
const docPath = path.join(API_DOCS_ROOT_DIR, `_${protocolName}.md`)
const [preemble, ...apiDocs] = protocolDocs[protocolName]
fs.writeFileSync(docPath, preemble + apiDocs.join('\n---\n'), { encoding: 'utf-8' })
console.log(`Generated docs for ${protocolName} protocol`)
protocolDocEntry.items.push(`${category}/${protocolName}`)
}
/**
* Have API intro page first, then protocol commands, then general API docs last
*/
const [api, ...rest] = sidebars[category]
sidebars.api = [api, protocolDocEntry, ...rest]
}