docs: generate documentation for UI components (#5849)

* added tool to generate spec files for React components

* use typedoc for missing descriptions and types

* improvements and fixes

* improvements

* added doc comments for half of the components

* add custom resolver + more doc comments

* added all tsdocs

* general improvements

* add specs to UI docs

* added github action

* remove unnecessary api route

* Added readme for react-docs-generator

* remove comment

* Update packages/design-system/ui/src/components/currency-input/currency-input.tsx

Co-authored-by: Kasper Fabricius Kristensen <45367945+kasperkristensen@users.noreply.github.com>

* remove description of aria fields + add generate script

---------

Co-authored-by: Kasper Fabricius Kristensen <45367945+kasperkristensen@users.noreply.github.com>
This commit is contained in:
Shahed Nasser
2023-12-13 16:02:41 +02:00
committed by GitHub
parent edc49bfe1d
commit 245e5c9a69
288 changed files with 6029 additions and 1447 deletions

View File

@@ -22,12 +22,15 @@ export function getTypeChildren(
break
case "reference":
// eslint-disable-next-line no-case-declarations
const referencedReflection =
reflectionType.reflection && "children" in reflectionType.reflection
const referencedReflection = reflectionType.reflection
? "children" in reflectionType.reflection
? reflectionType.reflection
: project
? getProjectChild(project, reflectionType.name)
? project.getReflectionById(reflectionType.reflection.id)
: undefined
: project
? getProjectChild(project, reflectionType.name)
: undefined
if (referencedReflection instanceof DeclarationReflection) {
if (referencedReflection.children) {

View File

@@ -0,0 +1,577 @@
import {
ArrayType,
ConditionalType,
DeclarationReflection,
IndexedAccessType,
InferredType,
IntersectionType,
IntrinsicType,
LiteralType,
ParameterReflection,
ProjectReflection,
QueryType,
ReferenceType,
ReflectionType,
SignatureReflection,
SomeType,
TupleType,
TypeOperatorType,
TypeParameterReflection,
UnionType,
UnknownType,
} from "typedoc"
import { escapeChars, getHTMLChar } from "./str-utils"
import { getProjectChild } from "./get-project-child"
export type ReflectionParameterType =
| ParameterReflection
| DeclarationReflection
| TypeParameterReflection
export type Collapse = "object" | "function" | "all" | "none"
export type TypeOptions<T = SomeType> = {
reflectionType: T
collapse?: Collapse
wrapBackticks?: boolean
hideLink?: boolean
escape?: boolean
project?: ProjectReflection
getRelativeUrlMethod?: (url: string) => string
}
export function getType({ reflectionType, ...options }: TypeOptions): string {
if (reflectionType instanceof ReferenceType) {
return getReferenceType({
reflectionType,
...options,
})
}
if (reflectionType instanceof ArrayType && reflectionType.elementType) {
return getArrayType({
reflectionType,
...options,
})
}
if (reflectionType instanceof UnionType && reflectionType.types) {
return getUnionType({
reflectionType,
...options,
})
}
if (reflectionType instanceof IntersectionType && reflectionType.types) {
return getIntersectionType({
reflectionType,
...options,
})
}
if (reflectionType instanceof TupleType && reflectionType.elements) {
return getTupleType({
reflectionType,
...options,
})
}
if (reflectionType instanceof IntrinsicType && reflectionType.name) {
return getIntrinsicType({
reflectionType,
...options,
})
}
if (reflectionType instanceof ReflectionType) {
return getReflectionType({
reflectionType: reflectionType.declaration,
...options,
})
}
if (reflectionType instanceof DeclarationReflection) {
return getReflectionType({
reflectionType,
...options,
})
}
if (reflectionType instanceof TypeOperatorType) {
return getTypeOperatorType({
reflectionType,
...options,
})
}
if (reflectionType instanceof QueryType) {
return getQueryType({
reflectionType,
...options,
})
}
if (reflectionType instanceof ConditionalType) {
return getConditionalType({
reflectionType,
...options,
})
}
if (reflectionType instanceof IndexedAccessType) {
return getIndexAccessType({
reflectionType,
...options,
})
}
if (reflectionType instanceof UnknownType) {
return getUnknownType({
reflectionType,
...options,
})
}
if (reflectionType instanceof InferredType) {
return getInferredType({
reflectionType,
...options,
})
}
if (reflectionType instanceof LiteralType) {
return getLiteralType({
reflectionType,
...options,
})
}
return reflectionType ? escapeChars(reflectionType.toString()) : ""
}
export function getReflectionType({
reflectionType: model,
collapse,
wrapBackticks = true,
hideLink = false,
}: TypeOptions<ReflectionParameterType>): string {
if ("signatures" in model && model.signatures) {
return collapse === "function" || collapse === "all"
? `${wrapBackticks ? "`" : ""}fn${wrapBackticks ? "`" : ""}`
: getFunctionType({
modelSignatures: model.signatures,
wrapBackticks,
hideLink,
escape: !wrapBackticks,
})
}
return collapse === "object" || collapse === "all"
? `${wrapBackticks ? "`" : ""}object${wrapBackticks ? "`" : ""}`
: `${wrapBackticks ? "`" : ""}${getDeclarationType({
reflectionType: model as DeclarationReflection,
wrapBackticks,
hideLink,
escape: !wrapBackticks,
})}${wrapBackticks ? "`" : ""}`
}
export function getDeclarationType({
reflectionType: model,
wrapBackticks = true,
hideLink = false,
escape,
...options
}: TypeOptions<DeclarationReflection>): string {
escape = getShouldEscape(wrapBackticks, escape)
if (model.indexSignature || model.children) {
let indexSignature = ""
const declarationIndexSignature = model.indexSignature
if (declarationIndexSignature) {
const key = declarationIndexSignature.parameters
? declarationIndexSignature.parameters.map(
(param) => `[${param.name}: ${param.type}]`
)
: ""
const obj = declarationIndexSignature.type
? getType({
reflectionType: declarationIndexSignature.type,
wrapBackticks: false,
hideLink,
escape,
...options,
})
: ""
indexSignature = `${key}: ${obj}; `
}
const types =
model.children &&
model.children.map((obj) => {
return `${obj.name}${obj.flags.isOptional ? "?" : ""}: ${
obj.type
? getType({
reflectionType: obj.type,
wrapBackticks: false,
hideLink,
escape,
...options,
})
: getFormattedStr(obj.toString(), false, escape)
} ${
obj.defaultValue && obj.defaultValue !== "..."
? `= ${getFormattedStr(`${obj.defaultValue}`, false, escape)}`
: ""
}`
})
return `${wrapBackticks ? "`{" : getHTMLChar("{")} ${
indexSignature ? indexSignature : ""
}${types ? types.join("; ") : ""} ${
wrapBackticks ? "}`" : getHTMLChar("}")
}${
model.defaultValue && model.defaultValue !== "..."
? `= ${getFormattedStr(`${model.defaultValue}`, wrapBackticks, escape)}`
: ""
}`
}
return getFormattedStr("{}", wrapBackticks, escape)
}
export function getFunctionType({
modelSignatures,
wrapBackticks = true,
hideLink = false,
escape,
...options
}: Omit<TypeOptions, "reflectionType"> & {
modelSignatures: SignatureReflection[]
}): string {
escape = getShouldEscape(wrapBackticks, escape)
const functions = modelSignatures.map((fn) => {
const typeParams = fn.typeParameters
? `${wrapBackticks ? "`<" : getHTMLChar("<")}${fn.typeParameters
.map((typeParameter) => typeParameter.name)
.join(", ")}${wrapBackticks ? ">`" : getHTMLChar(">")}`
: []
const params = fn.parameters
? fn.parameters.map((param) => {
return `${param.flags.isRest ? "..." : ""}${
wrapBackticks ? "`" : ""
}${param.name}${param.flags.isOptional ? "?" : ""}${
wrapBackticks ? "`" : ""
}: ${
param.type
? getType({
reflectionType: param.type,
wrapBackticks,
hideLink,
escape,
...options,
})
: getFormattedStr(param.toString(), wrapBackticks, escape)
}`
})
: []
const returns = fn.type
? getType({
reflectionType: fn.type,
wrapBackticks,
hideLink,
escape,
...options,
})
: getFormattedStr(fn.toString(), wrapBackticks, escape)
return typeParams + `(${params.join(", ")}) => ${returns}`
})
return functions.join("")
}
export function getLiteralType({
reflectionType: model,
wrapBackticks = true,
escape,
}: TypeOptions<LiteralType>): string {
escape = getShouldEscape(wrapBackticks, escape)
return getFormattedStr(
model.value === "bigint" ? model.value : JSON.stringify(model.value),
wrapBackticks,
escape
)
}
export function getReferenceType({
reflectionType: model,
wrapBackticks = true,
hideLink = false,
escape,
project,
getRelativeUrlMethod,
...options
}: TypeOptions<ReferenceType>): string {
escape = getShouldEscape(wrapBackticks, escape)
const shouldShowLink = !hideLink && model.name !== "Record"
const wrappedInBackticks = wrapBackticks && !shouldShowLink
let modelReflection = model.reflection
if (!modelReflection && project) {
// try to load reflection
modelReflection = getProjectChild(project!, model.name)
}
if (modelReflection || (model.name && model.typeArguments)) {
const reflection: string[] = [wrappedInBackticks ? "`" : ""]
if (modelReflection?.url) {
reflection.push(
shouldShowLink
? `[${modelReflection.name}](${
getRelativeUrlMethod?.(modelReflection.url) || modelReflection.url
})`
: getFormattedStr(modelReflection.name, false, escape)
)
} else {
reflection.push(
shouldShowLink
? model.externalUrl
? `[${model.name}]( ${model.externalUrl} )`
: model.name
: getFormattedStr(model.name, false, escape)
)
}
if (model.typeArguments && model.typeArguments.length > 0) {
reflection.push(
`${wrappedInBackticks ? "<" : getHTMLChar("<")}${model.typeArguments
.map((typeArgument) =>
getType({
reflectionType: typeArgument,
wrapBackticks: false,
hideLink,
escape: false,
...options,
})
)
.join(", ")}${wrappedInBackticks ? ">" : getHTMLChar(">")}`
)
}
if (wrappedInBackticks) {
reflection.push("`")
}
return reflection.join("")
}
return shouldShowLink
? model.externalUrl
? `[${getFormattedStr(model.name, wrapBackticks, escape)}]( ${
model.externalUrl
} )`
: getFormattedStr(model.name, wrapBackticks, escape)
: getFormattedStr(model.name, wrapBackticks, escape)
}
export function getArrayType({
reflectionType: model,
hideLink = false,
...options
}: TypeOptions<ArrayType>): string {
const arrayType = getType({
reflectionType: model.elementType,
hideLink,
...options,
})
return model.elementType.type === "union"
? `(${arrayType})[]`
: `${arrayType}[]`
}
export function getUnionType({
reflectionType: model,
hideLink = false,
...options
}: TypeOptions<UnionType>): string {
return model.types
.map((unionType) =>
getType({
reflectionType: unionType,
hideLink,
...options,
})
)
.join(` \\| `)
}
export function getIntersectionType({
reflectionType: model,
hideLink = false,
...options
}: TypeOptions<IntersectionType>): string {
return model.types
.map((intersectionType) =>
getType({
reflectionType: intersectionType,
hideLink,
...options,
})
)
.join(" & ")
}
export function getTupleType({
reflectionType: model,
hideLink = false,
...options
}: TypeOptions<TupleType>): string {
return `[${model.elements
.map((element) =>
getType({
reflectionType: element,
hideLink,
...options,
})
)
.join(", ")}]`
}
export function getIntrinsicType({
reflectionType: model,
wrapBackticks = true,
escape,
}: TypeOptions<IntrinsicType>): string {
escape = getShouldEscape(wrapBackticks, escape)
return getFormattedStr(model.name, wrapBackticks, escape)
}
export function getTypeOperatorType({
reflectionType: model,
hideLink = false,
...options
}: TypeOptions<TypeOperatorType>): string {
return `${model.operator} ${getType({
reflectionType: model.target,
hideLink,
...options,
})}`
}
export function getQueryType({
reflectionType: model,
hideLink = false,
...options
}: TypeOptions<QueryType>): string {
return `typeof ${getType({
reflectionType: model.queryType,
hideLink,
...options,
})}`
}
export function getInferredType({
reflectionType: model,
escape,
}: TypeOptions<InferredType>): string {
escape = getShouldEscape(false, escape)
return `infer ${getFormattedStr(model.name, false, escape)}`
}
export function getUnknownType({
reflectionType: model,
escape,
}: TypeOptions<UnknownType>): string {
escape = getShouldEscape(false, escape)
return getFormattedStr(model.name, false, escape)
}
export function getConditionalType({
reflectionType: model,
hideLink = false,
...options
}: TypeOptions<ConditionalType>): string {
const md: string[] = []
if (model.checkType) {
md.push(
getType({
reflectionType: model.checkType,
hideLink,
...options,
})
)
}
md.push("extends")
if (model.extendsType) {
md.push(
getType({
reflectionType: model.extendsType,
hideLink,
...options,
})
)
}
md.push("?")
if (model.trueType) {
md.push(
getType({
reflectionType: model.trueType,
hideLink,
...options,
})
)
}
md.push(":")
if (model.falseType) {
md.push(
getType({
reflectionType: model.falseType,
hideLink,
...options,
})
)
}
return md.join(" ")
}
export function getIndexAccessType({
reflectionType: model,
hideLink = false,
...options
}: TypeOptions<IndexedAccessType>): string {
const md: string[] = []
if (model.objectType) {
md.push(
getType({
reflectionType: model.objectType,
hideLink,
...options,
})
)
}
if (model.indexType) {
md.push(
`[${getType({
reflectionType: model.indexType,
hideLink,
...options,
})}]`
)
}
return md.join("")
}
export function hasTypes(parameters: TypeParameterReflection[]) {
const types = (parameters as TypeParameterReflection[]).map(
(param) => !!param.type || !!param.default
)
return !types.every((value) => !value)
}
function getShouldEscape(wrapBackticks: boolean, escape?: boolean) {
return escape === undefined ? !wrapBackticks : escape
}
function getFormattedStr(
str: string,
wrapBackticks: boolean,
escape?: boolean
) {
return wrapBackticks ? `\`${str}\`` : escape ? escapeChars(str) : str
}

View File

@@ -1,2 +1,4 @@
export * from "./get-type-children"
export * from "./get-project-child"
export * from "./get-type-str"
export * from "./str-utils"

View File

@@ -0,0 +1,23 @@
export function getHTMLChar(str: string) {
return str
.replace(/</g, "&#60;")
.replace(/{/g, "&#123;")
.replace(/}/g, "&#125;")
.replace(/>/g, "&#62;")
}
export function escapeChars(str: string, escapeBackticks = true) {
const result = getHTMLChar(str).replace(/_/g, "\\_").replace(/\|/g, "\\|")
return escapeBackticks ? result.replace(/`/g, "\\`") : result
}
export function stripLineBreaks(str: string) {
return str
? str
.replace(/\n/g, " ")
.replace(/\r/g, " ")
.replace(/\t/g, " ")
.replace(/[\s]{2,}/g, " ")
.trim()
: ""
}