webdriverio/scripts/docs-generation/3rdPartyDocs.ts

192 lines
7.7 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-explicit-any */
import fs from 'node:fs/promises'
import url from 'node:url'
import path from 'node:path'
import { downloadFromGitHub } from '../utils/index.js'
import { buildPreface } from '../utils/helpers.js'
import reporters3rdParty from './3rd-party/reporters.json' with { type: 'json' }
import services3rdParty from './3rd-party/services.json' with { type: 'json' }
import api3rdParty from './3rd-party/api.json' with { type: 'json' }
interface Plugin {
packageName: string
title: string
githubUrl: string
npmUrl: string
branch?: string
location?: string
locations: string[]
suppressBuildInfo?: boolean
}
const docsFixes: Record<string, ((docs: string) => string)> = {
'@sap_oss/wdio-qmate-service' : (docs: string) => docs
.replace('Benjamin Warth <benjamin.warth@sap.com>', '[Benjamin Warth](mailto:benjamin.warth@sap.com)')
.replace('Georgios Treska <georgios.treska@sap.com>', '[Georgios Treska](mailto:georgios.treska@sap.com)')
.replace('Marvin Grüßinger <marvin.gruessinger@sap.com>', '[Marvin Grüßinger](mailto:marvin.gruessinger@sap.com)'),
'wdio-ui5-service': (docs: string) => docs
.replace('<https://ui5-community.github.io/wdi5/>', '[https://ui5-community.github.io/wdi5/](https://ui5-community.github.io/wdi5/)')
.replace('Roadmap: <https://github.com/orgs/ui5-community/projects/2/views/1>', '[Roadmap](https://github.com/orgs/ui5-community/projects/2/views/1)'),
'wdio-intercept-service': (docs: string) => docs
.replace('browser.excludeUrls(urlRegexes: (string | RegExp)[])', '`browser.excludeUrls(urlRegexes: (string | RegExp)[])`')
.replace('browser.assertRequests({ orderBy?: \'START\' | \'END\' }?: = {})', '`browser.assertRequests({ orderBy?: \'START\' | \'END\' }?: = {})`')
.replace('browser.assertExpectedRequestsOnly({ inOrder?: boolean, orderBy?: \'START\' | \'END\' }?: = {})', "`browser.assertExpectedRequestsOnly({ inOrder?: boolean, orderBy?: 'START' | 'END' }?: = {})`")
.replace('browser.getRequest(index: number, { includePending?: boolean, orderBy?: \'START\' | \'END\' }?: = {})', "`browser.getRequest(index: number, { includePending?: boolean, orderBy?: 'START' | 'END' }?: = {})`")
.replace('browser.getRequests({ includePending?: boolean, orderBy?: \'START\' | \'END\' }?: = {})', "`browser.getRequests({ includePending?: boolean, orderBy?: 'START' | 'END' }?: = {})`"),
'wdio-reportportal-reporter': (docs: string) => docs
.replace('<http://reportportal.io/>', '[http://reportportal.io/](http://reportportal.io/)')
}
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
const plugins = [{
category: 'docs',
namePlural: 'Reporter',
nameSingular: 'Reporter',
packages3rdParty: reporters3rdParty
}, {
category: 'docs',
namePlural: 'Services',
nameSingular: 'Service',
packages3rdParty: services3rdParty
}, {
category: 'api',
namePlural: 'Testrunner',
nameSingular: '',
packages3rdParty: api3rdParty
}]
const githubReadme = 'README.md'
const readmeHeaderLines = 9
const readmeHeaders = ['===', '# ']
const readmeBadges = ['https://badge', 'https://travis-ci.org/']
const PROJECT_ROOT_DIR = path.join(__dirname, '..', '..')
const DOCS_ROOT_DIR = path.join(PROJECT_ROOT_DIR, 'website', 'docs')
/**
* Generate docs for 3rd party reporters and services
* @param {object} sidebars website/sidebars
*/
export async function generate3rdPartyDocs (sidebars: any) {
for (const { category, namePlural, nameSingular, packages3rdParty } of plugins) {
const categoryDir = path.join(DOCS_ROOT_DIR, category === 'api' ? 'api' : '')
await fs.mkdir(categoryDir, { recursive: true })
const sidebar = sidebars[category]
const items: string[] = []
for (const { packageName, title, githubUrl, npmUrl, suppressBuildInfo, locations, location = githubReadme, branch = 'main' } of packages3rdParty as Plugin[]) {
const readme = locations
? await Promise.all(locations.map((l) => downloadFromGitHub(githubUrl, branch, l)))
.then((readmes) => readmes.join('\n'))
: await downloadFromGitHub(githubUrl, branch, location)
const id = `${packageName}`.replace(/@/g, '').replace(/\//g, '-')
const doc = normalizeDoc(
readme,
githubUrl,
branch,
buildPreface(id, title, nameSingular, `${githubUrl}/edit/${branch}/${location}`),
suppressBuildInfo ? [] : buildInfo(packageName, githubUrl, npmUrl),
packageName
)
await fs.writeFile(path.join(categoryDir, `_${id}.md`), doc, { encoding: 'utf-8' })
if (namePlural === 'Testrunner') {
return
}
console.log(`Generated docs for ${packageName}`)
items.push(category === 'api' ? `${category}/${id}` : id)
}
const section = sidebar.find((s: any) => s.label === namePlural)
section.items.push(...items)
}
}
/**
* Removes header from README.md
* @param {string} readme readme content
* @param {string} githubUrl repo url
* @param {string} branch repo branch
* @param {string} preface docusaurus header
* @param {string} repoInfo repoInfo
* @return {string} readme content without header
*/
function normalizeDoc(readme: string, githubUrl: string, branch: string, preface: string[], repoInfo: string[], packageName: string) {
/**
* remove badges
*/
let readmeArr = readme.split('\n').filter(row => !readmeBadges.some(b => row.includes(b)))
/**
* get index of header to remove further
*/
let sliceIdx = 0
for (let i = 0; i < readmeHeaderLines && sliceIdx === 0; i++) {
if (typeof readmeArr[i] === 'string' && readmeHeaders.some(x => readmeArr[i].startsWith(x))) {
sliceIdx = i + 1
}
}
readmeArr = readmeArr.slice(sliceIdx)
/**
* prepend additional # to header rows
* and add path to links
*/
readmeArr.forEach((row, idx) => {
/**
* prepend # to header rows
*/
if (row.match(/^(# )\1* /)) {
readmeArr[idx] = `#${row}`
}
/**
* transform partial to full links
* match links like [foo](bar). `stringInParentheses` would be `bar`
* do not match [foo](http://bar), [foo](#bar)
*/
const mdLinks = row.match(/\[([^\]]+)\]\(([^)"]+)(?: "([^"]+)")?\)/g) || []
for (const mdLink of mdLinks) {
const urlMatcher = mdLink.match(/\[([^[]+)\]\((.*)\)/)
if (!urlMatcher) {
continue
}
const stringInParentheses = urlMatcher[2]
const url = ( stringInParentheses.startsWith('http') || stringInParentheses.startsWith('#') )
? stringInParentheses
: `${githubUrl}/blob/${branch}/${stringInParentheses}`
readmeArr[idx] = readmeArr[idx].replace(`](${stringInParentheses})`, `](${url})`)
}
})
/**
* apply custom fixes
*/
if (docsFixes[packageName]) {
console.log(`Applying custom fixes for ${packageName}`)
readmeArr = [docsFixes[packageName](readmeArr.join('\n'))]
}
return [...preface, ...repoInfo, ...readmeArr]
.join('\n')
.replace(/<br>/g, '<br />')
}
/**
* 3rd party package info
* @param {string} packageName package name
* @param {string} githubUrl GitHub url
* @param {string} npmUrl npm url
*/
function buildInfo(packageName: string, githubUrl: string, npmUrl: string) {
return [
`> ${packageName} is a 3rd party package, for more information please see [GitHub](${githubUrl}) | [npm](${npmUrl})`
]
}