Skip to content

Commit cbe0ae4

Browse files
authored
Merge pull request #277 from microsoft/octogonz/tsdoc-config-features
Add "supportForTags" field to tsdoc.json schema
2 parents 600ecd9 + 8601691 commit cbe0ae4

13 files changed

+650
-14
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@microsoft/tsdoc-config",
5+
"comment": "Add new \"supportForTags\" field to tsdoc.json schema",
6+
"type": "minor"
7+
}
8+
],
9+
"packageName": "@microsoft/tsdoc-config",
10+
"email": "4673363+octogonz@users.noreply.github.com"
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@microsoft/tsdoc-config",
5+
"comment": "Add new APIs: TSDocConfigFile.supportForTags, .clearTagDefinitions(), .addTagDefinition(), .clearSupportForTags(), .setSupportForTag(), .loadFromParser(), .saveFile(), .saveToObject()",
6+
"type": "minor"
7+
}
8+
],
9+
"packageName": "@microsoft/tsdoc-config",
10+
"email": "4673363+octogonz@users.noreply.github.com"
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@microsoft/tsdoc",
5+
"comment": "Add new APIs: TSDocConfiguration.clear() and TSDocTagDefinition.validateTSDocTagName()",
6+
"type": "minor"
7+
}
8+
],
9+
"packageName": "@microsoft/tsdoc",
10+
"email": "4673363+octogonz@users.noreply.github.com"
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@microsoft/tsdoc",
5+
"comment": "Add new \"supportForTags\" field to tsdoc.json schema",
6+
"type": "minor"
7+
}
8+
],
9+
"packageName": "@microsoft/tsdoc",
10+
"email": "4673363+octogonz@users.noreply.github.com"
11+
}

tsdoc-config/src/TSDocConfigFile.ts

Lines changed: 185 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ParserMessage,
88
TextRange,
99
IParserMessageParameters,
10+
ITSDocTagDefinitionParameters,
1011
} from '@microsoft/tsdoc';
1112
import * as fs from 'fs';
1213
import * as resolve from 'resolve';
@@ -36,9 +37,9 @@ interface ITagConfigJson {
3637

3738
interface IConfigJson {
3839
$schema: string;
39-
tsdocVersion: string;
4040
extends?: string[];
41-
tagDefinitions: ITagConfigJson[];
41+
tagDefinitions?: ITagConfigJson[];
42+
supportForTags?: { [tagName: string]: boolean };
4243
}
4344

4445
/**
@@ -64,6 +65,8 @@ export class TSDocConfigFile {
6465
private _tsdocSchema: string;
6566
private readonly _extendsPaths: string[];
6667
private readonly _tagDefinitions: TSDocTagDefinition[];
68+
private readonly _tagDefinitionNames: Set<string>;
69+
private readonly _supportForTags: Map<string, boolean>;
6770

6871
private constructor() {
6972
this.log = new ParserMessageLog();
@@ -76,6 +79,8 @@ export class TSDocConfigFile {
7679
this._tsdocSchema = '';
7780
this._extendsPaths = [];
7881
this._tagDefinitions = [];
82+
this._tagDefinitionNames = new Set();
83+
this._supportForTags = new Map();
7984
}
8085

8186
/**
@@ -132,6 +137,75 @@ export class TSDocConfigFile {
132137
return this._tagDefinitions;
133138
}
134139

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+
135209
/**
136210
* This can be used for cache eviction. It returns true if the modification timestamp has changed for
137211
* 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 {
230304
// The JSON schema should have caught this error
231305
throw new Error('Unexpected tag kind');
232306
}
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+
}
240321
}
241322
}
242323

@@ -357,6 +438,87 @@ export class TSDocConfigFile {
357438
return configFile;
358439
}
359440

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+
360522
/**
361523
* Returns a report of any errors that occurred while attempting to load this file or any files
362524
* referenced via the "extends" field.
@@ -398,5 +560,19 @@ export class TSDocConfigFile {
398560
for (const tagDefinition of this.tagDefinitions) {
399561
configuration.addTagDefinition(tagDefinition);
400562
}
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+
});
401577
}
402578
}

0 commit comments

Comments
 (0)