tldraw/apps/docs/scripts/utils.ts
2023-04-25 12:01:25 +01:00

120 lines
2.8 KiB
TypeScript

import { ApiItem } from '@microsoft/api-extractor-model'
import {
DocCodeSpan,
DocEscapedText,
DocFencedCode,
DocNode,
DocParagraph,
DocPlainText,
DocSection,
DocSoftBreak,
} from '@microsoft/tsdoc'
import prettier from 'prettier'
export function getPath(item: { canonicalReference: ApiItem['canonicalReference'] }): string {
return item.canonicalReference
.toString()
.replace(/^@tldraw\/([^!]+)/, '$1/')
.replace(/[!:()#.]/g, '-')
.replace(/-+/g, '-')
.replace(/^-/, '')
.replace(/\/-/, '/')
.replace(/-$/, '')
}
export function getSlug(item: { canonicalReference: ApiItem['canonicalReference'] }): string {
return getPath(item).replace(/^[^/]+\//, '')
}
const prettierConfigPromise = prettier.resolveConfig(__dirname)
const languages: { [tag: string]: string | undefined } = {
ts: 'typescript',
tsx: 'typescript',
}
export async function formatWithPrettier(
code: string,
{
languageTag,
// roughly the width of our code blocks on a desktop
printWidth = 80,
}: { languageTag?: string; printWidth?: number } = {}
) {
const language = languages[languageTag || 'ts']
if (!language) {
throw new Error(`Unknown language: ${languageTag}`)
}
const prettierConfig = await prettierConfigPromise
const formattedCode = prettier.format(code, {
...prettierConfig,
parser: language,
printWidth,
tabWidth: 2,
useTabs: false,
})
return formattedCode.trimEnd()
}
export class MarkdownWriter {
static async docNodeToMarkdown(docNode: DocNode) {
const writer = new MarkdownWriter()
await writer.writeDocNode(docNode)
return writer.toString()
}
private result = ''
write(...parts: string[]): this {
this.result += parts.join('')
return this
}
endsWith(str: string) {
return this.result.endsWith(str)
}
writeIfNeeded(str: string): this {
if (!this.endsWith(str)) {
this.write(str)
}
return this
}
async writeDocNode(docNode: DocNode) {
if (docNode instanceof DocPlainText) {
this.write(docNode.text)
} else if (docNode instanceof DocSection || docNode instanceof DocParagraph) {
await this.writeDocNodes(docNode.nodes)
this.writeIfNeeded('\n\n')
} else if (docNode instanceof DocSoftBreak) {
this.writeIfNeeded('\n')
} else if (docNode instanceof DocCodeSpan) {
this.write('`', docNode.code, '`')
} else if (docNode instanceof DocFencedCode) {
this.writeIfNeeded('\n').write(
'```',
docNode.language,
'\n',
await formatWithPrettier(docNode.code, { languageTag: docNode.language }),
'\n',
'```\n'
)
} else if (docNode instanceof DocEscapedText) {
this.write(docNode.encodedText)
} else {
throw new Error(`Unknown docNode kind: ${docNode.kind}`)
}
}
async writeDocNodes(docNodes: readonly DocNode[]) {
for (const docNode of docNodes) {
await this.writeDocNode(docNode)
}
return this
}
toString() {
return this.result
}
}