@@ -45,10 +45,21 @@ const yamlApiSchema: JsonSchema = JsonSchema.fromFile(path.join(__dirname, 'type
4545 */
4646export class YamlDocumenter {
4747 private _docItemSet : DocItemSet ;
48+
49+ // This is used by the _linkToUidIfPossible() workaround.
50+ // It stores a mapping from type name (e.g. "MyClass") to the corresponding DocItem.
51+ // If the mapping would be ambiguous (e.g. "MyClass" is defined by multiple packages)
52+ // then it is excluded from the mapping. Also excluded are DocItems (such as package
53+ // and function) which are not typically used as a data type.
54+ private _docItemsByTypeName : Map < string , DocItem > ;
55+
4856 private _outputFolder : string ;
4957
5058 public constructor ( docItemSet : DocItemSet ) {
5159 this . _docItemSet = docItemSet ;
60+ this . _docItemsByTypeName = new Map < string , DocItem > ( ) ;
61+
62+ this . _initDocItemsByTypeName ( ) ;
5263 }
5364
5465 public generateFiles ( outputFolder : string ) : void { // virtual
@@ -335,7 +346,7 @@ export class YamlDocumenter {
335346 . replace ( / ^ \s * - \s + / , '' ) ; // temporary workaround for people who mistakenly add a hyphen, e.g. "@returns - blah"
336347
337348 syntax . return = {
338- type : [ apiMethod . returnValue . type ] ,
349+ type : [ this . _linkToUidIfPossible ( apiMethod . returnValue . type ) ] ,
339350 description : returnDescription
340351 } ;
341352 }
@@ -347,7 +358,7 @@ export class YamlDocumenter {
347358 {
348359 id : parameterName ,
349360 description : this . _renderMarkdown ( apiParameter . description , docItem ) ,
350- type : [ apiParameter . type || '' ]
361+ type : [ this . _linkToUidIfPossible ( apiParameter . type || '' ) ]
351362 } as IYamlParameter
352363 ) ;
353364 }
@@ -369,7 +380,7 @@ export class YamlDocumenter {
369380
370381 if ( apiProperty . type ) {
371382 syntax . return = {
372- type : [ apiProperty . type ]
383+ type : [ this . _linkToUidIfPossible ( apiProperty . type ) ]
373384 } ;
374385 }
375386 }
@@ -454,6 +465,89 @@ export class YamlDocumenter {
454465 return result ;
455466 }
456467
468+ /**
469+ * Initialize the _docItemsByTypeName() data structure.
470+ */
471+ private _initDocItemsByTypeName ( ) : void {
472+ // Collect the _docItemsByTypeName table
473+ const ambiguousNames : Set < string > = new Set < string > ( ) ;
474+
475+ this . _docItemSet . forEach ( ( docItem : DocItem ) => {
476+ switch ( docItem . kind ) {
477+ case DocItemKind . Class :
478+ case DocItemKind . Enum :
479+ case DocItemKind . Interface :
480+ // Attempt to register both the fully qualified name and the short name
481+ const namesForType : string [ ] = [ docItem . name ] ;
482+
483+ // Note that nameWithDot cannot conflict with docItem.name (because docItem.name
484+ // cannot contain a dot)
485+ const nameWithDot : string | undefined = this . _getTypeNameWithDot ( docItem ) ;
486+ if ( nameWithDot ) {
487+ namesForType . push ( nameWithDot ) ;
488+ }
489+
490+ // Register all names
491+ for ( const typeName of namesForType ) {
492+ if ( ambiguousNames . has ( typeName ) ) {
493+ break ;
494+ }
495+
496+ if ( this . _docItemsByTypeName . has ( typeName ) ) {
497+ // We saw this name before, so it's an ambiguous match
498+ ambiguousNames . add ( typeName ) ;
499+ break ;
500+ }
501+
502+ this . _docItemsByTypeName . set ( typeName , docItem ) ;
503+ }
504+
505+ break ;
506+ }
507+ } ) ;
508+
509+ // Remove the ambiguous matches
510+ for ( const ambiguousName of ambiguousNames ) {
511+ this . _docItemsByTypeName . delete ( ambiguousName ) ;
512+ }
513+ }
514+
515+ /**
516+ * This is a temporary workaround to enable limited autolinking of API item types
517+ * until the YAML file format is enhanced to support general hyperlinks.
518+ * @remarks
519+ * In the current version, fields such as IApiProperty.type allow either:
520+ * (1) a UID identifier such as "node-core-library.JsonFile" which will be rendered
521+ * as a hyperlink to that type name, or (2) a block of freeform text that must not
522+ * contain any Markdown links. The _substituteUidForSimpleType() function assumes
523+ * it is given #2 but substitutes #1 if the name can be matched to a DocItem.
524+ */
525+ private _linkToUidIfPossible ( typeName : string ) : string {
526+ // Note that typeName might be a _getTypeNameWithDot() name or it might be a simple class name
527+ const docItem : DocItem | undefined = this . _docItemsByTypeName . get ( typeName . trim ( ) ) ;
528+ if ( docItem ) {
529+ // Substitute the UID
530+ return this . _getUid ( docItem ) ;
531+ }
532+ return typeName ;
533+ }
534+
535+ /**
536+ * If the docItem represents a scoped name such as "my-library:MyNamespace.MyClass",
537+ * this returns a string such as "MyNamespace.MyClass". If the result would not
538+ * have at least one dot in it, then undefined is returned.
539+ */
540+ private _getTypeNameWithDot ( docItem : DocItem ) : string | undefined {
541+ const hierarchy : DocItem [ ] = docItem . getHierarchy ( ) ;
542+ if ( hierarchy . length > 0 && hierarchy [ 0 ] . kind === DocItemKind . Package ) {
543+ hierarchy . shift ( ) ; // ignore the package qualifier
544+ }
545+ if ( hierarchy . length < 1 ) {
546+ return undefined ;
547+ }
548+ return hierarchy . map ( x => x . name ) . join ( '.' ) ;
549+ }
550+
457551 private _getYamlItemName ( docItem : DocItem ) : string {
458552 if ( docItem . parent && docItem . parent . kind === DocItemKind . Namespace ) {
459553 // For members a namespace, show the full name excluding the package part:
0 commit comments