diff --git a/.eslintrc.js b/.eslintrc.js index 7c8eb85..e553aa4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -26,6 +26,7 @@ module.exports = { '@typescript-eslint/member-delimiter-style': 'off', '@typescript-eslint/no-use-before-define': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/ban-ts-comment': 'off' + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/no-non-null-assertion': 'off' } } diff --git a/README.md b/README.md index 2dc59bd..7178f0d 100644 --- a/README.md +++ b/README.md @@ -33,11 +33,12 @@ Usage $ api-docs-gen ... Options - --config, -c configuration file + --config, -c configration file --output, -o output dierectory that is markdown contents --generate-style, -g document generating style, default 'prefix' 'prefix': be able to separated with each package name 'directory': be able to separated with each package directory + --tsdoc-config, -t tsdoc configration file ``` @@ -53,7 +54,7 @@ const input = [path.resolve(process.cwd(), './package1.api.json')] const output = path.resolve(process.cwd(), './docs') // generate API docs with prefixed package name -await generate(input, output, 'prefix', DefaultConfig) +await generate(input, output, { style: 'prefix', config: DefaultConfig }) ``` About details, See the [API References](https://github.com/kazupon/api-docs-gen/blob/master/api-docs-gen-api.md) @@ -76,6 +77,21 @@ $ yarn example:gen # genearte API docs with `api-docs-gen` $ yarn example:docs # run vuepress ``` +## :bookmark: TSDoc custom tags + +`api-docs-gen` allows TSDoc custom tags to be processed using [tsdoc-config](https://github.com/microsoft/tsdoc/tree/master/tsdoc-config). + +You can make it work from the `api-extractor` model by specifying tsdoc configration in the `--tsdoc-config` option as follows: + +```bash +$ api-docs-gen package1.api.json --tsdoc-config ./tsdoc.json +``` + +If you want to output custom tags comment to markdown, you need to implement and configure the custom `MarkdownProcessor`. + +For the `MarkdownProcessor`, see the [API References](https://github.com/kazupon/api-docs-gen/blob/master/api-docs-gen-api.md). + +See how to configure it in the following configration. ## :wrench: Configration You can fully customize the generation of api docs using the config offered by `api-docs-gen`. diff --git a/api-docs-gen-api.md b/api-docs-gen-api.md index a307d21..f3f31b0 100644 --- a/api-docs-gen-api.md +++ b/api-docs-gen-api.md @@ -6,6 +6,7 @@ - [Config](#config) - [ContentBuilder](#contentbuilder) - [ContentBuilderOptions](#contentbuilderoptions) + - [GenerateOptions](#generateoptions) - [MarkdownContent](#markdowncontent) - [Function](#function) - [createContentBuilder](#createcontentbuilder) @@ -199,6 +200,87 @@ indentLevel?: number; ``` +### GenerateOptions + +Generate Options for Generate API + +**Signature:** +```typescript +export interface GenerateOptions +``` + + +#### Methods + + +#### Properties + +##### config + +configration + +**Signature:** +```typescript +config: Config; +``` + +#### Remarks + +see the [Config](#config) + +##### done + +generate done callback + +**Signature:** +```typescript +done?: (pkgname: string, filename: string) => void; +``` + +#### Remarks + +The callback that will be called when the generate process is finished. + +##### errorOnTSDocConfig + +TSDoc configration error callback + +**Signature:** +```typescript +errorOnTSDocConfig?: (error: string) => void; +``` + +#### Remarks + +The callback occurs if you have an error in configration when `--tsdoc-config` is specified + +##### style + +generate style + +**Signature:** +```typescript +style: GenerateStyle; +``` + +#### Remarks + +see the [GenerateStyle](#generatestyle) + +##### tsdocConfigPath + +TSDoc configration path + +**Signature:** +```typescript +tsdocConfigPath?: string; +``` + +#### Remarks + +Optional, see the [here](https://github.com/microsoft/tsdoc/tree/master/tsdoc-config) + + ### MarkdownContent Markdown content @@ -304,7 +386,7 @@ Generate API docs **Signature:** ```typescript -export declare function generate(input: string[], output: string, style: GenerateStyle, config: Config, callback?: (pkgname: string, filename: string) => void): Promise; +export declare function generate(input: string[], output: string, options: GenerateOptions): Promise; ``` #### Parameters @@ -313,9 +395,7 @@ export declare function generate(input: string[], output: string, style: Generat | --- | --- | --- | | input | string\[\] | input paths | | output | string | output api docs full path | -| style | GenerateStyle | generate style, see the [GenerateStyle](#generatestyle) | -| config | Config | configration, see the [Config](#config) | -| callback | (pkgname: string, filename: string) => void | | +| options | GenerateOptions | optiosn for generate, see the [GenerateOptions](#generateoptions) | ### getDocSectionContent @@ -323,7 +403,7 @@ Get DocSection content **Signature:** ```typescript -export declare function getDocSectionContent(model: ApiModel, pkg: ApiPackage, content: DocSection, contextItem: ApiItem, style: GenerateStyle, resolver: ReferenceResolver): string; +export declare function getDocSectionContent(model: ApiModel, pkg: ApiPackage, content: DocSection, contextItem: ApiItem, style: GenerateStyle, resolver: ReferenceResolver, customTags: string[]): string; ``` #### Parameters @@ -336,6 +416,7 @@ export declare function getDocSectionContent(model: ApiModel, pkg: ApiPackage, c | contextItem | ApiItem | a context [item](https://rushstack.io/pages/api/api-extractor-model.apiitem/) | | style | GenerateStyle | generate style, See the [GenerateStyle](#generatestyle) | | resolver | ReferenceResolver | [resolver](#referenceresolver) to resolve markdown content references | +| customTags | string\[\] | | #### Returns @@ -366,7 +447,7 @@ Process of API doc model **Signature:** ```typescript -export declare function process(model: ApiModel, pkg: ApiPackage, style: GenerateStyle, resolver: ReferenceResolver): string | MarkdownContent[]; +export declare function process(model: ApiModel, pkg: ApiPackage, style: GenerateStyle, resolver: ReferenceResolver, customTags?: string[]): string | MarkdownContent[]; ``` #### Parameters @@ -377,6 +458,7 @@ export declare function process(model: ApiModel, pkg: ApiPackage, style: Generat | pkg | ApiPackage | a [package](https://rushstack.io/pages/api/api-extractor-model.apipackage/) | | style | GenerateStyle | generate style, See the [GenerateStyle](#generatestyle) | | resolver | ReferenceResolver | [resolver](#referenceresolver) to resolve markdown content references | +| customTags | string\[\] | TSDoc custom tags. This parameter is set to an array of custom tag names defined in `--tsdoc-config`. | #### Returns @@ -426,7 +508,7 @@ Process of API doc model **Signature:** ```typescript -export declare function process(model: ApiModel, pkg: ApiPackage, style: GenerateStyle, resolver: ReferenceResolver): string | MarkdownContent[]; +export declare function process(model: ApiModel, pkg: ApiPackage, style: GenerateStyle, resolver: ReferenceResolver, customTags?: string[]): string | MarkdownContent[]; ``` #### Parameters @@ -437,6 +519,7 @@ export declare function process(model: ApiModel, pkg: ApiPackage, style: Generat | pkg | ApiPackage | a [package](https://rushstack.io/pages/api/api-extractor-model.apipackage/) | | style | GenerateStyle | generate style, See the [GenerateStyle](#generatestyle) | | resolver | ReferenceResolver | [resolver](#referenceresolver) to resolve markdown content references | +| customTags | string\[\] | TSDoc custom tags. This parameter is set to an array of custom tag names defined in `--tsdoc-config`. | #### Returns @@ -520,7 +603,7 @@ Markdown docs processor **Signature:** ```typescript -export declare type MarkdownProcessor = (model: ApiModel, pkg: ApiPackage, style: GenerateStyle, resolver: ReferenceResolver) => string | MarkdownContent[]; +export declare type MarkdownProcessor = (model: ApiModel, pkg: ApiPackage, style: GenerateStyle, resolver: ReferenceResolver, customTags?: string[]) => string | MarkdownContent[]; ``` ### ReferenceResolver diff --git a/package.json b/package.json index d9ab09b..b01a47b 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "dependencies": { "@microsoft/api-extractor-model": "^7.12.0", "@microsoft/tsdoc": "^0.12.21", + "@microsoft/tsdoc-config": "^0.13.6", "chalk": "^4.1.0", "debug": "^4.3.1", "meow": "^8.0.0" diff --git a/src/cli.ts b/src/cli.ts index c87056a..b2d9d53 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -23,6 +23,10 @@ export const flags = { type: 'string', alias: 'g', default: GenerateStyle.Prefix + }, + 'tsdoc-config': { + type: 'string', + alias: 't' } } as const @@ -32,17 +36,19 @@ const cli = meow( $ api-docs-gen ... Options - --config, -c configuration file + --config, -c configration file --output, -o output dierectory that is markdown contents --generate-style, -g document generating style, default 'prefix' 'prefix': be able to separated with each package name 'directory': be able to separated with each package directory + --tsdoc-config, -t tsdoc configration file Examples $ api-docs-gen package1.api.json $ api-docs-gen package1.api.json --output ./docs $ api-docs-gen package1.api.json --config docsgen.config.js $ api-docs-gen package1.api.json package2.api.json --generate-style directory + $ api-docs-gen package1.api.json --tsdoc-config ./tsdoc.json `, { flags @@ -91,18 +97,26 @@ const genStyle = [GenerateStyle.Prefix, GenerateStyle.Directory].includes( : GenerateStyle.Prefix debug('packageDocsStyle', genStyleFlag, genStyle) +// tsdoc configratio +const tsdocConfig = cli.flags['tsdoc-config'] + // run try { ;(async () => { - await generate( - input, - output, - genStyle, + await generate(input, output, { + style: genStyle, config, - (pkgname: string, filepath: string) => { + tsdocConfigPath: + tsdocConfig != null + ? path.resolve(process.cwd(), tsdocConfig) + : undefined, + errorOnTSDocConfig: (error: string): void => { + console.log(chalk.yellow(`⚠️ Error on TSDoc configration: ${error}`)) + }, + done: (pkgname: string, filepath: string): void => { console.log(chalk.green(`📦 ${pkgname}: 📝 save ${filepath}`)) } - ) + }) })() } catch (e) { console.error(chalk.red(`[api-docs-gen] ${e.message}`)) diff --git a/src/config.ts b/src/config.ts index 2315b43..244830c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -69,6 +69,7 @@ export interface MarkdownContent { * @param pkg - a {@link https://rushstack.io/pages/api/api-extractor-model.apipackage/ | package} * @param style - generate style. see the {@link GenerateStyle} * @param resolver - the markdown reference {@link ReferenceResolver | resolver}. if you're specfified at {@link Config}, it's passed, else it's not specified passed internal refenrece resolver. + * @param customTags - TSDoc custom tags. This parameter is set to an array of custom tag names defined in `--tsdoc-config`. * * @returns markdown content * @@ -78,7 +79,8 @@ export type MarkdownProcessor = ( model: ApiModel, pkg: ApiPackage, style: GenerateStyle, - resolver: ReferenceResolver + resolver: ReferenceResolver, + customTags?: string[] ) => string | MarkdownContent[] /** diff --git a/src/generator.ts b/src/generator.ts index d97cfb6..93457bb 100644 --- a/src/generator.ts +++ b/src/generator.ts @@ -1,32 +1,86 @@ import path from 'path' import { ApiModel } from '@microsoft/api-extractor-model' import { debug as Debug } from 'debug' -import { loadPackage } from './resolver' +import { loadPackage, loadTSDocConfig, mergeTSDocTagDefinition } from './tsdoc' import { isString, mkdir, writeFile } from './utils' import type { Config, GenerateStyle } from './config' const debug = Debug('api-docs-gen:generator') +/** + * Generate Options for Generate API + * + * @public + */ +export interface GenerateOptions { + /** + * generate style + * + * @remarks + * see the {@link GenerateStyle} + */ + style: GenerateStyle + /** + * configration + * + * @remarks + * see the {@link Config} + */ + config: Config + /** + * TSDoc configration path + * + * @remarks + * Optional, see the {@link https://github.com/microsoft/tsdoc/tree/master/tsdoc-config | here} + */ + tsdocConfigPath?: string + /** + * generate done callback + * + * @remarks + * The callback that will be called when the generate process is finished. + */ + done?: (pkgname: string, filename: string) => void + /** + * TSDoc configration error callback + * + * @remarks + * The callback occurs if you have an error in configration when `--tsdoc-config` is specified + */ + errorOnTSDocConfig?: (error: string) => void +} + /** * Generate API docs * * @param input - input paths * @param output - output api docs full path - * @param style - generate style, see the {@link GenerateStyle} - * @param config - configration, see the {@link Config} + * @param options - optiosn for generate, see the {@link GenerateOptions} * * @public */ export async function generate( input: string[], output: string, - style: GenerateStyle, - config: Config, - callback?: (pkgname: string, filename: string) => void + options: GenerateOptions ): Promise { + const { style, config, tsdocConfigPath, done, errorOnTSDocConfig } = options debug(`config`, config) debug('style', style) + debug('tsdocConfig', tsdocConfigPath) + + let customTags: string[] = [] + if (tsdocConfigPath) { + try { + const tsdocConfig = loadTSDocConfig(tsdocConfigPath) + customTags = mergeTSDocTagDefinition(tsdocConfig.tagDefinitions) + debug('TSDoc custom tags:', customTags) + } catch (e) { + debug('error on TSDoc Configration', e.message) + errorOnTSDocConfig && errorOnTSDocConfig(e.message) + } + } const apiModel = new ApiModel() for (const target of input) { @@ -37,7 +91,8 @@ export async function generate( apiModel, apiPackage, style, - config.linkReferencer! // eslint-disable-line @typescript-eslint/no-non-null-assertion + config.linkReferencer!, + customTags ) if (isString(result)) { @@ -72,7 +127,7 @@ export async function generate( ) } await writeFile(filepath, body) - callback && callback(apiPackage.displayName, filepath) + done && done(apiPackage.displayName, filepath) } } } diff --git a/src/index.ts b/src/index.ts index b65384a..977d195 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,4 +15,4 @@ export { getDocSectionContent } from './processor' export { multi as multiResolver, toc as tocResolver } from './resolver' -export { generate } from './generator' +export { generate, GenerateOptions } from './generator' diff --git a/src/processor/multi.ts b/src/processor/multi.ts index 1d2e957..3d166c5 100644 --- a/src/processor/multi.ts +++ b/src/processor/multi.ts @@ -38,6 +38,7 @@ import { * @param pkg - a {@link https://rushstack.io/pages/api/api-extractor-model.apipackage/ | package} * @param style - generate style, See the {@link GenerateStyle} * @param resolver - {@link ReferenceResolver | resolver} to resolve markdown content references + * @param customTags - TSDoc custom tags. This parameter is set to an array of custom tag names defined in `--tsdoc-config`. * * @returns markdown content strign or Array of {@link MarkdownContent} * @@ -47,7 +48,8 @@ export function process( model: ApiModel, pkg: ApiPackage, style: GenerateStyle, - resolver: ReferenceResolver + resolver: ReferenceResolver, + customTags?: string[] ): string | MarkdownContent[] { // build function build(pkg: ApiPackage): Map { @@ -75,22 +77,70 @@ export function process( switch (kind) { case ApiItemKind.Function: - buildFunctionContent(style, model, pkg, resolver, builder, item) + buildFunctionContent( + style, + model, + pkg, + resolver, + builder, + item, + customTags || [] + ) break case ApiItemKind.Enum: - buildEnumContent(style, model, pkg, resolver, builder, item) + buildEnumContent( + style, + model, + pkg, + resolver, + builder, + item, + customTags || [] + ) break case ApiItemKind.Interface: - buildInterfaceContent(style, model, pkg, resolver, builder, item) + buildInterfaceContent( + style, + model, + pkg, + resolver, + builder, + item, + customTags || [] + ) break case ApiItemKind.Class: - buildClassContent(style, model, pkg, resolver, builder, item) + buildClassContent( + style, + model, + pkg, + resolver, + builder, + item, + customTags || [] + ) break case ApiItemKind.TypeAlias: - buildTypeAliasContent(style, model, pkg, resolver, builder, item) + buildTypeAliasContent( + style, + model, + pkg, + resolver, + builder, + item, + customTags || [] + ) break case ApiItemKind.Variable: - buildVariableContent(style, model, pkg, resolver, builder, item) + buildVariableContent( + style, + model, + pkg, + resolver, + builder, + item, + customTags || [] + ) break default: break diff --git a/src/processor/toc.ts b/src/processor/toc.ts index e397241..abd8e99 100644 --- a/src/processor/toc.ts +++ b/src/processor/toc.ts @@ -30,6 +30,7 @@ import { * @param pkg - a {@link https://rushstack.io/pages/api/api-extractor-model.apipackage/ | package} * @param style - generate style, See the {@link GenerateStyle} * @param resolver - {@link ReferenceResolver | resolver} to resolve markdown content references + * @param customTags - TSDoc custom tags. This parameter is set to an array of custom tag names defined in `--tsdoc-config`. * * @returns markdown string content that have TOC * @@ -39,7 +40,8 @@ export function process( model: ApiModel, pkg: ApiPackage, style: GenerateStyle, - resolver: ReferenceResolver + resolver: ReferenceResolver, + customTags?: string[] ): string | MarkdownContent[] { function build(): string { const builder = createContentBuilder() @@ -102,11 +104,21 @@ export function process( resolver, contentBuilder, item, + customTags || [], 3 ) break case ApiItemKind.Enum: - buildEnumContent(style, model, pkg, resolver, contentBuilder, item, 3) + buildEnumContent( + style, + model, + pkg, + resolver, + contentBuilder, + item, + customTags || [], + 3 + ) break case ApiItemKind.Interface: buildInterfaceContent( @@ -116,6 +128,7 @@ export function process( resolver, contentBuilder, item, + customTags || [], 3 ) break @@ -127,6 +140,7 @@ export function process( resolver, contentBuilder, item, + customTags || [], 3 ) break @@ -138,6 +152,7 @@ export function process( resolver, contentBuilder, item, + customTags || [], 3 ) break @@ -149,6 +164,7 @@ export function process( resolver, contentBuilder, item, + customTags || [], 3 ) break diff --git a/src/processor/utils.ts b/src/processor/utils.ts index 49087ad..9d967f9 100644 --- a/src/processor/utils.ts +++ b/src/processor/utils.ts @@ -32,6 +32,7 @@ export function buildFunctionContent( resolver: ReferenceResolver, builder: ContentBuilder, item: ApiItem, + customTags: string[], base = 2 ): void { builder.pushline(`${'#'.repeat(base)} ${item.displayName}`) @@ -53,7 +54,8 @@ export function buildFunctionContent( docs.summarySection, item, style, - resolver + resolver, + customTags ) ) builder.newline() @@ -88,7 +90,8 @@ export function buildFunctionContent( p.tsdocParamBlock.content, item, style, - resolver + resolver, + customTags ) : '' } |` @@ -109,7 +112,8 @@ export function buildFunctionContent( docs.returnsBlock.content, item, style, - resolver + resolver, + customTags ) ) builder.newline() @@ -128,7 +132,8 @@ export function buildFunctionContent( t.content, item, style, - resolver + resolver, + customTags )}` if (throws.length > 1) { text = `- ` + text @@ -150,7 +155,8 @@ export function buildFunctionContent( docs.remarksBlock.content, item, style, - resolver + resolver, + customTags ) ) builder.newline() @@ -168,7 +174,15 @@ export function buildFunctionContent( builder.pushline(`${'#'.repeat(base + 2)} Example ${count}`) } builder.pushline( - `${getDocSectionContent(model, pkg, e.content, item, style, resolver)}` + `${getDocSectionContent( + model, + pkg, + e.content, + item, + style, + resolver, + customTags + )}` ) builder.newline() count++ @@ -184,6 +198,7 @@ export function buildEnumContent( resolver: ReferenceResolver, builder: ContentBuilder, item: ApiItem, + customTags: string[], base = 2 ): void { builder.pushline(`${'#'.repeat(base)} ${item.displayName}`) @@ -205,7 +220,8 @@ export function buildEnumContent( docs.summarySection, item, style, - resolver + resolver, + customTags ) ) builder.newline() @@ -244,7 +260,8 @@ export function buildEnumContent( memberDeclared.tsdocComment.summarySection, item, style, - resolver + resolver, + customTags ) : '' } |` @@ -265,7 +282,8 @@ export function buildEnumContent( docs.remarksBlock.content, item, style, - resolver + resolver, + customTags ) ) builder.newline() @@ -283,7 +301,15 @@ export function buildEnumContent( builder.pushline(`${'#'.repeat(base + 1)} Example ${count}`) } builder.pushline( - `${getDocSectionContent(model, pkg, e.content, item, style, resolver)}` + `${getDocSectionContent( + model, + pkg, + e.content, + item, + style, + resolver, + customTags + )}` ) builder.newline() count++ @@ -300,6 +326,7 @@ export function buildContentForClassinizable( builder: ContentBuilder, item: ApiItem, type: string, + customTags: string[], base = 3 ) { const itemDeclared = item as ApiDeclaredItem @@ -354,7 +381,8 @@ export function buildContentForClassinizable( p.tsdocParamBlock.content, item, style, - resolver + resolver, + customTags ) : '' } |` @@ -375,7 +403,8 @@ export function buildContentForClassinizable( docs.returnsBlock.content, item, style, - resolver + resolver, + customTags ) ) builder.newline() @@ -394,7 +423,8 @@ export function buildContentForClassinizable( t.content, item, style, - resolver + resolver, + customTags )}` if (throws.length > 1) { text = `- ` + text @@ -416,7 +446,8 @@ export function buildContentForClassinizable( docs.remarksBlock.content, item, style, - resolver + resolver, + customTags ) ) builder.newline() @@ -434,7 +465,15 @@ export function buildContentForClassinizable( builder.pushline(`${'#'.repeat(base + 1)} Example ${count}`) } builder.pushline( - `${getDocSectionContent(model, pkg, e.content, item, style, resolver)}` + `${getDocSectionContent( + model, + pkg, + e.content, + item, + style, + resolver, + customTags + )}` ) builder.newline() count++ @@ -450,6 +489,7 @@ export function buildInterfaceContent( resolver: ReferenceResolver, builder: ContentBuilder, item: ApiItem, + customTags: string[], base = 2 ): void { builder.pushline(`${'#'.repeat(base)} ${item.displayName}`) @@ -462,6 +502,7 @@ export function buildInterfaceContent( builder, item, 'interface', + customTags, base + 1 ) builder.newline() @@ -480,6 +521,7 @@ export function buildInterfaceContent( builder, method, 'method', + customTags, base + 1 ) } @@ -499,6 +541,7 @@ export function buildInterfaceContent( builder, property, 'property', + customTags, base + 1 ) } @@ -512,6 +555,7 @@ export function buildClassContent( resolver: ReferenceResolver, builder: ContentBuilder, item: ApiItem, + customTags: string[], base = 2 ): void { builder.pushline(`${'#'.repeat(base)} ${item.displayName}`) @@ -523,7 +567,8 @@ export function buildClassContent( resolver, builder, item, - 'class' + 'class', + customTags ) builder.newline() @@ -538,6 +583,7 @@ export function buildClassContent( builder, ctor, 'constructor', + customTags, base + 1 ) builder.newline() @@ -556,6 +602,7 @@ export function buildClassContent( builder, method, 'method', + customTags, base + 1 ) } @@ -575,6 +622,7 @@ export function buildClassContent( builder, property, 'property', + customTags, base + 1 ) } @@ -588,6 +636,7 @@ export function buildTypeAliasContent( resolver: ReferenceResolver, builder: ContentBuilder, item: ApiItem, + customTags: string[], base = 2 ): void { builder.pushline(`${'#'.repeat(base)} ${item.displayName}`) @@ -609,7 +658,8 @@ export function buildTypeAliasContent( docs.summarySection, item, style, - resolver + resolver, + customTags ) ) builder.newline() @@ -638,7 +688,8 @@ export function buildTypeAliasContent( docs.remarksBlock.content, item, style, - resolver + resolver, + customTags ) ) builder.newline() @@ -656,7 +707,15 @@ export function buildTypeAliasContent( builder.pushline(`${'#'.repeat(base + 2)} Example ${count}`) } builder.pushline( - `${getDocSectionContent(model, pkg, e.content, item, style, resolver)}` + `${getDocSectionContent( + model, + pkg, + e.content, + item, + style, + resolver, + customTags + )}` ) builder.newline() count++ @@ -672,6 +731,7 @@ export function buildVariableContent( resolver: ReferenceResolver, builder: ContentBuilder, item: ApiItem, + customTags: string[], base = 2 ): void { builder.pushline(`${'#'.repeat(base)} ${item.displayName}`) @@ -693,7 +753,8 @@ export function buildVariableContent( docs.summarySection, item, style, - resolver + resolver, + customTags ) ) builder.newline() @@ -722,7 +783,8 @@ export function buildVariableContent( docs.remarksBlock.content, item, style, - resolver + resolver, + customTags ) ) builder.newline() @@ -740,7 +802,15 @@ export function buildVariableContent( builder.pushline(`${'#'.repeat(base + 2)} Example ${count}`) } builder.pushline( - `${getDocSectionContent(model, pkg, e.content, item, style, resolver)}` + `${getDocSectionContent( + model, + pkg, + e.content, + item, + style, + resolver, + customTags + )}` ) builder.newline() count++ @@ -769,7 +839,8 @@ export function getDocSectionContent( content: DocSection, contextItem: ApiItem, style: GenerateStyle, - resolver: ReferenceResolver + resolver: ReferenceResolver, + customTags: string[] // eslint-disable-line @typescript-eslint/no-unused-vars ): string { let ret = '' diff --git a/src/resolver/index.ts b/src/resolver/index.ts index bde68e5..5237588 100644 --- a/src/resolver/index.ts +++ b/src/resolver/index.ts @@ -1,12 +1,2 @@ -import type { ApiModel, ApiPackage } from '@microsoft/api-extractor-model' - export { resolve as multi } from './multi' export { resolve as toc } from './toc' - -export function loadPackage(modelPath: string, model: ApiModel): ApiPackage { - try { - return model.loadPackage(modelPath) - } catch (e) { - throw new Error(`Cannot load package model from ${modelPath}: ${e.message}`) - } -} diff --git a/src/tsdoc.ts b/src/tsdoc.ts new file mode 100644 index 0000000..e816b6b --- /dev/null +++ b/src/tsdoc.ts @@ -0,0 +1,37 @@ +import { TSDocConfigFile } from '@microsoft/tsdoc-config' +import { AedocDefinitions } from '@microsoft/api-extractor-model' +import type { ApiModel, ApiPackage } from '@microsoft/api-extractor-model' +import type { TSDocTagDefinition } from '@microsoft/tsdoc' + +export function loadPackage(modelPath: string, model: ApiModel): ApiPackage { + try { + return model.loadPackage(modelPath) + } catch (e) { + throw new Error(`Cannot load package model from ${modelPath}: ${e.message}`) + } +} + +export function loadTSDocConfig(path: string): TSDocConfigFile { + const tsdocConfig = TSDocConfigFile.loadFile(path) + if (tsdocConfig.hasErrors) { + throw new Error(tsdocConfig.getErrorSummary()) + } + return tsdocConfig +} + +export function mergeTSDocTagDefinition( + definitions: readonly TSDocTagDefinition[] +): string[] { + const tsdocConfig = AedocDefinitions.tsdocConfiguration + const customTags = [] as string[] + + definitions.forEach(definition => { + if (tsdocConfig.tryGetTagDefinition(definition.tagName) == null) { + // @ts-ignore + tsdocConfig.addTagDefinition(definition) + customTags.push(definition.tagName) + } + }) + + return customTags +} diff --git a/test/__snapshots__/mutli.test.ts.snap b/test/__snapshots__/mutli.test.ts.snap index 87ef4eb..466e152 100644 --- a/test/__snapshots__/mutli.test.ts.snap +++ b/test/__snapshots__/mutli.test.ts.snap @@ -1,5 +1,354 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`multi with custom tags: class.md 1`] = ` +"# Class + +## Calculator + +Calculator class + +**Signature:** +\`\`\`typescript +export declare class Calculator implements Calculatable +\`\`\` + +### Remarks + +This is remarks of Calculator class + +### Examples + + +\`\`\`javascript +const c = new Calculator() +const v1 = c.add(1, 1) +const v2 = c.sub(1, 1) +\`\`\` + + + +### Constructor + +Conssutructor of usage + +**Signature:** +\`\`\`typescript +constructor(type: string); +\`\`\` + + +### Methods + +#### add + +add method + +**Signature:** +\`\`\`typescript +add(a: number, b: number): number; +\`\`\` + +*Parameters* + +| Parameter | Type | Description | +| --- | --- | --- | +| a | number | target 1 | +| b | number | target 2 | + +#### sub + +sub method + +**Signature:** +\`\`\`typescript +sub(a: number, b: number): number; +\`\`\` + +*Parameters* + +| Parameter | Type | Description | +| --- | --- | --- | +| a | number | target 1 | +| b | number | target 2 | + + +### Properties + +#### PI + +PI + +**Signature:** +\`\`\`typescript +PI: number; +\`\`\` + +#### type + +calcurator types 'simple' + +**Signature:** +\`\`\`typescript +type: string; +\`\`\` + + +" +`; + +exports[`multi with custom tags: enum.md 1`] = ` +"# Enum + +## ErrorCodes + +Error Code + +**Signature:** +\`\`\`typescript +export declare enum ErrorCodes +\`\`\` + +### Members + +| Member | Value| Description | +| --- | --- | --- | +| InvalidFormat | 1 | Invalid format | +| Succcess | 0 | Success | + +## TokenChars + +Token Characters + +**Signature:** +\`\`\`typescript +export declare enum TokenChars +\`\`\` + +### Members + +| Member | Value| Description | +| --- | --- | --- | +| Modulo | \\"%\\" | Modulo charactor | +| Plus | \\"+\\" | Plus charactor | + +### Remarks + +This is remarks of Token Chararaceters + +" +`; + +exports[`multi with custom tags: function.md 1`] = ` +"# Function + +## add + +add function : \`x\` + +**Signature:** +\`\`\`typescript +export declare function add(a: number, b: number): number; +\`\`\` + +### Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| a | number | target \`1\` | +| b | number | target 2 | + +### Returns + + result as \`a\` + \`b\` + +### Throws + +- \`SyntaxError\` this is syntax error +- \`Error\` this is general error + +### Remarks + +This is add function remarks: [ErrorCodes](./library1-enum#errorcodes). See [add](https://foo.bar.com/api/add). + +### Examples + +example of \`add\` function: +\`\`\`javascript +console.log(add(1, 1)) +\`\`\` + + +## undumbify + +un dummy + +**Signature:** +\`\`\`typescript +export declare function undumbify(dummy: DumbType): T; +\`\`\` + +### Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| dummy | DumbType<T> | A dummy | + +" +`; + +exports[`multi with custom tags: interface.md 1`] = ` +"# Interface + +## Calculatable + +Calculatable interface + +**Signature:** +\`\`\`typescript +export interface Calculatable +\`\`\` + + +### Methods + +#### add + +add method + +**Signature:** +\`\`\`typescript +add(a: number, b: number): number; +\`\`\` + +*Parameters* + +| Parameter | Type | Description | +| --- | --- | --- | +| a | number | target 1 | +| b | number | target 2 | + + +### Properties + +#### PI + +PI + +**Signature:** +\`\`\`typescript +PI: number; +\`\`\` + + +" +`; + +exports[`multi with custom tags: typealias.md 1`] = ` +"# TypeAlias + +## A + +A + +**Signature:** +\`\`\`typescript +export declare type A = string; +\`\`\` + +## B + +[A](./library1-typealias#a) + +**Signature:** +\`\`\`typescript +export declare type B = number; +\`\`\` + +## DumbType + +A dumb type + +**Signature:** +\`\`\`typescript +export declare type DumbType = { + foo: T; +}; +\`\`\` + +## FallbackLocale + +Falback Locale + +**Signature:** +\`\`\`typescript +export declare type FallbackLocale = Locale | Locale[] | { + [locale in string]: Locale[]; +} | false; +\`\`\` + +### Remarks + +This is remarks of \`Fallback Locale\` + +## Locale + +Locale + +**Signature:** +\`\`\`typescript +export declare type Locale = string; +\`\`\` + +## LocaleMessage + +Locale Message resources + +**Signature:** +\`\`\`typescript +export declare type LocaleMessage = string | LocaleMessage[]; +\`\`\` + +" +`; + +exports[`multi with custom tags: variable.md 1`] = ` +"# Variable + +## Config + +Configrations + +**Signature:** +\`\`\`typescript +Config: { + [name: string]: unknown; +} +\`\`\` + +## VERSION + +app version + +**Signature:** +\`\`\`typescript +VERSION = \\"1.0.0\\" +\`\`\` + +### Remarks + +you can lookup application version that is semver format. + +### Examples + + +\`\`\`javascript +console.log(VERSION) +\`\`\` + + +" +`; + exports[`multi: class.md 1`] = ` "# Class diff --git a/test/fixtures/library1.custom.api.json b/test/fixtures/library1.custom.api.json new file mode 100644 index 0000000..3dbf906 --- /dev/null +++ b/test/fixtures/library1.custom.api.json @@ -0,0 +1,816 @@ +{ + "metadata": { + "toolPackage": "@microsoft/api-extractor", + "toolVersion": "7.9.2", + "schemaVersion": 1003, + "oldestForwardsCompatibleVersion": 1001 + }, + "kind": "Package", + "canonicalReference": "library1!", + "docComment": "", + "name": "library1", + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "library1!", + "name": "", + "members": [ + { + "kind": "TypeAlias", + "canonicalReference": "library1!A:type", + "docComment": "/**\n * A\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type A = " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "A", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Function", + "canonicalReference": "library1!add:function(1)", + "docComment": "/**\n * add function : `x`\n *\n * @remarks\n *\n * This is add function remarks: {@link ErrorCodes}. See {@link https://foo.bar.com/api/add | add}.\n *\n * @param a - target `1`\n *\n * @param b - target 2\n *\n * @returns result as `a` + `b`\n *\n * @throws\n *\n * `SyntaxError` this is syntax error\n *\n * @throws\n *\n * `Error` this is general error\n *\n * @example\n *\n * example of `add` function:\n * ```javascript\n * console.log(add(1, 1))\n * ```\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function add(a: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ", b: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "a", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "parameterName": "b", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + } + ], + "name": "add" + }, + { + "kind": "TypeAlias", + "canonicalReference": "library1!B:type", + "docComment": "/**\n * {@link A}\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type B = " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "B", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Interface", + "canonicalReference": "library1!Calculatable:interface", + "docComment": "/**\n * Calculatable interface\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface Calculatable " + } + ], + "releaseTag": "Public", + "name": "Calculatable", + "members": [ + { + "kind": "MethodSignature", + "canonicalReference": "library1!Calculatable#add:member(1)", + "docComment": "/**\n * add method\n *\n * @param a - target 1\n *\n * @param b - target 2\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "add(a: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ", b: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "a", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "parameterName": "b", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + } + ], + "name": "add" + }, + { + "kind": "PropertySignature", + "canonicalReference": "library1!Calculatable#PI:member", + "docComment": "/**\n * PI\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "PI: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "PI", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "library1!Calculator:class", + "docComment": "/**\n * Calculator class\n *\n * @remarks\n *\n * This is remarks of Calculator class\n *\n * @example\n * ```javascript\n * const c = new Calculator()\n * const v1 = c.add(1, 1)\n * const v2 = c.sub(1, 1)\n * ```\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class Calculator implements " + }, + { + "kind": "Reference", + "text": "Calculatable", + "canonicalReference": "library1!Calculatable:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "Calculator", + "members": [ + { + "kind": "Constructor", + "canonicalReference": "library1!Calculator:constructor(1)", + "docComment": "/**\n * Conssutructor of usage\n *\n * @param type - calculator type\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "constructor(type: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ");" + } + ], + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "type", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + }, + { + "kind": "Method", + "canonicalReference": "library1!Calculator#add:member(1)", + "docComment": "/**\n * add method\n *\n * @param a - target 1\n *\n * @param b - target 2\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "add(a: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ", b: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "a", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "parameterName": "b", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + } + ], + "name": "add" + }, + { + "kind": "Property", + "canonicalReference": "library1!Calculator#PI:member", + "docComment": "/**\n * PI\n *\n * @returns 3.14\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "PI: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "PI", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false + }, + { + "kind": "Method", + "canonicalReference": "library1!Calculator#sub:member(1)", + "docComment": "/**\n * sub method\n *\n * @param a - target 1\n *\n * @param b - target 2\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "sub(a: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ", b: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "a", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "parameterName": "b", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + } + ], + "name": "sub" + }, + { + "kind": "Property", + "canonicalReference": "library1!Calculator#type:member", + "docComment": "/**\n * calcurator types\n *\n * @default 'simple'\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "type: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "type", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false + } + ], + "implementsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 3 + } + ] + }, + { + "kind": "Variable", + "canonicalReference": "library1!Config:var", + "docComment": "/**\n * Configrations\n *\n * @default {}\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "Config: " + }, + { + "kind": "Content", + "text": "{\n [name: string]: unknown;\n}" + } + ], + "releaseTag": "Public", + "name": "Config", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "TypeAlias", + "canonicalReference": "library1!DumbType:type", + "docComment": "/**\n * A dumb type\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type DumbType = " + }, + { + "kind": "Content", + "text": "{\n foo: T;\n}" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "DumbType", + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ], + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Enum", + "canonicalReference": "library1!ErrorCodes:enum", + "docComment": "/**\n * Error Code\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare enum ErrorCodes " + } + ], + "releaseTag": "Public", + "name": "ErrorCodes", + "members": [ + { + "kind": "EnumMember", + "canonicalReference": "library1!ErrorCodes.InvalidFormat:member", + "docComment": "/**\n * Invalid format\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "InvalidFormat = " + }, + { + "kind": "Content", + "text": "1" + } + ], + "releaseTag": "Public", + "name": "InvalidFormat", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "EnumMember", + "canonicalReference": "library1!ErrorCodes.Succcess:member", + "docComment": "/**\n * Success\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "Succcess = " + }, + { + "kind": "Content", + "text": "0" + } + ], + "releaseTag": "Public", + "name": "Succcess", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + }, + { + "kind": "TypeAlias", + "canonicalReference": "library1!FallbackLocale:type", + "docComment": "/**\n * Falback Locale\n *\n * @remarks\n *\n * This is remarks of `Fallback Locale`\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type FallbackLocale = " + }, + { + "kind": "Reference", + "text": "Locale", + "canonicalReference": "library1!Locale:type" + }, + { + "kind": "Content", + "text": " | " + }, + { + "kind": "Reference", + "text": "Locale", + "canonicalReference": "library1!Locale:type" + }, + { + "kind": "Content", + "text": "[] | {\n [locale in string]: " + }, + { + "kind": "Reference", + "text": "Locale", + "canonicalReference": "library1!Locale:type" + }, + { + "kind": "Content", + "text": "[];\n} | false" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "FallbackLocale", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 7 + } + }, + { + "kind": "TypeAlias", + "canonicalReference": "library1!Locale:type", + "docComment": "/**\n * Locale\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type Locale = " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "Locale", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "TypeAlias", + "canonicalReference": "library1!LocaleMessage:type", + "docComment": "/**\n * Locale Message resources\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type LocaleMessage = " + }, + { + "kind": "Content", + "text": "string | " + }, + { + "kind": "Reference", + "text": "LocaleMessage", + "canonicalReference": "library1!LocaleMessage:type" + }, + { + "kind": "Content", + "text": "[]" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "LocaleMessage", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 4 + } + }, + { + "kind": "Enum", + "canonicalReference": "library1!TokenChars:enum", + "docComment": "/**\n * Token Characters\n *\n * @remarks\n *\n * This is remarks of Token Chararaceters\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare enum TokenChars " + } + ], + "releaseTag": "Public", + "name": "TokenChars", + "members": [ + { + "kind": "EnumMember", + "canonicalReference": "library1!TokenChars.Modulo:member", + "docComment": "/**\n * Modulo charactor\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "Modulo = " + }, + { + "kind": "Content", + "text": "\"%\"" + } + ], + "releaseTag": "Public", + "name": "Modulo", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "EnumMember", + "canonicalReference": "library1!TokenChars.Plus:member", + "docComment": "/**\n * Plus charactor\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "Plus = " + }, + { + "kind": "Content", + "text": "\"+\"" + } + ], + "releaseTag": "Public", + "name": "Plus", + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + }, + { + "kind": "Function", + "canonicalReference": "library1!undumbify:function(1)", + "docComment": "/**\n * un dummy\n *\n * @param dummy - A dummy\n *\n * @category category1\n *\n * @vueCategory\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function undumbify(dummy: " + }, + { + "kind": "Reference", + "text": "DumbType", + "canonicalReference": "library1!DumbType:type" + }, + { + "kind": "Content", + "text": "" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "T" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 4, + "endIndex": 5 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "dummy", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + } + ], + "typeParameters": [ + { + "typeParameterName": "T", + "constraintTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "defaultTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ], + "name": "undumbify" + }, + { + "kind": "Variable", + "canonicalReference": "library1!VERSION:var", + "docComment": "/**\n * app version\n *\n * @remarks\n *\n * you can lookup application version that is semver format.\n *\n * @example\n * ```javascript\n * console.log(VERSION)\n * ```\n *\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "VERSION = \"1.0.0\"" + } + ], + "releaseTag": "Public", + "name": "VERSION", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ] + } + ] +} diff --git a/test/fixtures/tsdoc.json b/test/fixtures/tsdoc.json new file mode 100644 index 0000000..0889401 --- /dev/null +++ b/test/fixtures/tsdoc.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "tagDefinitions": [ + { + "tagName": "@myTag", + "syntaxKind": "modifier" + } + ] +} diff --git a/test/fixtures/tsdoc.library1.json b/test/fixtures/tsdoc.library1.json new file mode 100644 index 0000000..8901d4e --- /dev/null +++ b/test/fixtures/tsdoc.library1.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "tagDefinitions": [ + { + "tagName": "@category", + "syntaxKind": "block" + }, + { + "tagName": "@vueInline", + "syntaxKind": "inline" + }, + { + "tagName": "@vueCategory", + "syntaxKind": "modifier" + } + ] +} diff --git a/test/generator.test.ts b/test/generator.test.ts index c6565d8..89a7790 100644 --- a/test/generator.test.ts +++ b/test/generator.test.ts @@ -41,7 +41,10 @@ afterEach(() => { test('generate prefix style contents', async () => { const input = [API_JSON1, API_JSON2] const output = path.resolve(__dirname, './') - await generate(input, output, GenerateStyle.Prefix, DefaultConfig) + await generate(input, output, { + style: GenerateStyle.Prefix, + config: DefaultConfig + }) expect(mkdir).toHaveBeenCalledTimes(7) expect(writeFile).toHaveBeenCalledTimes(7) @@ -65,7 +68,10 @@ test('generate prefix style contents', async () => { test('generate directory style contents', async () => { const input = [API_JSON1, API_JSON2] const output = path.resolve(__dirname, './') - await generate(input, output, GenerateStyle.Directory, DefaultConfig) + await generate(input, output, { + style: GenerateStyle.Directory, + config: DefaultConfig + }) expect(mkdir).toHaveBeenCalledTimes(7) diff --git a/test/mutli.test.ts b/test/mutli.test.ts index 0bd32cf..0d7133d 100644 --- a/test/mutli.test.ts +++ b/test/mutli.test.ts @@ -2,6 +2,7 @@ import path from 'path' import { ApiModel } from '@microsoft/api-extractor-model' import { multi as multiResolver } from '../src/resolver' import { multi as multiProcessor } from '../src/processor' +import { loadTSDocConfig, mergeTSDocTagDefinition } from '../src/tsdoc' import { MarkdownContent, GenerateStyle } from '../src/config' test('multi', () => { @@ -18,3 +19,25 @@ test('multi', () => { expect(content.body).toMatchSnapshot(content.filename) } }) + +test('multi with custom tags', () => { + const tsdocConfigPath = path.resolve( + __dirname, + './fixtures/tsdoc.library1.json' + ) + const { tagDefinitions } = loadTSDocConfig(tsdocConfigPath) + const customTags = mergeTSDocTagDefinition(tagDefinitions) + const apiModel = new ApiModel() + const target = path.resolve(__dirname, './fixtures/library1.custom.api.json') + const apiPackage = apiModel.loadPackage(target) + const contents = multiProcessor( + apiModel, + apiPackage, + GenerateStyle.Prefix, + multiResolver, + customTags + ) as MarkdownContent[] + for (const content of contents) { + expect(content.body).toMatchSnapshot(content.filename) + } +}) diff --git a/test/tsdoc.test.ts b/test/tsdoc.test.ts new file mode 100644 index 0000000..248b5e0 --- /dev/null +++ b/test/tsdoc.test.ts @@ -0,0 +1,30 @@ +import { resolve } from 'path' +import { TSDocTagSyntaxKind } from '@microsoft/tsdoc' +import { AedocDefinitions } from '@microsoft/api-extractor-model' +import { loadTSDocConfig, mergeTSDocTagDefinition } from '../src/tsdoc' + +test('loadTSDocConfig', () => { + const tsdocConfigPath = resolve(__dirname, './fixtures/tsdoc.json') + const { tagDefinitions } = loadTSDocConfig(tsdocConfigPath) + + expect(tagDefinitions.length).toEqual(1) + expect(tagDefinitions[0].syntaxKind).toEqual(TSDocTagSyntaxKind.ModifierTag) + expect(tagDefinitions[0].tagName).toEqual('@myTag') +}) + +test('mergeTSDocTagDefinition', () => { + const beforeLength = AedocDefinitions.tsdocConfiguration.tagDefinitions.length + const tsdocConfigPath = resolve(__dirname, './fixtures/tsdoc.json') + const { tagDefinitions } = loadTSDocConfig(tsdocConfigPath) + const customTags = mergeTSDocTagDefinition(tagDefinitions) + const afterLength = AedocDefinitions.tsdocConfiguration.tagDefinitions.length + const myTagDefine = AedocDefinitions.tsdocConfiguration.tagDefinitions.find( + tag => tag.tagName === '@myTag' + ) + + expect(beforeLength).not.toEqual(afterLength) + expect(myTagDefine!.tagName).toEqual('@myTag') + expect(myTagDefine!.syntaxKind).toEqual(TSDocTagSyntaxKind.ModifierTag) + expect(customTags.length).toEqual(1) + expect(customTags[0]).toEqual('@myTag') +}) diff --git a/yarn.lock b/yarn.lock index 9edc787..7001eac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1904,12 +1904,22 @@ source-map "~0.6.1" typescript "~4.0.5" +"@microsoft/tsdoc-config@^0.13.6": + version "0.13.6" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc-config/-/tsdoc-config-0.13.6.tgz#2154785e264edaa515ce5bb2a6c9cd7865f356cf" + integrity sha512-VJjV35PnrNISoX2WMemZjnCIdOUPTRpCz6pu8inISotLd3SgoDSJygGaE7+lOYdCtDl+4c8PWJdZivxxXgOnLw== + dependencies: + "@microsoft/tsdoc" "0.12.21" + ajv "~6.12.3" + jju "~1.4.0" + resolve "~1.12.0" + "@microsoft/tsdoc@0.12.19": version "0.12.19" resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.19.tgz#2173ccb92469aaf62031fa9499d21b16d07f9b57" integrity sha512-IpgPxHrNxZiMNUSXqR1l/gePKPkfAmIKoDRP9hp7OwjU29ZR8WCJsOJ8iBKgw0Qk+pFwR+8Y1cy8ImLY6e9m4A== -"@microsoft/tsdoc@^0.12.21": +"@microsoft/tsdoc@0.12.21", "@microsoft/tsdoc@^0.12.21": version "0.12.21" resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.21.tgz#1098c393634826ed47386862a1241ce8b7c0cf0d" integrity sha512-j+9OJ0A0buZZaUn6NxeHUVpoa05tY2PgVs7kXJhJQiKRB0G1zQqbJxer3T7jWtzpqQWP89OBDluyIeyTsMk8Sg== @@ -2962,7 +2972,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@~6.12.3: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -11308,6 +11318,13 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.17.0, resolve@^1.18 is-core-module "^2.0.0" path-parse "^1.0.6" +resolve@~1.12.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.3.tgz#96d5253df8005ce19795c14338f2a013c38a8c15" + integrity sha512-hF6+hAPlxjqHWrw4p1rF3Wztbgxd4AjA5VlUzY5zcTb4J8D3JK4/1RjU48pHz2PJWzGVsLB1VWZkvJzhK2CCOA== + dependencies: + path-parse "^1.0.6" + resolve@~1.17.0: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"