11import { ITextElement , IDocElement , IHrefLinkElement , ICodeLinkElement , ISeeDocElement } from './IDocElement' ;
22import ApiDefinitionReference from './ApiDefinitionReference' ;
3+ import ApiDocumentation from './definitions/ApiDocumentation' ;
4+ import { ApiItemKind } from './definitions/ApiItem' ;
35import Token , { TokenType } from './Token' ;
46import Tokenizer from './Tokenizer' ;
7+ import ResolvedApiItem from './ResolvedApiItem' ;
58
69export default class DocElementParser {
710
@@ -57,7 +60,7 @@ export default class DocElementParser {
5760 return { kind : 'textDocElement' , value : text } as ITextElement ;
5861 }
5962
60- public static parse ( tokenizer : Tokenizer , reportError : ( message : string ) => void ) : IDocElement [ ] {
63+ public static parse ( documentation : ApiDocumentation , tokenizer : Tokenizer ) : IDocElement [ ] {
6164 const docElements : IDocElement [ ] = [ ] ;
6265 let parsing : boolean = true ;
6366 let token : Token ;
@@ -75,7 +78,7 @@ export default class DocElementParser {
7578 tokenizer . getToken ( ) ;
7679 docElements . push ( {
7780 kind : 'seeDocElement' ,
78- seeElements : this . parse ( tokenizer , reportError )
81+ seeElements : this . parse ( documentation , tokenizer )
7982 } as ISeeDocElement ) ;
8083 break ;
8184 default :
@@ -84,10 +87,22 @@ export default class DocElementParser {
8487 }
8588 } else if ( token . type === TokenType . Inline ) {
8689 switch ( token . tag ) {
90+ case '@inheritdoc' :
91+ tokenizer . getToken ( ) ;
92+ if ( docElements . length > 0 || documentation . summary . length > 0 ) {
93+ documentation . reportError ( 'Cannot provide summary in JsDoc if @inheritdoc tag is given' ) ;
94+ }
95+ documentation . incompleteInheritdocs . push ( token ) ;
96+ documentation . isDocInherited = true ;
97+ break ;
8798 case '@link' :
88- const linkDocElement : ICodeLinkElement | IHrefLinkElement = this . parseLinkTag ( token , reportError ) ;
99+ const linkDocElement : ICodeLinkElement | IHrefLinkElement = this . parseLinkTag ( documentation , token ) ;
89100 if ( linkDocElement ) {
101+ // Push to docElements to retain position in the documentation
90102 docElements . push ( linkDocElement ) ;
103+ if ( linkDocElement . referenceType === 'code' ) {
104+ documentation . incompleteLinks . push ( linkDocElement ) ;
105+ }
91106 }
92107 tokenizer . getToken ( ) ; // get the link token
93108 break ;
@@ -99,7 +114,7 @@ export default class DocElementParser {
99114 docElements . push ( { kind : 'textDocElement' , value : token . text } as ITextElement ) ;
100115 tokenizer . getToken ( ) ;
101116 } else {
102- reportError ( `Unidentifiable Token ${ token . type } ${ token . tag } ${ token . text } ` ) ;
117+ documentation . reportError ( `Unidentifiable Token ${ token . type } ${ token . tag } ${ token . text } ` ) ;
103118 }
104119 }
105120 return docElements ;
@@ -119,10 +134,9 @@ export default class DocElementParser {
119134 * \{@link @microsoft/sp-core-library:Guid.newGuid | new Guid Object \ }
120135 * \{@link @microsoft/sp-core-library:Guid.newGuid \ }
121136 */
122- public static parseLinkTag ( tokenItem : Token ,
123- reportError : ( message : string ) => void ) : IHrefLinkElement | ICodeLinkElement {
137+ public static parseLinkTag ( documentation : ApiDocumentation , tokenItem : Token ) : IHrefLinkElement | ICodeLinkElement {
124138 if ( ! tokenItem . text ) {
125- reportError ( 'Invalid @link inline token, a url or API definition reference must be given' ) ;
139+ documentation . reportError ( 'Invalid @link inline token, a url or API definition reference must be given' ) ;
126140 return ;
127141 }
128142
@@ -134,7 +148,7 @@ export default class DocElementParser {
134148 }
135149 } ) ;
136150 if ( pipeSplitContent . length > 2 ) {
137- reportError ( 'Invalid @link parameters, at most one pipe character allowed.' ) ;
151+ documentation . reportError ( 'Invalid @link parameters, at most one pipe character allowed.' ) ;
138152 return ;
139153 }
140154
@@ -145,7 +159,7 @@ export default class DocElementParser {
145159
146160 // Make sure only a single url is given
147161 if ( urlContent . length > 1 && urlContent [ 1 ] !== '' ) {
148- reportError ( 'Invalid @link parameter, url must be a single string.' ) ;
162+ documentation . reportError ( 'Invalid @link parameter, url must be a single string.' ) ;
149163 return ;
150164 }
151165
@@ -160,7 +174,7 @@ export default class DocElementParser {
160174 // we are processing an API definition reference
161175 const apiDefitionRef : ApiDefinitionReference = ApiDefinitionReference . createFromString (
162176 pipeSplitContent [ 0 ] ,
163- reportError
177+ documentation . reportError
164178 ) ;
165179
166180 // Once we can locate local API definitions, an error should be reported here if not found.
@@ -181,7 +195,7 @@ export default class DocElementParser {
181195 if ( linkDocElement && pipeSplitContent . length > 1 ) {
182196 const displayTextParts : string [ ] = pipeSplitContent [ 1 ] . match ( this . _wordRegEx ) ;
183197 if ( displayTextParts && displayTextParts [ 0 ] . length !== pipeSplitContent [ 1 ] . length ) {
184- reportError ( 'Display name in @link token may only contain alphabetic characters.' ) ;
198+ documentation . reportError ( 'Display name in @link token may only contain alphabetic characters.' ) ;
185199 return ;
186200 }
187201 // Full match is valid text
@@ -190,4 +204,87 @@ export default class DocElementParser {
190204
191205 return linkDocElement ;
192206 }
207+
208+ /**
209+ * This method parses the semantic information in an \@inheritdoc JSDoc tag and sets
210+ * all the relevant documenation properties from the inherited doc onto the documenation
211+ * of the current api item.
212+ *
213+ * The format for the \@inheritdoc tag is {\@inheritdoc scopeName/packageName:exportName.memberName}.
214+ * For more information on the format see IInheritdocRef.
215+ */
216+ public static parseInheritDoc ( documentation : ApiDocumentation , token : Token ) : void {
217+
218+ // Check to make sure the API definition reference is at most one string
219+ const tokenChunks : string [ ] = token . text . split ( ' ' ) ;
220+ if ( tokenChunks . length > 1 ) {
221+ documentation . reportError ( 'Too many parameters for @inheritdoc inline tag.' +
222+ 'The format should be {@inheritdoc scopeName/packageName:exportName}. Extra parameters are ignored' ) ;
223+ return ;
224+ }
225+
226+ // Create the IApiDefinitionReference object
227+ // Deconstruct the API reference expression 'scopeName/packageName:exportName.memberName'
228+ const apiDefinitionRef : ApiDefinitionReference = ApiDefinitionReference . createFromString (
229+ token . text ,
230+ documentation . reportError
231+ ) ;
232+ // if API reference expression is formatted incorrectly then apiDefinitionRef will be undefined
233+ if ( ! apiDefinitionRef ) {
234+ documentation . reportError ( 'Incorrecty formatted API definition reference' ) ;
235+ return ;
236+ }
237+
238+ // Atempt to locate the apiDefinitionRef
239+ const resolvedApiItem : ResolvedApiItem = documentation . referenceResolver . resolve (
240+ apiDefinitionRef ,
241+ documentation . extractor . package ,
242+ documentation . reportError
243+ ) ;
244+
245+ // If no resolvedApiItem found then nothing to inherit
246+ // But for the time being set the summary to a text object
247+ if ( ! resolvedApiItem ) {
248+ const textDocItem : IDocElement = {
249+ kind : 'textDocElement' ,
250+ value : `See documentation for ${ tokenChunks [ 0 ] } `
251+ } as ITextElement ;
252+ documentation . summary = [ textDocItem ] ;
253+ return ;
254+ }
255+
256+ // We are going to copy the resolvedApiItem's documentation
257+ // We must make sure it's documentation can be completed,
258+ // if we cannot, an error will be reported viathe documentation error handler.
259+ // This will only be the case our resolvedApiItem was created from a local
260+ // ApiItem. Resolutions from JSON will have an undefined 'apiItem' property.
261+ // Example: a circular reference will report an error.
262+ if ( resolvedApiItem . apiItem ) {
263+ resolvedApiItem . apiItem . completeInitialization ( ) ;
264+ }
265+
266+ // inheritdoc found, copy over IDocBase properties
267+ documentation . summary = resolvedApiItem . summary ;
268+ documentation . remarks = resolvedApiItem . remarks ;
269+
270+ // Copy over detailed properties if neccessary
271+ // Add additional cases if needed
272+ switch ( resolvedApiItem . kind ) {
273+ case ApiItemKind . Function :
274+ documentation . parameters = resolvedApiItem . params ;
275+ documentation . returnsMessage = resolvedApiItem . returnsMessage ;
276+ break ;
277+ case ApiItemKind . Method :
278+ documentation . parameters = resolvedApiItem . params ;
279+ documentation . returnsMessage = resolvedApiItem . returnsMessage ;
280+ break ;
281+ }
282+
283+ // Check if inheritdoc is depreacted
284+ // We need to check if this documentation has a deprecated message
285+ // but it may not appear until after this token.
286+ if ( resolvedApiItem . deprecatedMessage ) {
287+ documentation . isDocInheritedDeprecated = true ;
288+ }
289+ }
193290}
0 commit comments