@@ -14,25 +14,42 @@ import {Reference} from '../../imports';
1414import { DirectiveMeta , InputMapping , InputOrOutput , MetadataReader , NgModuleMeta , PipeMeta } from '../../metadata' ;
1515import { ClassDeclaration } from '../../reflection' ;
1616
17- import { ClassEntry , DirectiveEntry , EntryType , MemberEntry , MemberTags , MemberType , MethodEntry , PipeEntry , PropertyEntry } from './entities' ;
17+ import { ClassEntry , DirectiveEntry , EntryType , InterfaceEntry , MemberEntry , MemberTags , MemberType , MethodEntry , PipeEntry , PropertyEntry } from './entities' ;
1818import { extractResolvedTypeString } from './type_extractor' ;
1919
20+ // For the purpose of extraction, we can largely treat properties and accessors the same.
21+
2022/** A class member declaration that is *like* a property (including accessors) */
2123type PropertyDeclarationLike = ts . PropertyDeclaration | ts . AccessorDeclaration ;
2224
23- /** Extractor to pull info for API reference documentation for a TypeScript class. */
25+ // For the purposes of extraction, we can treat interfaces as identical to classes
26+ // with a couple of shorthand types to normalize over the differences between them.
27+
28+ /** Type representing either a class declaration ro an interface declaration. */
29+ type ClassDeclarationLike = ts . ClassDeclaration | ts . InterfaceDeclaration ;
30+
31+ /** Type representing either a class member node or an interface member node. */
32+ type MemberElement = ts . ClassElement | ts . TypeElement ;
33+
34+ /** Type representing either a class method declaration or an interface method signature. */
35+ type MethodLike = ts . MethodDeclaration | ts . MethodSignature ;
36+
37+ /** Type representing either a class property declaration or an interface property signature. */
38+ type PropertyLike = PropertyDeclarationLike | ts . PropertySignature ;
39+
40+ /** Extractor to pull info for API reference documentation for a TypeScript class or interface. */
2441class ClassExtractor {
2542 constructor (
26- protected declaration : ClassDeclaration & ts . ClassDeclaration ,
27- protected reference : Reference ,
43+ protected declaration : ClassDeclaration & ClassDeclarationLike ,
2844 protected typeChecker : ts . TypeChecker ,
2945 ) { }
3046
3147 /** Extract docs info specific to classes. */
3248 extract ( ) : ClassEntry {
3349 return {
34- name : this . declaration . name ! . text ,
35- entryType : EntryType . UndecoratedClass ,
50+ name : this . declaration . name . text ,
51+ entryType : ts . isInterfaceDeclaration ( this . declaration ) ? EntryType . Interface :
52+ EntryType . UndecoratedClass ,
3653 members : this . extractAllClassMembers ( this . declaration ) ,
3754 description : extractJsDocDescription ( this . declaration ) ,
3855 jsdocTags : extractJsDocTags ( this . declaration ) ,
@@ -41,7 +58,7 @@ class ClassExtractor {
4158 }
4259
4360 /** Extracts doc info for a class's members. */
44- protected extractAllClassMembers ( classDeclaration : ts . ClassDeclaration ) : MemberEntry [ ] {
61+ protected extractAllClassMembers ( classDeclaration : ClassDeclarationLike ) : MemberEntry [ ] {
4562 const members : MemberEntry [ ] = [ ] ;
4663
4764 for ( const member of classDeclaration . members ) {
@@ -57,10 +74,10 @@ class ClassExtractor {
5774 }
5875
5976 /** Extract docs for a class's members (methods and properties). */
60- protected extractClassMember ( memberDeclaration : ts . ClassElement ) : MemberEntry | undefined {
61- if ( ts . isMethodDeclaration ( memberDeclaration ) ) {
77+ protected extractClassMember ( memberDeclaration : MemberElement ) : MemberEntry | undefined {
78+ if ( this . isMethod ( memberDeclaration ) ) {
6279 return this . extractMethod ( memberDeclaration ) ;
63- } else if ( ts . isPropertyDeclaration ( memberDeclaration ) ) {
80+ } else if ( this . isProperty ( memberDeclaration ) ) {
6481 return this . extractClassProperty ( memberDeclaration ) ;
6582 } else if ( ts . isAccessor ( memberDeclaration ) ) {
6683 return this . extractGetterSetter ( memberDeclaration ) ;
@@ -72,7 +89,7 @@ class ClassExtractor {
7289 }
7390
7491 /** Extracts docs for a class method. */
75- protected extractMethod ( methodDeclaration : ts . MethodDeclaration ) : MethodEntry {
92+ protected extractMethod ( methodDeclaration : MethodLike ) : MethodEntry {
7693 const functionExtractor = new FunctionExtractor ( methodDeclaration , this . typeChecker ) ;
7794 return {
7895 ...functionExtractor . extract ( ) ,
@@ -82,7 +99,7 @@ class ClassExtractor {
8299 }
83100
84101 /** Extracts doc info for a property declaration. */
85- protected extractClassProperty ( propertyDeclaration : PropertyDeclarationLike ) : PropertyEntry {
102+ protected extractClassProperty ( propertyDeclaration : PropertyLike ) : PropertyEntry {
86103 return {
87104 name : propertyDeclaration . name . getText ( ) ,
88105 type : extractResolvedTypeString ( propertyDeclaration , this . typeChecker ) ,
@@ -102,8 +119,7 @@ class ClassExtractor {
102119 }
103120
104121 /** Gets the tags for a member (protected, readonly, static, etc.) */
105- protected getMemberTags ( member : ts . MethodDeclaration | ts . PropertyDeclaration |
106- ts . AccessorDeclaration ) : MemberTags [ ] {
122+ protected getMemberTags ( member : MethodLike | PropertyLike ) : MemberTags [ ] {
107123 const tags : MemberTags [ ] = this . getMemberTagsFromModifiers ( member . modifiers ?? [ ] ) ;
108124
109125 if ( member . questionToken ) {
@@ -144,28 +160,38 @@ class ClassExtractor {
144160 * - The member is neither a method nor property
145161 * - The member is protected
146162 */
147- private isMemberExcluded ( member : ts . ClassElement ) : boolean {
163+ private isMemberExcluded ( member : MemberElement ) : boolean {
148164 return ! member . name || ! this . isDocumentableMember ( member ) ||
149165 ! ! member . modifiers ?. some ( mod => mod . kind === ts . SyntaxKind . PrivateKeyword ) ;
150166 }
151167
152168 /** Gets whether a class member is a method, property, or accessor. */
153- private isDocumentableMember ( member : ts . ClassElement ) : member is ts . MethodDeclaration
154- | ts . PropertyDeclaration {
155- return ts . isMethodDeclaration ( member ) || ts . isPropertyDeclaration ( member ) ||
156- ts . isAccessor ( member ) ;
169+ private isDocumentableMember ( member : MemberElement ) : member is MethodLike | PropertyLike {
170+ return this . isMethod ( member ) || this . isProperty ( member ) || ts . isAccessor ( member ) ;
171+ }
172+
173+ /** Gets whether a member is a property. */
174+ private isProperty ( member : MemberElement ) : member is PropertyLike {
175+ // Classes have declarations, interface have signatures
176+ return ts . isPropertyDeclaration ( member ) || ts . isPropertySignature ( member ) ;
177+ }
178+
179+ /** Gets whether a member is a method. */
180+ private isMethod ( member : MemberElement ) : member is MethodLike {
181+ // Classes have declarations, interface have signatures
182+ return ts . isMethodDeclaration ( member ) || ts . isMethodSignature ( member ) ;
157183 }
158184}
159185
160186/** Extractor to pull info for API reference documentation for an Angular directive. */
161187class DirectiveExtractor extends ClassExtractor {
162188 constructor (
163189 declaration : ClassDeclaration & ts . ClassDeclaration ,
164- reference : Reference ,
190+ protected reference : Reference ,
165191 protected metadata : DirectiveMeta ,
166192 checker : ts . TypeChecker ,
167193 ) {
168- super ( declaration , reference , checker ) ;
194+ super ( declaration , checker ) ;
169195 }
170196
171197 /** Extract docs info for directives and components (including underlying class info). */
@@ -215,11 +241,11 @@ class DirectiveExtractor extends ClassExtractor {
215241class PipeExtractor extends ClassExtractor {
216242 constructor (
217243 declaration : ClassDeclaration & ts . ClassDeclaration ,
218- reference : Reference ,
244+ protected reference : Reference ,
219245 private metadata : PipeMeta ,
220246 typeChecker : ts . TypeChecker ,
221247 ) {
222- super ( declaration , reference , typeChecker ) ;
248+ super ( declaration , typeChecker ) ;
223249 }
224250
225251 override extract ( ) : PipeEntry {
@@ -236,11 +262,11 @@ class PipeExtractor extends ClassExtractor {
236262class NgModuleExtractor extends ClassExtractor {
237263 constructor (
238264 declaration : ClassDeclaration & ts . ClassDeclaration ,
239- reference : Reference ,
265+ protected reference : Reference ,
240266 private metadata : NgModuleMeta ,
241267 typeChecker : ts . TypeChecker ,
242268 ) {
243- super ( declaration , reference , typeChecker ) ;
269+ super ( declaration , typeChecker ) ;
244270 }
245271
246272 override extract ( ) : ClassEntry {
@@ -272,8 +298,17 @@ export function extractClass(
272298 } else if ( ngModuleMetadata ) {
273299 extractor = new NgModuleExtractor ( classDeclaration , ref , ngModuleMetadata , typeChecker ) ;
274300 } else {
275- extractor = new ClassExtractor ( classDeclaration , ref , typeChecker ) ;
301+ extractor = new ClassExtractor ( classDeclaration , typeChecker ) ;
276302 }
277303
278304 return extractor . extract ( ) ;
279305}
306+
307+ /** Extracts documentation info for an interface. */
308+ export function extractInterface (
309+ declaration : ts . InterfaceDeclaration ,
310+ typeChecker : ts . TypeChecker ,
311+ ) : InterfaceEntry {
312+ const extractor = new ClassExtractor ( declaration , typeChecker ) ;
313+ return extractor . extract ( ) ;
314+ }
0 commit comments