Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for synonyms #204

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@microsoft/tsdoc-config",
"comment": "Add support for configuring synonyms.",
"type": "minor"
}
],
"packageName": "@microsoft/tsdoc-config",
"email": "ron.buckton@microsoft.com"
}
11 changes: 11 additions & 0 deletions common/changes/@microsoft/tsdoc/synonyms_2019-12-19-22-47.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@microsoft/tsdoc",
"comment": "Add support for synonyms and the 'see' tag.",
"type": "minor"
}
],
"packageName": "@microsoft/tsdoc",
"email": "ron.buckton@microsoft.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "eslint-plugin-tsdoc",
"comment": "",
"type": "none"
}
],
"packageName": "eslint-plugin-tsdoc",
"email": "ron.buckton@microsoft.com"
}
56 changes: 55 additions & 1 deletion tsdoc-config/src/TSDocConfigFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,24 @@ interface ITagConfigJson {
tagName: string;
syntaxKind: 'inline' | 'block' | 'modifier';
allowMultiple?: boolean;
synonyms?: string[];
}

interface ISynonymConfigJson {
add?: ISynonymSetJson;
remove?: ISynonymSetJson;
}

interface ISynonymSetJson {
[tagName: string]: string[];
}

interface IConfigJson {
$schema: string;
tsdocVersion: string;
extends?: string[];
tagDefinitions: ITagConfigJson[];
synonyms?: ISynonymConfigJson;
}

/**
Expand All @@ -64,6 +75,8 @@ export class TSDocConfigFile {
private _tsdocSchema: string;
private readonly _extendsPaths: string[];
private readonly _tagDefinitions: TSDocTagDefinition[];
private readonly _synonymAdditions: Map<string, string[]>;
private readonly _synonymDeletions: Map<string, string[]>;

private constructor() {
this.log = new ParserMessageLog();
Expand All @@ -75,7 +88,9 @@ export class TSDocConfigFile {
this._fileMTime = 0;
this._tsdocSchema = '';
this._extendsPaths = [];
this._tagDefinitions= [];
this._tagDefinitions = [];
this._synonymAdditions = new Map<string, string[]>();
this._synonymDeletions = new Map<string, string[]>();
}

/**
Expand Down Expand Up @@ -132,6 +147,14 @@ export class TSDocConfigFile {
return this._tagDefinitions;
}

public get synonymAdditions(): ReadonlyMap<string, ReadonlyArray<string>> {
return this._synonymAdditions;
}

public get synonymDeletions(): ReadonlyMap<string, ReadonlyArray<string>> {
return this._synonymDeletions;
}

/**
* This can be used for cache eviction. It returns true if the modification timestamp has changed for
* any of the files that were read when loading this `TSDocConfigFile`, which indicates that the file should be
Expand Down Expand Up @@ -227,9 +250,22 @@ export class TSDocConfigFile {
this._tagDefinitions.push(new TSDocTagDefinition({
tagName: jsonTagDefinition.tagName,
syntaxKind: syntaxKind,
synonyms: jsonTagDefinition.synonyms,
allowMultiple: jsonTagDefinition.allowMultiple
}));
}
if (configJson.synonyms) {
if (configJson.synonyms.add) {
for (const tagName of Object.keys(configJson.synonyms.add)) {
this._synonymAdditions.set(tagName, configJson.synonyms.add[tagName]);
}
}
if (configJson.synonyms.remove) {
for (const tagName of Object.keys(configJson.synonyms.remove)) {
this._synonymDeletions.set(tagName, configJson.synonyms.remove[tagName]);
}
}
}
}

private _loadWithExtends(configFilePath: string, referencingConfigFile: TSDocConfigFile | undefined,
Expand Down Expand Up @@ -388,5 +424,23 @@ export class TSDocConfigFile {
for (const tagDefinition of this.tagDefinitions) {
configuration.addTagDefinition(tagDefinition);
}

this.synonymDeletions.forEach((synonyms, tagName) => {
const tagDefinition: TSDocTagDefinition | undefined
= configuration.tryGetTagDefinition(tagName);
if (!tagDefinition) {
throw new Error(`A tag with the name ${tagName} could not be found.`);
}
configuration.removeSynonym(tagDefinition, ...synonyms);
});

this.synonymAdditions.forEach((synonyms, tagName) => {
const tagDefinition: TSDocTagDefinition | undefined
= configuration.tryGetTagDefinition(tagName);
if (!tagDefinition) {
throw new Error(`A tag with the name ${tagName} could not be found.`);
}
configuration.addSynonym(tagDefinition, ...synonyms);
});
}
}
72 changes: 72 additions & 0 deletions tsdoc-config/src/__tests__/TSDocConfigFile.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as path from 'path';

import { TSDocConfigFile } from '../TSDocConfigFile';
import { TSDocSynonymCollection } from '@microsoft/tsdoc/lib/configuration/TSDocSynonymCollection';

function getRelativePath(testPath: string): string {
return path
Expand All @@ -23,10 +24,32 @@ expect.addSnapshotSerializer({
extendsPaths: value.extendsPaths,
extendsFiles: value.extendsFiles,
tagDefinitions: value.tagDefinitions,
synonymAdditions: Array.from(value.synonymAdditions).reduce<Record<string, ReadonlyArray<string>>>(
(obj, [key, value]) => {
obj[key] = value;
return obj;
},
{}
),
synonymDeletions: Array.from(value.synonymDeletions).reduce<Record<string, ReadonlyArray<string>>>(
(obj, [key, value]) => {
obj[key] = value;
return obj;
},
{}
),
messages: value.log.messages
});
}
});
expect.addSnapshotSerializer({
test(value: unknown) {
return value instanceof TSDocSynonymCollection;
},
print(value: TSDocSynonymCollection, serialize: (value: unknown) => string, indent: (str: string) => string): string {
return serialize(value.synonyms);
}
});

function testLoadingFolder(assetPath: string): TSDocConfigFile {
return TSDocConfigFile.loadForFolder(path.join(__dirname, assetPath));
Expand All @@ -40,6 +63,8 @@ test('Load p1', () => {
"fileNotFound": false,
"filePath": "assets/p1/tsdoc.json",
"messages": Array [],
"synonymAdditions": Object {},
"synonymDeletions": Object {},
"tagDefinitions": Array [],
"tsdocSchema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
}
Expand All @@ -66,6 +91,8 @@ test('Load p2', () => {
"unformattedText": "File not found",
},
],
"synonymAdditions": Object {},
"synonymDeletions": Object {},
"tagDefinitions": Array [],
"tsdocSchema": "",
}
Expand All @@ -81,8 +108,11 @@ test('Load p3', () => {
"fileNotFound": false,
"filePath": "assets/p3/base1/tsdoc-base1.json",
"messages": Array [],
"synonymAdditions": Object {},
"synonymDeletions": Object {},
"tagDefinitions": Array [
TSDocTagDefinition {
"_synonymCollection": Array [],
"allowMultiple": false,
"standardization": "None",
"syntaxKind": 2,
Expand All @@ -98,8 +128,11 @@ test('Load p3', () => {
"fileNotFound": false,
"filePath": "assets/p3/base2/tsdoc-base2.json",
"messages": Array [],
"synonymAdditions": Object {},
"synonymDeletions": Object {},
"tagDefinitions": Array [
TSDocTagDefinition {
"_synonymCollection": Array [],
"allowMultiple": false,
"standardization": "None",
"syntaxKind": 2,
Expand All @@ -117,8 +150,11 @@ test('Load p3', () => {
"fileNotFound": false,
"filePath": "assets/p3/tsdoc.json",
"messages": Array [],
"synonymAdditions": Object {},
"synonymDeletions": Object {},
"tagDefinitions": Array [
TSDocTagDefinition {
"_synonymCollection": Array [],
"allowMultiple": false,
"standardization": "None",
"syntaxKind": 2,
Expand All @@ -140,8 +176,11 @@ test('Load p4', () => {
"fileNotFound": false,
"filePath": "assets/p4/node_modules/example-lib/dist/tsdoc-example.json",
"messages": Array [],
"synonymAdditions": Object {},
"synonymDeletions": Object {},
"tagDefinitions": Array [
TSDocTagDefinition {
"_synonymCollection": Array [],
"allowMultiple": false,
"standardization": "None",
"syntaxKind": 2,
Expand All @@ -158,8 +197,11 @@ test('Load p4', () => {
"fileNotFound": false,
"filePath": "assets/p4/tsdoc.json",
"messages": Array [],
"synonymAdditions": Object {},
"synonymDeletions": Object {},
"tagDefinitions": Array [
TSDocTagDefinition {
"_synonymCollection": Array [],
"allowMultiple": false,
"standardization": "None",
"syntaxKind": 2,
Expand All @@ -171,3 +213,33 @@ test('Load p4', () => {
}
`);
});
test('Load synonyms', () => {
expect(testLoadingFolder('assets/synonyms')).toMatchInlineSnapshot(`
Object {
"extendsFiles": Array [],
"extendsPaths": Array [],
"fileNotFound": false,
"filePath": "assets/synonyms/tsdoc.json",
"messages": Array [],
"synonymAdditions": Object {
"@readonly": Array [
"@readonly2",
],
},
"synonymDeletions": Object {},
"tagDefinitions": Array [
TSDocTagDefinition {
"_synonymCollection": Array [
"@bar",
],
"allowMultiple": false,
"standardization": "None",
"syntaxKind": 1,
"tagName": "@foo",
"tagNameWithUpperCase": "@FOO",
},
],
"tsdocSchema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
}
`);
});
2 changes: 2 additions & 0 deletions tsdoc-config/src/__tests__/assets/synonyms/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
11 changes: 11 additions & 0 deletions tsdoc-config/src/__tests__/assets/synonyms/tsdoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
"tagDefinitions": [
{ "tagName": "@foo", "syntaxKind": "block", "synonyms": ["@bar"] }
],
"synonyms": {
"add": {
"@readonly": ["@readonly2"]
}
}
}
34 changes: 34 additions & 0 deletions tsdoc/schemas/tsdoc.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@
"items": {
"$ref": "#/definitions/tsdocTagDefinition"
}
},

"synonyms": {
"description": "Additional synonyms to add or remove from built-in tag definitions.",
"type": "object",
"properties": {
"add": {
"description": "Synonyms to add.",
"$ref": "#/definitions/synonymSet"
},
"remove": {
"description": "Synonyms to remove.",
"$ref": "#/definitions/synonymSet"
}
},
"additionalProperties": false
}
},
"required": [ "$schema" ],
Expand All @@ -44,10 +60,28 @@
"allowMultiple": {
"description": "If true, then this tag may appear multiple times in a doc comment. By default, a tag may only appear once.",
"type": "boolean"
},
"synonyms": {
"description": "Synonyms of the custom tag. TSDoc tag names start with an at-sign (@) followed by ASCII letters using camelCase capitalization.",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["tagName", "syntaxKind"],
"additionalProperties": false
},
"synonymSet": {
"description": "Provides the assocation between a tag and the synonyms to be added or removed.",
"type": "object",
"additionalProperties": {
"description": "Synonyms of the tag. TSDoc tag names start with an at-sign (@) followed by ASCII letters using camelCase capitalization.",
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
15 changes: 15 additions & 0 deletions tsdoc/src/__tests__/ParsingBasics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
TSDocTagSyntaxKind
} from '../index';
import { TestHelpers } from '../parser/__tests__/TestHelpers';
import { StandardTags } from '../details/StandardTags';

test('01 Simple @beta and @internal extraction', () => {
const parserContext: ParserContext = TestHelpers.parseAndMatchDocCommentSnapshot([
Expand Down Expand Up @@ -157,4 +158,18 @@ test('07 Invalid JSDoc type', () => {
' * @public',
' */'
].join('\n'));
});

test('08 synonyms', () => {
const configuration: TSDocConfiguration = new TSDocConfiguration();
configuration.addSynonym(StandardTags.readonly, "@readonly2");
TestHelpers.parseAndMatchDocCommentSnapshot([
'/**',
' * @param a - description1',
' * @arg b - description2',
' * @argument c - description3',
' * @return description4',
' * @readonly2',
' */'
].join('\n'), configuration);
});
Loading