-
Notifications
You must be signed in to change notification settings - Fork 604
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
[api-extractor] Adds package-defined TSDoc tag support #1950
Changes from 13 commits
a3010f7
03b0127
ff63440
5451da7
61bdcb6
6bd65e4
7ef3840
b1004b0
26d4b2c
0a5d0a4
32b306e
9ecc08f
52829d8
0ce7230
7d49b39
9bbf43f
ad628a8
00b9aee
ff5f108
bbcbe92
156aed9
8a5d5c2
f55ebc2
00ed463
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,18 @@ import { ApiDocumentedItem, IApiDocumentedItemOptions } from '../items/ApiDocume | |
import { ApiEntryPoint } from './ApiEntryPoint'; | ||
import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; | ||
import { DeserializerContext, ApiJsonSchemaVersion } from './DeserializerContext'; | ||
import { TSDocConfiguration, TSDocTagDefinition, TSDocTagSyntaxKind } from '@microsoft/tsdoc'; | ||
|
||
interface ITagConfigJson { | ||
tagName: string; | ||
syntaxKind: 'inline' | 'block' | 'modifier'; | ||
allowMultiple?: boolean; | ||
} | ||
|
||
interface ITSDocConfigJson { | ||
tagDefinitions: ITagConfigJson[]; | ||
supportForTags: { [tagName: string]: boolean }; | ||
} | ||
|
||
/** | ||
* Constructor options for {@link ApiPackage}. | ||
|
@@ -22,7 +34,12 @@ import { DeserializerContext, ApiJsonSchemaVersion } from './DeserializerContext | |
export interface IApiPackageOptions | ||
extends IApiItemContainerMixinOptions, | ||
IApiNameMixinOptions, | ||
IApiDocumentedItemOptions {} | ||
IApiDocumentedItemOptions { | ||
/** | ||
* The TSDoc tag definitions and support for the package | ||
*/ | ||
tsDocConfig: ITSDocConfigJson; | ||
} | ||
|
||
export interface IApiPackageMetadataJson { | ||
/** | ||
|
@@ -58,6 +75,11 @@ export interface IApiPackageMetadataJson { | |
* `IApiPackageMetadataJson.schemaVersion`. | ||
*/ | ||
oldestForwardsCompatibleVersion?: ApiJsonSchemaVersion; | ||
|
||
/** | ||
* The TSDoc tags used by the package | ||
*/ | ||
tsDocConfig: ITSDocConfigJson; | ||
} | ||
|
||
export interface IApiPackageJson extends IApiItemJson { | ||
|
@@ -105,8 +127,15 @@ export interface IApiPackageSaveOptions extends IJsonFileSaveOptions { | |
* @public | ||
*/ | ||
export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumentedItem)) { | ||
/** | ||
* TSDoc Tags for to the package. | ||
*/ | ||
private readonly _tsdocConfig: ITSDocConfigJson; | ||
|
||
public constructor(options: IApiPackageOptions) { | ||
super(options); | ||
|
||
this._tsdocConfig = options.tsDocConfig; | ||
} | ||
|
||
public static loadFromJsonFile(apiJsonFilename: string): ApiPackage { | ||
|
@@ -157,11 +186,35 @@ export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumented | |
} | ||
} | ||
|
||
const tsdocConfiguration: TSDocConfiguration = new TSDocConfiguration(); | ||
tsdocConfiguration.clear(true); | ||
const { tagDefinitions, supportForTags } = jsonObject.metadata.tsDocConfig; | ||
tsdocConfiguration.addTagDefinitions( | ||
tagDefinitions.map((definition) => { | ||
const { syntaxKind } = definition; | ||
const formattedSyntaxKind: TSDocTagSyntaxKind = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the re-mapping I am referring to in my previous comment. Should there be a mechanism from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nicholasrice The right solution would be to implement a corresponding If you want to make a PR for TSDoc that would be great. However your PR has been open for a very long time, so if it helps speed things along, I would also be okay with merging a less ideal solution to get you unblocked. And then we could come back later and improve the I am away on vacation right now, but I will review this PR as soon as I get back. Sorry about the delays. For future reference if you need help getting PRs merged @iclanton's team at Microsoft is a good point of contact, and also we now have a #contributor-helpline chatroom for getting attention of the maintainers. Thanks! |
||
syntaxKind === 'block' | ||
? TSDocTagSyntaxKind.BlockTag | ||
: syntaxKind === 'inline' | ||
? TSDocTagSyntaxKind.InlineTag | ||
: TSDocTagSyntaxKind.ModifierTag; | ||
return new TSDocTagDefinition({ ...definition, syntaxKind: formattedSyntaxKind }); | ||
}) | ||
); | ||
|
||
Object.entries(supportForTags).forEach(([name, supported]) => { | ||
const tag: TSDocTagDefinition | undefined = tsdocConfiguration.tryGetTagDefinition(name); | ||
if (tag) { | ||
tsdocConfiguration.setSupportForTag(tag, supported); | ||
} | ||
}); | ||
|
||
const context: DeserializerContext = new DeserializerContext({ | ||
apiJsonFilename, | ||
toolPackage: jsonObject.metadata.toolPackage, | ||
toolVersion: jsonObject.metadata.toolVersion, | ||
versionToDeserialize: versionToDeserialize | ||
versionToDeserialize: versionToDeserialize, | ||
tsdocConfiguration | ||
}); | ||
|
||
return ApiItem.deserialize(jsonObject, context) as ApiPackage; | ||
|
@@ -208,7 +261,8 @@ export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumented | |
// the version is bumped. Instead we write a placeholder string. | ||
toolVersion: options.testMode ? '[test mode]' : options.toolVersion || packageJson.version, | ||
schemaVersion: ApiJsonSchemaVersion.LATEST, | ||
oldestForwardsCompatibleVersion: ApiJsonSchemaVersion.OLDEST_FORWARDS_COMPATIBLE | ||
oldestForwardsCompatibleVersion: ApiJsonSchemaVersion.OLDEST_FORWARDS_COMPATIBLE, | ||
tsDocConfig: this._tsdocConfig | ||
} | ||
} as IApiPackageJson; | ||
this.serializeInto(jsonObject); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. | ||
// See LICENSE in the project root for license information. | ||
|
||
import { StandardTags } from '@microsoft/tsdoc'; | ||
import * as path from 'path'; | ||
|
||
import { ExtractorConfig } from '../ExtractorConfig'; | ||
|
||
const testDataFolder: string = path.join(__dirname, 'test-data'); | ||
|
||
describe('Extractor-custom-tags', () => { | ||
describe('should use a TSDocConfiguration', () => { | ||
it.only("with custom TSDoc tags defined in the package's tsdoc.json", () => { | ||
const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare( | ||
path.join(testDataFolder, 'custom-tsdoc-tags/api-extractor.json') | ||
); | ||
const { tsdocConfiguration } = extractorConfig; | ||
|
||
expect(tsdocConfiguration.tryGetTagDefinition('@block')).not.toBe(undefined); | ||
expect(tsdocConfiguration.tryGetTagDefinition('@inline')).not.toBe(undefined); | ||
expect(tsdocConfiguration.tryGetTagDefinition('@modifier')).not.toBe(undefined); | ||
}); | ||
it.only("with custom TSDoc tags enabled per the package's tsdoc.json", () => { | ||
const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare( | ||
path.join(testDataFolder, 'custom-tsdoc-tags/api-extractor.json') | ||
); | ||
const { tsdocConfiguration } = extractorConfig; | ||
const block = tsdocConfiguration.tryGetTagDefinition('@block')!; | ||
const inline = tsdocConfiguration.tryGetTagDefinition('@inline')!; | ||
const modifier = tsdocConfiguration.tryGetTagDefinition('@modifier')!; | ||
|
||
expect(tsdocConfiguration.isTagSupported(block)).toBe(true); | ||
expect(tsdocConfiguration.isTagSupported(inline)).toBe(true); | ||
expect(tsdocConfiguration.isTagSupported(modifier)).toBe(false); | ||
}); | ||
it.only("with standard tags and API Extractor custom tags defined and supported when the package's tsdoc.json extends API Extractor's tsdoc.json", () => { | ||
const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare( | ||
path.join(testDataFolder, 'custom-tsdoc-tags/api-extractor.json') | ||
); | ||
const { tsdocConfiguration } = extractorConfig; | ||
|
||
expect(tsdocConfiguration.tryGetTagDefinition('@inline')).not.toBe(undefined); | ||
expect(tsdocConfiguration.tryGetTagDefinition('@block')).not.toBe(undefined); | ||
expect(tsdocConfiguration.tryGetTagDefinition('@modifier')).not.toBe(undefined); | ||
|
||
StandardTags.allDefinitions | ||
.concat([ | ||
tsdocConfiguration.tryGetTagDefinition('@betaDocumentation')!, | ||
tsdocConfiguration.tryGetTagDefinition('@internalRemarks')!, | ||
tsdocConfiguration.tryGetTagDefinition('@preapproved')! | ||
]) | ||
.forEach((tag) => { | ||
expect(tsdocConfiguration.tagDefinitions.includes(tag)); | ||
expect(tsdocConfiguration.supportedTagDefinitions.includes(tag)); | ||
}); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", | ||
|
||
"mainEntryPointFilePath": "<projectFolder>/index.d.ts", | ||
|
||
"apiReport": { | ||
"enabled": true | ||
}, | ||
|
||
"docModel": { | ||
"enabled": true | ||
}, | ||
|
||
"dtsRollup": { | ||
"enabled": true | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/** | ||
* @block | ||
* | ||
* @inline test | ||
* @modifier | ||
*/ | ||
interface CustomTagsTestInterface {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"name": "config-lookup1", | ||
"version": "1.0.0" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"$schema": "http://json.schemastore.org/tsconfig", | ||
|
||
"compilerOptions": { | ||
"outDir": "lib", | ||
"rootDir": "src", | ||
|
||
"forceConsistentCasingInFileNames": true, | ||
"jsx": "react", | ||
"declaration": true, | ||
"sourceMap": true, | ||
"declarationMap": true, | ||
"inlineSources": true, | ||
"experimentalDecorators": true, | ||
"strictNullChecks": true, | ||
"noUnusedLocals": true, | ||
"types": ["heft-jest", "node"], | ||
|
||
"module": "commonjs", | ||
"target": "es2017", | ||
"lib": ["es2017"] | ||
}, | ||
"include": ["src/**/*.ts", "src/**/*.tsx"], | ||
"exclude": ["node_modules", "lib"] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@octogonz defining these here is odd to me because they're essentially a copy of the interfaces defined in
tsdoc-config
and are the product ofsaveToObject()
, butsaveToObject()
returnsunknown
. Should I do something to address this?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was easy, so I went ahead and implemented the missing
loadFromObject()
operation in microsoft/tsdoc#288