From 85dbf856cc8b30ef193a2fe0252756913b2eaaa1 Mon Sep 17 00:00:00 2001 From: Mohamed Shams El-Deen Date: Fri, 24 Jul 2026 16:10:17 +0300 Subject: [PATCH] refactor(processor): extract 'Hooks' group --- plugins/processor/extractHooksGroup.mjs | 117 ++++++++++++++++++++++++ plugins/processor/index.mjs | 5 + 2 files changed, 122 insertions(+) create mode 100644 plugins/processor/extractHooksGroup.mjs diff --git a/plugins/processor/extractHooksGroup.mjs b/plugins/processor/extractHooksGroup.mjs new file mode 100644 index 00000000..4838b6db --- /dev/null +++ b/plugins/processor/extractHooksGroup.mjs @@ -0,0 +1,117 @@ +import { + ReflectionKind, + ReflectionGroup, + ParameterReflection, + SignatureReflection, + IntrinsicType, +} from 'typedoc'; + +function extractHooks(type) { + let hooks = []; + if (!type) return hooks; + + type.visit({ + reflection: t => { + if (t.declaration?.children) { + hooks.push(...t.declaration.children); + } + }, + reference: t => { + if (t.name === 'Readonly' && t.typeArguments?.length) { + hooks.push(...extractHooks(t.typeArguments[0])); + } else if (t.reflection?.children) { + hooks.push(...t.reflection.children); + } + }, + intersection: t => { + if (t.types) { + t.types.forEach(innerType => { + hooks.push(...extractHooks(innerType)); + }); + } + }, + }); + + return hooks; +} + +export function extractHooksGroup(reflection) { + if (!reflection.groups) return; + + const propsGroup = reflection.groups.find(g => g.title === 'Properties'); + if (!propsGroup) return; + + const hooksIndex = propsGroup.children.findIndex(p => p.name === 'hooks'); + if (hooksIndex === -1) return; + + const hooksProp = propsGroup.children[hooksIndex]; + + const individualHooks = extractHooks(hooksProp.type); + + if (individualHooks.length > 0) { + propsGroup.children.splice(hooksIndex, 1); + + individualHooks.forEach(hook => { + hook.kind = ReflectionKind.Method; + const sig = new SignatureReflection( + hook.name, + ReflectionKind.CallSignature, + hook + ); + + if (hook.type?.type === 'reference' && hook.type.typeArguments?.length) { + const argsTuple = hook.type.typeArguments[0]; + if (argsTuple.type === 'tuple' && argsTuple.elements) { + sig.parameters = argsTuple.elements.map((el, i) => { + const type = el.type === 'named-tuple-member' ? el.element : el; + let name = el.type === 'named-tuple-member' ? el.name : undefined; + if (!name) { + if (type.type === 'reference' && type.name) { + name = type.name.charAt(0).toLowerCase() + type.name.slice(1); + } else if (type.type === 'intrinsic') { + name = type.name; + } else { + name = `arg${i}`; + } + } + const param = new ParameterReflection( + name, + ReflectionKind.Parameter, + sig + ); + param.type = type; + return param; + }); + } + + const hookName = hook.type.name; + if (hookName.includes('Bail') && hook.type.typeArguments.length > 1) { + sig.type = hook.type.typeArguments[1]; + } else if ( + hookName.includes('Waterfall') && + argsTuple.type === 'tuple' && + argsTuple.elements?.length + ) { + const el = argsTuple.elements[0]; + sig.type = el.type === 'named-tuple-member' ? el.element : el; + } else { + sig.type = new IntrinsicType('void'); + } + } + + hook.signatures = [sig]; + }); + + const hooksGroup = new ReflectionGroup('Hooks', ReflectionKind.Method); + hooksGroup.children = individualHooks; + + const methodsIndex = reflection.groups.findIndex( + g => g.title === 'Methods' + ); + if (methodsIndex !== -1) { + reflection.groups.splice(methodsIndex + 1, 0, hooksGroup); + } else { + reflection.groups.push(hooksGroup); + } + } +} diff --git a/plugins/processor/index.mjs b/plugins/processor/index.mjs index 01e973d4..9a6f6b11 100644 --- a/plugins/processor/index.mjs +++ b/plugins/processor/index.mjs @@ -1,5 +1,6 @@ import { Converter, ReflectionKind, Renderer } from 'typedoc'; import { MarkdownPageEvent } from 'typedoc-plugin-markdown'; +import { extractHooksGroup } from './extractHooksGroup.mjs'; import { getSourceMetadata } from './metadata.mjs'; import { writeFileSync } from 'node:fs'; import { join } from 'node:path'; @@ -74,6 +75,10 @@ export function load(app) { } }); + app.renderer.on(MarkdownPageEvent.BEGIN, page => { + extractHooksGroup(page.model); + }); + app.renderer.on(MarkdownPageEvent.END, page => { const sourceMeta = getSourceMetadata(page.model);