diff --git a/plugins/theme/helpers/index.mjs b/plugins/theme/helpers/index.mjs index 880933e..441ca1e 100644 --- a/plugins/theme/helpers/index.mjs +++ b/plugins/theme/helpers/index.mjs @@ -21,7 +21,7 @@ export default (ctx) => ({ : ""; const descPart = comment - ? ` ${ctx.helpers.getCommentParts(comment.summary ?? comment.content)}` + ? ` ${ctx.helpers.getCommentParts(comment.summary ?? comment.content)}${ctx.helpers.renderExamples(comment)}` : ""; return `*${namePart}${typePart}${descPart}`; @@ -64,4 +64,34 @@ export default (ctx) => ({ return null; }, + + /** + * Renders `@example` tags from a comment as Markdown. + * Pass `headingLevel` to prepend a heading (block context); + * omit it for inline use (e.g. inside a list item). + * Always returns a string never `null`. + * + * @param {import("typedoc").Comment | import("typedoc").CommentTag | null | undefined} comment + * @param {number} [headingLevel] + * @returns {string} + */ + renderExamples(comment, headingLevel) { + const examples = + comment?.blockTags?.filter((t) => t.tag === "@example") ?? []; + if (!examples.length) return ""; + const bodies = examples + .map((tag) => { + const body = ctx.helpers.getCommentParts(tag.content).trim(); + if (!body) return null; + if (headingLevel != null) { + const prefix = "#".repeat(headingLevel + 1); + const suffix = + examples.length > 1 ? ` ${examples.indexOf(tag) + 1}` : ""; + return `${prefix} Example${suffix}\n\n${body}`; + } + return body; + }) + .filter(Boolean); + return bodies.length ? "\n\n" + bodies.join("\n\n") : ""; + }, }); diff --git a/plugins/theme/partials/index.mjs b/plugins/theme/partials/index.mjs index 56463fb..7bd48c6 100644 --- a/plugins/theme/partials/index.mjs +++ b/plugins/theme/partials/index.mjs @@ -27,70 +27,80 @@ export const getMemberPrefix = (model) => { * @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx * @returns {import('typedoc-plugin-markdown').MarkdownThemeContext['partials']} */ -export default (ctx) => ({ - ...ctx.partials, - ...typePartials, +export default (ctx) => { + const baseComment = ctx.partials.comment; - signature(model, options) { - const comment = options.multipleSignatures - ? model.comment - : model.comment || model.parent?.comment; + return { + ...ctx.partials, + ...typePartials, - const stability = ctx.helpers.stabilityBlockquote(comment); + comment(model, options) { + return ( + baseComment.call(ctx, model, { ...options, showTags: false }) + + ctx.helpers.renderExamples(model, options?.headingLevel) + ); + }, - return [ - stability, - stability && "", - model.typeParameters?.length && - ctx.partials.typeParametersList(model.typeParameters, { - headingLevel: options.headingLevel, + signature(model, options) { + const comment = options.multipleSignatures + ? model.comment + : model.comment || model.parent?.comment; + const stability = ctx.helpers.stabilityBlockquote(comment); + return [ + stability, + stability && "", + model.typeParameters?.length && + ctx.partials.typeParametersList(model.typeParameters, { + headingLevel: options.headingLevel, + }), + model.parameters?.length && + ctx.partials.parametersList(model.parameters, { + headingLevel: options.headingLevel, + }), + ctx.helpers.typedListItem({ + label: "Returns", + type: model.type ?? "void", + comment: model.comment?.getTag("@returns"), }), - model.parameters?.length && - ctx.partials.parametersList(model.parameters, { - headingLevel: options.headingLevel, - }), - ctx.helpers.typedListItem({ - label: "Returns", - type: model.type ?? "void", - comment: model.comment?.getTag("@returns"), - }), - "", - comment && - ctx.partials.comment(comment, { - headingLevel: options.headingLevel, - showTags: false, - }), - ] - .filter((x) => typeof x === "string" || Boolean(x)) - .join("\n"); - }, + "", + comment && + baseComment.call(ctx, comment, { + headingLevel: options.headingLevel, + showTags: false, + }), + ctx.helpers.renderExamples(comment, options.headingLevel), + ] + .filter((x) => typeof x === "string" || Boolean(x)) + .join("\n"); + }, - memberTitle(model) { - const prefix = getMemberPrefix(model); - const params = model.signatures?.[0]?.parameters; + memberTitle(model) { + const prefix = getMemberPrefix(model); + const params = model.signatures?.[0]?.parameters; - if (!params) { - return `${prefix}\`${model.name}\``; - } + if (!params) { + return `${prefix}\`${model.name}\``; + } - const paramsString = params - .map((param, index) => { - const paramName = param.name; - if (param.flags?.isOptional) { - // For optional params, wrap comma + name in brackets (except for first param) - return index === 0 ? `[${paramName}]` : `[, ${paramName}]`; - } else { - // For required params, add comma separator (except for first param) - return index === 0 ? paramName : `, ${paramName}`; - } - }) - .join(""); + const paramsString = params + .map((param, index) => { + const paramName = param.name; + if (param.flags?.isOptional) { + // For optional params, wrap comma + name in brackets (except for first param) + return index === 0 ? `[${paramName}]` : `[, ${paramName}]`; + } else { + // For required params, add comma separator (except for first param) + return index === 0 ? paramName : `, ${paramName}`; + } + }) + .join(""); - return `${prefix}\`${model.name}(${paramsString})\``; - }, + return `${prefix}\`${model.name}(${paramsString})\``; + }, - parametersList: ctx.helpers.typedList, - typedParametersList: ctx.helpers.typedList, - typeDeclarationList: ctx.helpers.typedList, - propertiesTable: ctx.helpers.typedList, -}); + parametersList: ctx.helpers.typedList, + typedParametersList: ctx.helpers.typedList, + typeDeclarationList: ctx.helpers.typedList, + propertiesTable: ctx.helpers.typedList, + }; +};