[api-documenter] How to define custom tags behavior?
Summary
The tsdoc.json file allows adding custom tags. This allows them to be parsed, but how do I get them to be eventually emitted by api-documenter?
To be more specific, I want to add the inline @linkcode tag and have it behave exactly the same as the @link tag.
Repro steps
tsdoc.json:
{
"$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
"tagDefinitions": [
{
"tagName": "@linkcode",
"syntaxKind": "inline"
}
]
}
Source code:
/**
* This is a {@linkcode http://example.com/ | link}.
*
* @public
*/
export class MyClass {}
Actual result:
The documentation is created without any errors, but the custom @linkcode tag is simply ignored.
Details
I noticed there's a seemingly undocumented api-documenter.json config file, but it mentions nothing of custom tags. If I need to create a plugin to add here, that's fine, but a how-to would be nice.
Standard questions
Please answer these questions to help us investigate your issue more quickly:
| Question | Answer |
|---|---|
@microsoft/api-documenter version? |
7.25.14 |
| Operating system? | Windows |
| Documentation target? | Markdown |
| Would you consider contributing a PR? | No |
| TypeScript compiler version? | 5.4.2 |
Node.js version (node -v)? |
22.7.0 |
I have the same issue. I created a tsdoc.json next to api-extractor.json where I define my custom tags and enable them
@octogonz - Can you provide some info on how to do this? This would be via a TSDoc plugin I think.
The best I can do right now is an intermediate script between api-extractor and api-documenter that replaces custom tags in the .api.json file with tags that api-documenter can understand. For example, this is what I'm doing to get @linkcode to work:
const apiPath = path.resolve(__dirname, '../temp/PACKAGE.api.json')
const apiJson = JSON.parse(fs.readFileSync(apiPath, 'utf-8'))
function jsonCrawler (obj, handler, context = { parent: null }) {
handler(obj, context)
if (typeof obj === 'object') {
if (obj === null) {
// nothing
} else if (Array.isArray(obj)) {
for (let index = 0; index < obj.length; ++index) {
jsonCrawler(obj[index], handler, { parent: { parent: context, _: obj }, key: index })
}
} else {
for (const key in obj) {
jsonCrawler(obj[key], handler, { parent: { parent: context, _: obj }, key })
}
}
}
}
jsonCrawler(apiJson, (value, { parent, key }) => {
if (key === 'docComment' && typeof value === 'string') {
value = value.replaceAll(/{@linkcode ([^|}]*) \| ([^}]*)}/g, '{@link $1 | <code>$2</code>}')
value = value.replaceAll(/{@linkcode ([^|}]*)}/g, '{@link $1 | <code>$1</code>}')
value = value.replaceAll(/@linkcode/g, '@link')
parent._[key] = value
}
})
fs.writeFileSync(apiPath, JSON.stringify(apiJson, null, 2))
The intend design is that API Extractor would accept these tags (because they are valid according to your config definition). And then an API Documenter plugin would implement any special processing.
The plugin system is in early/experimental stages, but if you are interested to contribute to API Documenter, I can help to design a solution for your problem. I've been really busy lately, so the best way would be to arrange a Rush Stack community call.
Hi @octogonz , me and my team working on https://github.com/iTwin/itwinjs-core are interested in contributing if it'd help move this along. We'd like to create new jsdoc tags to use, as well as override existing tags such as the @preapproved tag to match some custom behavior. Please let us know how we can help!