From 8528bb5e758ddd9388e4543b2ea8ad385b7659fe Mon Sep 17 00:00:00 2001 From: Matthieu Riegler Date: Sun, 5 Oct 2025 17:59:45 +0200 Subject: [PATCH] docs(docs-infra): fix @example in class members (#64249) eg: ApplicationRef PR Close #64249 --- .../extraction/interpolate_code_examples.mts | 23 +++++++- .../test/interpolate_code_examples.spec.mts | 56 ++++++++++++++++++- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/adev/shared-docs/pipeline/api-gen/extraction/interpolate_code_examples.mts b/adev/shared-docs/pipeline/api-gen/extraction/interpolate_code_examples.mts index 3341e660ffe..2e84d8aa644 100644 --- a/adev/shared-docs/pipeline/api-gen/extraction/interpolate_code_examples.mts +++ b/adev/shared-docs/pipeline/api-gen/extraction/interpolate_code_examples.mts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {DocEntry} from '@angular/compiler-cli'; +import {DocEntry, ClassEntry, MethodEntry} from '@angular/compiler-cli'; import {basename, dirname, resolve} from 'path'; import fs from 'fs'; @@ -48,6 +48,27 @@ export function interpolateCodeExamples(entries: DocEntry[]): void { for (const jsdocTag of entry.jsdocTags) { jsdocTag.comment = replaceExample(jsdocTag.comment); } + + if ('members' in entry) { + const members = (entry as ClassEntry).members ?? []; + for (const member of members) { + member.description = replaceExample(member.description); + + for (const jsdocTag of member.jsdocTags) { + jsdocTag.comment = replaceExample(jsdocTag.comment); + } + + const method = member as MethodEntry; + if (method.implementation) { + for (const functionSignature of [method.implementation, ...(method.signatures ?? [])]) { + functionSignature.description = replaceExample(functionSignature.description); + functionSignature.jsdocTags.forEach((jsdocTag) => { + jsdocTag.comment = replaceExample(jsdocTag.comment); + }); + } + } + } + } } } diff --git a/adev/shared-docs/pipeline/api-gen/extraction/test/interpolate_code_examples.spec.mts b/adev/shared-docs/pipeline/api-gen/extraction/test/interpolate_code_examples.spec.mts index 6f6be39944b..9d744f5fa21 100644 --- a/adev/shared-docs/pipeline/api-gen/extraction/test/interpolate_code_examples.spec.mts +++ b/adev/shared-docs/pipeline/api-gen/extraction/test/interpolate_code_examples.spec.mts @@ -8,7 +8,14 @@ import fs from 'fs'; import {interpolateCodeExamples} from '../interpolate_code_examples.mjs'; -import {DocEntry} from '@angular/compiler-cli'; +import { + ClassEntry, + DocEntry, + EntryType, + FunctionSignatureMetadata, + MemberType, + MethodEntry, +} from '@angular/compiler-cli'; import {mockReadFileSync} from './fake-examples.mjs'; const tsMdBlock = (code: string) => '```angular-ts\n' + code + '\n```'; @@ -156,4 +163,51 @@ class Baz { expect(getComment(entries)).toMatch(/^\`\`\`/m); }); + + it('should interpolate an example on a method', () => { + const entries: ClassEntry[] = [ + { + description: '', + rawComment: '', + entryType: EntryType.UndecoratedClass, + name: 'Test', + jsdocTags: [], + isAbstract: false, + generics: [], + implements: [], + extends: undefined, + members: [ + { + name: 'test', + jsdocTags: [], + description: '', + memberTags: [], + memberType: MemberType.Method, + signatures: [], + entryType: EntryType.Function, + rawComment: '', + implementation: { + name: 'test', + entryType: EntryType.Function, + rawComment: '', + params: [], + returnType: 'void', + generics: [], + isNewType: false, + jsdocTags: [{name: '', comment: "{@example dummy/single.ts region='foo'}"}], + description: `Example: {@example dummy/single.ts region='foo'}`, + } as FunctionSignatureMetadata, + } as MethodEntry, + ], + }, + ]; + + interpolateCodeExamples(entries as DocEntry[]); + + const method = entries[0].members![0] as MethodEntry; + expect(method.implementation!.description).toContain(tsMdBlock("foo('Hello world!');")); + + const jsdocTag = method.implementation!.jsdocTags[0]; + expect(jsdocTag.comment).toEqual(tsMdBlock("foo('Hello world!');")); + }); });