chore(docs): Updated UI Reference (automated) (#13968)

* chore(docs): Generated + Updated UI Reference (automated)

* fix react-docs-generator not resolving external types

* sort undefined

---------

Co-authored-by: olivermrbl <olivermrbl@users.noreply.github.com>
Co-authored-by: Shahed Nasser <shahednasser@gmail.com>
This commit is contained in:
github-actions[bot]
2025-11-05 18:00:46 +02:00
committed by GitHub
parent 924d651188
commit 423b6d94dc
15 changed files with 402 additions and 86 deletions

View File

@@ -6,7 +6,7 @@ import {
TSFunctionSignatureType,
TypeDescriptor,
} from "react-docgen/dist/Documentation.js"
import { Comment, ReferenceReflection, ReferenceType } from "typedoc"
import { Comment, ReferenceReflection } from "typedoc"
import {
Application,
Context,
@@ -18,12 +18,14 @@ import {
SomeType,
SourceReference,
} from "typedoc"
import ts from "typescript"
import {
getFunctionType,
getProjectChild,
getType,
getTypeChildren,
} from "utils"
import { getTypescriptTsType } from "../utils/get-typescript-ts-type.js"
type MappedReflectionSignature = {
source: SourceReference
@@ -36,7 +38,7 @@ type Options = {
verbose?: boolean
}
type TsType = TypeDescriptor<TSFunctionSignatureType>
export type TsType = TypeDescriptor<TSFunctionSignatureType>
type ExcludeExternalOptions = {
parentReflection: DeclarationReflection
@@ -121,17 +123,14 @@ export default class TypedocManager {
return spec
}
const doesReflectionHaveSignature =
reflection.type?.type === "reference" &&
reflection.type.reflection instanceof DeclarationReflection &&
reflection.type.reflection.signatures?.length
if (reflection.type?.type === "reference") {
reflection = reflection.type.reflection as DeclarationReflection
}
let signature: SignatureReflection | undefined
let props: DeclarationReflection[] = []
if (doesReflectionHaveSignature) {
signature = (
(reflection.type! as ReferenceType).reflection as DeclarationReflection
).signatures![0]
if (reflection.signatures?.length) {
signature = reflection.signatures![0]
props =
signature?.parameters?.length && signature.parameters[0].type
? getTypeChildren({
@@ -282,7 +281,7 @@ export default class TypedocManager {
// Retrieves the `tsType` stored in a spec's prop
// The format is based on the expected format of React Docgen.
getTsType(reflectionType: SomeType, level = 1): TsType {
getTsType(reflectionType: SomeType, symbol?: ts.Symbol, level = 1): TsType {
const rawValue = getType({
reflectionType,
...this.getTypeOptions,
@@ -294,7 +293,11 @@ export default class TypedocManager {
}
switch (reflectionType.type) {
case "array": {
const elements = this.getTsType(reflectionType.elementType, level + 1)
const elements = this.getTsType(
reflectionType.elementType,
symbol,
level + 1
)
return {
name: "Array",
elements: [elements],
@@ -306,16 +309,27 @@ export default class TypedocManager {
(reflectionType.reflection as DeclarationReflection) ||
getProjectChild(this.project!, reflectionType.name)
const elements: TsType[] = []
if (!referenceReflection && symbol) {
return (
getTypescriptTsType(symbol) || {
name: reflectionType.name,
raw: rawValue,
elements,
}
)
}
if (referenceReflection?.children) {
referenceReflection.children?.forEach((child) => {
if (!child.type) {
return
}
elements.push(this.getTsType(child.type, level + 1))
elements.push(this.getTsType(child.type, symbol, level + 1))
})
} else if (referenceReflection?.type) {
elements.push(this.getTsType(referenceReflection.type, level + 1))
elements.push(
this.getTsType(referenceReflection.type, symbol, level + 1)
)
}
return {
name: reflectionType.name,
@@ -344,7 +358,7 @@ export default class TypedocManager {
typeData.signature.properties.push({
key: property.name,
value: property.type
? this.getTsType(property.type, level + 1)
? this.getTsType(property.type, symbol, level + 1)
: {
name: "unknown",
},
@@ -390,7 +404,7 @@ export default class TypedocManager {
const elementData: TsType[] = []
elements.forEach((element) => {
elementData.push(this.getTsType(element, level + 1))
elementData.push(this.getTsType(element, undefined, level + 1))
})
return elementData
@@ -462,10 +476,12 @@ export default class TypedocManager {
return: undefined,
},
}
const signatureSymbol = this.getReflectionSymbol(signature)
signature.parameters?.forEach((parameter) => {
const parameterSymbol = this.getReflectionSymbol(parameter)
const parameterType = parameter.type
? this.getTsType(parameter.type, level + 1)
? this.getTsType(parameter.type, parameterSymbol, level + 1)
: undefined
typeData.signature.arguments.push({
name: parameter.name,
@@ -475,14 +491,14 @@ export default class TypedocManager {
})
typeData.signature.return = signature.type
? this.getTsType(signature.type, level + 1)
? this.getTsType(signature.type, signatureSymbol, level + 1)
: undefined
return typeData
}
// Checks if a TsType only has a `name` field.
doesOnlyHaveName(obj: TsType): boolean {
onlyHasName(obj: TsType): boolean {
const primitiveTypes = ["string", "number", "object", "boolean", "function"]
const keys = Object.keys(obj)
@@ -493,6 +509,34 @@ export default class TypedocManager {
)
}
isRawTypeEmpty(tsType: TsType): boolean {
if (!("raw" in tsType)) {
return false
}
if ("elements" in tsType && tsType.elements.length > 0) {
return false
}
if ("signature" in tsType && tsType.signature) {
if (
"arguments" in tsType.signature &&
tsType.signature.arguments.length > 0
) {
return false
}
if (
"properties" in tsType.signature &&
tsType.signature.properties.length > 0
) {
return false
}
return false
}
return true
}
// retrieves a reflection by the provided name
// and check if its type is ReactNode
// this is useful for the CustomResolver to check
@@ -559,7 +603,10 @@ export default class TypedocManager {
return null
}
return this.getTsType(childReflection.type as SomeType)
return this.getTsType(
childReflection.type as SomeType,
this.getReflectionSymbol(childReflection)
)
}
// used to check if a reflection (typically of a prop)
@@ -686,4 +733,8 @@ export default class TypedocManager {
}
: undefined
}
getReflectionSymbol(reflection: Reflection): ts.Symbol | undefined {
return this.project?.getSymbolFromReflection(reflection)
}
}

View File

@@ -50,7 +50,7 @@ function resolveDocumentation(
utils.setPropDescription(documentation, propertyPath)
// set type if missing
if (!propDescriptor.tsType && typedocManager) {
if (typedocManager && !propDescriptor.tsType) {
const typeAnnotation = utils.getTypeAnnotation(path)
if (typeAnnotation?.isTSTypeReference()) {
const typeName = typeAnnotation.get("typeName")
@@ -71,7 +71,8 @@ function resolveDocumentation(
}
} else if (
propDescriptor.tsType &&
typedocManager?.doesOnlyHaveName(propDescriptor.tsType)
(typedocManager?.onlyHasName(propDescriptor.tsType) ||
typedocManager?.isRawTypeEmpty(propDescriptor.tsType))
) {
// see if the type needs to be resolved.
const typeReflection = typedocManager?.getReflectionByName(

View File

@@ -0,0 +1,180 @@
import ts from "typescript"
import { TsType } from "../classes/typedoc-manager.js"
const MAX_LEVEL = 3
export function getTypescriptTsType(
symbol: ts.Symbol | undefined
): TsType | null {
if (!symbol) {
return null
}
let convertedType: TsType | null = null
if ("type" in symbol) {
convertedType = convertTypeToTsType(symbol.type as ts.Type, 1)
}
if (
!convertedType &&
"links" in symbol &&
"type" in (symbol.links as Record<string, unknown>)
) {
const symbolTypeLink = (symbol.links as Record<string, unknown>)
.type as ts.Type
convertedType = convertTypeToTsType(symbolTypeLink, 1)
}
return convertedType
}
function convertTypeToTsType(type: ts.Type, level = 1): TsType | null {
if (level > MAX_LEVEL) {
return null
}
// Handle union types
if (type.isUnion()) {
const elements: TsType[] = type.types
.map((unionedType) => convertTypeToTsType(unionedType, level + 1))
.filter((element): element is TsType => element !== null)
// If all elements were filtered out, return null
if (elements.length === 0) {
return null
}
// Sort elements to put undefined at the end
elements.sort((a, b) => {
const aIsUndefined = a.name === "undefined"
const bIsUndefined = b.name === "undefined"
if (aIsUndefined && !bIsUndefined) {
return 1
}
if (!aIsUndefined && bIsUndefined) {
return -1
}
return 0
})
return {
name: "union",
raw: undefined,
elements,
}
}
// Handle intersection types
if (type.isIntersection()) {
const elements: TsType[] = type.types
.map((intersectedType) => convertTypeToTsType(intersectedType, level + 1))
.filter((element): element is TsType => element !== null)
// If all elements were filtered out, return null
if (elements.length === 0) {
return null
}
return {
name: "intersection",
raw: undefined,
elements,
}
}
const typeFlags = type.flags
// Handle string literal
if (typeFlags & ts.TypeFlags.StringLiteral) {
const literalType = type as ts.StringLiteralType
return {
name: "literal",
value: `"${literalType.value}"`,
}
}
// Handle number literal
if (typeFlags & ts.TypeFlags.NumberLiteral) {
const literalType = type as ts.NumberLiteralType
return {
name: "literal",
value: literalType.value.toString(),
}
}
// Handle boolean literal
if (typeFlags & ts.TypeFlags.BooleanLiteral) {
const literalType = type as ts.Type & { intrinsicName?: string }
return {
name: "literal",
value: literalType.intrinsicName || "boolean",
}
}
// Handle null
if (typeFlags & ts.TypeFlags.Null) {
return {
name: "null",
}
}
// Handle undefined
if (typeFlags & ts.TypeFlags.Undefined) {
return {
name: "undefined",
}
}
// Handle primitive types
if (typeFlags & ts.TypeFlags.String) {
return { name: "string" }
}
if (typeFlags & ts.TypeFlags.Number) {
return { name: "number" }
}
if (typeFlags & ts.TypeFlags.Boolean) {
return { name: "boolean" }
}
if (typeFlags & ts.TypeFlags.Void) {
return { name: "void" }
}
if (typeFlags & ts.TypeFlags.Any) {
return { name: "any" }
}
if (typeFlags & ts.TypeFlags.Unknown) {
return null
}
if (typeFlags & ts.TypeFlags.Never) {
return { name: "never" }
}
// Handle object types
if (typeFlags & ts.TypeFlags.Object) {
const objectType = type as ts.ObjectType
// Handle reference types (named types)
if (objectType.objectFlags & ts.ObjectFlags.Reference) {
const typeRef = type as ts.TypeReference
const typeName = typeRef.symbol?.name || "unknown"
const elements: TsType[] = []
if (typeRef.typeArguments) {
typeRef.typeArguments.forEach((typeArg) => {
const convertedType = convertTypeToTsType(typeArg, level + 1)
if (convertedType) {
elements.push(convertedType)
}
})
}
return {
name: typeRef.symbol?.name || typeName,
elements: elements.length > 0 ? elements : undefined,
raw: undefined,
}
}
}
// Fallback: return the string representation of the type
return null
}