7
7
ParserMessage ,
8
8
TextRange ,
9
9
IParserMessageParameters ,
10
+ ITSDocTagDefinitionParameters ,
10
11
} from '@microsoft/tsdoc' ;
11
12
import * as fs from 'fs' ;
12
13
import * as resolve from 'resolve' ;
@@ -36,9 +37,9 @@ interface ITagConfigJson {
36
37
37
38
interface IConfigJson {
38
39
$schema : string ;
39
- tsdocVersion : string ;
40
40
extends ?: string [ ] ;
41
- tagDefinitions : ITagConfigJson [ ] ;
41
+ tagDefinitions ?: ITagConfigJson [ ] ;
42
+ supportForTags ?: { [ tagName : string ] : boolean } ;
42
43
}
43
44
44
45
/**
@@ -64,6 +65,8 @@ export class TSDocConfigFile {
64
65
private _tsdocSchema : string ;
65
66
private readonly _extendsPaths : string [ ] ;
66
67
private readonly _tagDefinitions : TSDocTagDefinition [ ] ;
68
+ private readonly _tagDefinitionNames : Set < string > ;
69
+ private readonly _supportForTags : Map < string , boolean > ;
67
70
68
71
private constructor ( ) {
69
72
this . log = new ParserMessageLog ( ) ;
@@ -76,6 +79,8 @@ export class TSDocConfigFile {
76
79
this . _tsdocSchema = '' ;
77
80
this . _extendsPaths = [ ] ;
78
81
this . _tagDefinitions = [ ] ;
82
+ this . _tagDefinitionNames = new Set ( ) ;
83
+ this . _supportForTags = new Map ( ) ;
79
84
}
80
85
81
86
/**
@@ -132,6 +137,75 @@ export class TSDocConfigFile {
132
137
return this . _tagDefinitions ;
133
138
}
134
139
140
+ public get supportForTags ( ) : ReadonlyMap < string , boolean > {
141
+ return this . _supportForTags ;
142
+ }
143
+
144
+ /**
145
+ * Removes all items from the `tagDefinitions` array.
146
+ */
147
+ public clearTagDefinitions ( ) : void {
148
+ this . _tagDefinitions . length = 0 ;
149
+ this . _tagDefinitionNames . clear ( ) ;
150
+ }
151
+
152
+ /**
153
+ * Adds a new item to the `tagDefinitions` array.
154
+ */
155
+ public addTagDefinition ( parameters : ITSDocTagDefinitionParameters ) : void {
156
+ // This validates the tag name
157
+ const tagDefinition : TSDocTagDefinition = new TSDocTagDefinition ( parameters ) ;
158
+
159
+ if ( this . _tagDefinitionNames . has ( tagDefinition . tagNameWithUpperCase ) ) {
160
+ throw new Error ( `A tag defintion was already added with the tag name "${ parameters . tagName } "` ) ;
161
+ }
162
+ this . _tagDefinitionNames . add ( tagDefinition . tagName ) ;
163
+
164
+ this . _tagDefinitions . push ( tagDefinition ) ;
165
+ }
166
+
167
+ // Similar to addTagDefinition() but reports errors using _reportError()
168
+ private _addTagDefinitionForLoad ( parameters : ITSDocTagDefinitionParameters ) : void {
169
+ let tagDefinition : TSDocTagDefinition ;
170
+ try {
171
+ // This validates the tag name
172
+ tagDefinition = new TSDocTagDefinition ( parameters ) ;
173
+ } catch ( error ) {
174
+ this . _reportError ( {
175
+ messageId : TSDocMessageId . ConfigFileInvalidTagName ,
176
+ messageText : error . message ,
177
+ textRange : TextRange . empty ,
178
+ } ) ;
179
+ return ;
180
+ }
181
+
182
+ if ( this . _tagDefinitionNames . has ( tagDefinition . tagNameWithUpperCase ) ) {
183
+ this . _reportError ( {
184
+ messageId : TSDocMessageId . ConfigFileDuplicateTagName ,
185
+ messageText : `The "tagDefinitions" field specifies more than one tag with the name "${ parameters . tagName } "` ,
186
+ textRange : TextRange . empty ,
187
+ } ) ;
188
+ }
189
+ this . _tagDefinitionNames . add ( tagDefinition . tagName ) ;
190
+
191
+ this . _tagDefinitions . push ( tagDefinition ) ;
192
+ }
193
+
194
+ /**
195
+ * Removes all entries from the "supportForTags" map.
196
+ */
197
+ public clearSupportForTags ( ) : void {
198
+ this . _supportForTags . clear ( ) ;
199
+ }
200
+
201
+ /**
202
+ * Sets an entry in the "supportForTags" map.
203
+ */
204
+ public setSupportForTag ( tagName : string , supported : boolean ) : void {
205
+ TSDocTagDefinition . validateTSDocTagName ( tagName ) ;
206
+ this . _supportForTags . set ( tagName , supported ) ;
207
+ }
208
+
135
209
/**
136
210
* This can be used for cache eviction. It returns true if the modification timestamp has changed for
137
211
* any of the files that were read when loading this `TSDocConfigFile`, which indicates that the file should be
@@ -230,13 +304,20 @@ export class TSDocConfigFile {
230
304
// The JSON schema should have caught this error
231
305
throw new Error ( 'Unexpected tag kind' ) ;
232
306
}
233
- this . _tagDefinitions . push (
234
- new TSDocTagDefinition ( {
235
- tagName : jsonTagDefinition . tagName ,
236
- syntaxKind : syntaxKind ,
237
- allowMultiple : jsonTagDefinition . allowMultiple ,
238
- } )
239
- ) ;
307
+
308
+ this . _addTagDefinitionForLoad ( {
309
+ tagName : jsonTagDefinition . tagName ,
310
+ syntaxKind : syntaxKind ,
311
+ allowMultiple : jsonTagDefinition . allowMultiple ,
312
+ } ) ;
313
+ }
314
+
315
+ if ( configJson . supportForTags ) {
316
+ for ( const tagName of Object . keys ( configJson . supportForTags ) ) {
317
+ const supported : boolean = configJson . supportForTags [ tagName ] ;
318
+
319
+ this . _supportForTags . set ( tagName , supported ) ;
320
+ }
240
321
}
241
322
}
242
323
@@ -357,6 +438,87 @@ export class TSDocConfigFile {
357
438
return configFile ;
358
439
}
359
440
441
+ /**
442
+ * Initializes a TSDocConfigFile object using the state from the provided `TSDocConfiguration` object.
443
+ */
444
+ public static loadFromParser ( configuration : TSDocConfiguration ) : TSDocConfigFile {
445
+ const configFile : TSDocConfigFile = new TSDocConfigFile ( ) ;
446
+
447
+ for ( const tagDefinition of configuration . tagDefinitions ) {
448
+ configFile . addTagDefinition ( {
449
+ syntaxKind : tagDefinition . syntaxKind ,
450
+ tagName : tagDefinition . tagName ,
451
+ allowMultiple : tagDefinition . allowMultiple ,
452
+ } ) ;
453
+ }
454
+
455
+ for ( const tagDefinition of configuration . supportedTagDefinitions ) {
456
+ configFile . setSupportForTag ( tagDefinition . tagName , true ) ;
457
+ }
458
+
459
+ return configFile ;
460
+ }
461
+
462
+ /**
463
+ * Writes the config file content to a JSON file with the specified file path.
464
+ */
465
+ public saveFile ( jsonFilePath : string ) : void {
466
+ const jsonObject : unknown = this . saveToObject ( ) ;
467
+ const jsonContent : string = JSON . stringify ( jsonObject , undefined , 2 ) ;
468
+ fs . writeFileSync ( jsonFilePath , jsonContent ) ;
469
+ }
470
+
471
+ /**
472
+ * Writes the object state into a JSON-serializable object.
473
+ */
474
+ public saveToObject ( ) : unknown {
475
+ const configJson : IConfigJson = {
476
+ $schema : TSDocConfigFile . CURRENT_SCHEMA_URL ,
477
+ } ;
478
+
479
+ if ( this . tagDefinitions . length > 0 ) {
480
+ configJson . tagDefinitions = [ ] ;
481
+ for ( const tagDefinition of this . tagDefinitions ) {
482
+ configJson . tagDefinitions . push ( TSDocConfigFile . _serializeTagDefinition ( tagDefinition ) ) ;
483
+ }
484
+ }
485
+
486
+ if ( this . supportForTags . size > 0 ) {
487
+ configJson . supportForTags = { } ;
488
+ this . supportForTags . forEach ( ( supported , tagName ) => {
489
+ configJson . supportForTags ! [ tagName ] = supported ;
490
+ } ) ;
491
+ }
492
+
493
+ return configJson ;
494
+ }
495
+
496
+ private static _serializeTagDefinition ( tagDefinition : TSDocTagDefinition ) : ITagConfigJson {
497
+ let syntaxKind : 'inline' | 'block' | 'modifier' | undefined ;
498
+ switch ( tagDefinition . syntaxKind ) {
499
+ case TSDocTagSyntaxKind . InlineTag :
500
+ syntaxKind = 'inline' ;
501
+ break ;
502
+ case TSDocTagSyntaxKind . BlockTag :
503
+ syntaxKind = 'block' ;
504
+ break ;
505
+ case TSDocTagSyntaxKind . ModifierTag :
506
+ syntaxKind = 'modifier' ;
507
+ break ;
508
+ default :
509
+ throw new Error ( 'Unimplemented TSDocTagSyntaxKind' ) ;
510
+ }
511
+
512
+ const tagConfigJson : ITagConfigJson = {
513
+ tagName : tagDefinition . tagName ,
514
+ syntaxKind,
515
+ } ;
516
+ if ( tagDefinition . allowMultiple ) {
517
+ tagConfigJson . allowMultiple = true ;
518
+ }
519
+ return tagConfigJson ;
520
+ }
521
+
360
522
/**
361
523
* Returns a report of any errors that occurred while attempting to load this file or any files
362
524
* referenced via the "extends" field.
@@ -398,5 +560,19 @@ export class TSDocConfigFile {
398
560
for ( const tagDefinition of this . tagDefinitions ) {
399
561
configuration . addTagDefinition ( tagDefinition ) ;
400
562
}
563
+
564
+ this . supportForTags . forEach ( ( supported : boolean , tagName : string ) => {
565
+ const tagDefinition : TSDocTagDefinition | undefined = configuration . tryGetTagDefinition ( tagName ) ;
566
+ if ( tagDefinition ) {
567
+ // Note that setSupportForTag() automatically enables configuration.validation.reportUnsupportedTags
568
+ configuration . setSupportForTag ( tagDefinition , supported ) ;
569
+ } else {
570
+ this . _reportError ( {
571
+ messageId : TSDocMessageId . ConfigFileUndefinedTag ,
572
+ messageText : `The "supportForTags" field refers to an undefined tag ${ JSON . stringify ( tagName ) } .` ,
573
+ textRange : TextRange . empty ,
574
+ } ) ;
575
+ }
576
+ } ) ;
401
577
}
402
578
}
0 commit comments