/* 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] }