unified

Project: kamranayub/remark-typedoc-symbol-links

Package: remark-typedoc-symbol-links@2.1.0

  1. Dependents: 0
  2. A Remark plugin to transform TypeDoc symbol links into link tags
  1. remark 214
  2. remark-plugin 82
  3. typescript 4

remark-typedoc-symbol-links

GitHub code size in bytes GitHub repo size npm npm npm npm NPM npm GitHub last commit npm collaborators

A Remark plugin for transforming TypeDoc symbol links, such as [[symbol]] to a Markdown link, with Rehype compatibility.

Typedoc Compatibility

This version requires >=0.21.3. Use earlier versions of the package for Typedoc versions below this range.

The peerDependencies is kept up-to-date with what version of TypeDoc is supported. Each minor version tends to contain some breaking changes that affect this parsing.

Note: npm 7 and peer dependencies

If you have a version of Typedoc installed on your project that does not satisfy the peer dependency range above, npm 7 will install the latest version of TypeDoc that satisfies the peer dependency which means you may have a mismatch in behavior. The symbol links plugin will use its local Typedoc version instead of your project's version.

Install

Install via npm or yarn:

# npm
npm install remark-typedoc-symbol-links

# yarn
yarn add remark-typedoc-symbol-links

Usage

Then within Node.js:

const typedocSymbolLinks = require('remark-typedoc-symbol-links')

With Gatsby.js

This was developed for use by the excalibur.js project and is used in the documentation site, see the Gatsby config. This is the underlying package used in gatsby-remark-typedoc-symbol-links which depends on the gatsby-source-typedoc package to generate the required TypeDoc project structure for a TypeScript project and makes it available via GraphQL nodes.

With Remark and unified

This plugin is meant to be used with mdast inside a unified pipeline. If using directly as a Remark plugin, see examples/example.js.

Given the following Markdown:

## Introduction

Create a new [[Engine]] instance and call [[Engine.start|start]] to start the game!

And the following usage with unified and remark-parse:

const fs = require('fs')
const unified = require('unified')
const markdown = require('remark-parse')
const html = require('remark-html')
const typedocSymbolLinks = require('../dist')

// Load generated TypeDoc
const typedoc = JSON.parse(fs.readFileSync('../src/__tests__/typedoc.json'))

const doc = unified()
  .use(markdown)
  // Pass typedoc and other options
  .use(typedocSymbolLinks, { typedoc, basePath: '/docs/api' })
  .use(html)
  .processSync(fs.readFileSync('example.md'))
  .toString()

console.log(doc)

Node will output:

<h2>Introduction</h2>
<p>
  Create a new
  <a href="/docs/apiclasses/_engine_.engine.html" title="View &#x27;Engine&#x27;" class="tsdoc-link" target="_blank"
    >Engine</a
  >
  instance and call
  <a
    href="/docs/apiclasses/_engine_.engine.html#start"
    title="View &#x27;Engine.start&#x27;"
    class="tsdoc-link tsdoc-link--aliased"
    target="_blank"
    >start</a
  >
  to start the game!
</p>

When no matching symbol is detected, the anchor link is rendered with a missing class name (default: tsdoc-link--missing) and the title changes to indicate the symbol is missing. A warning is also output to the console in development mode (NODE_ENV === 'development'). This should provide enough feedback to make it easier to ensure your documentation doesn't drift out of date.

API

Transform TypeDoc markdown symbol links to links, with rehype compatibility.

options

options.typedoc: object (required)

An object representing TypeDoc output for a TypeScript project (such as running through typedoc --generateJson or done programmatically). This is the tree used to index symbols and perform link resolution. When used with gatsby-source-typedoc, this is provided automatically. See examples/example.js for an example loading JSON using fs.readSync.

options.basePath: string (optional, default: /)

The path prefix to prepend to all generated links. Typically the path to where your generated TypeDoc documentation lives.

The default class name to apply to the generated link. Will always be present on the link.

This will be appended to the link class names if the symbol could not be resolved.

This will be appened to the link class names if the symbol had an alias (e.g. [[Class.method|a cool method]])

options.linkTitleMessage: (symbolPath: string, missing: boolean) => string (optional)

A function to invoke that will be passed the qualified symbol path (e.g. Class.method) and whether or not the symbol was missing. If missing is true, the link could not be resolved.

The default implementation shows the following messages:

missing => `Could not resolve link to '${symbolPath}'`
not missing => `View '${symbolPath}'`

Compatibility and differences from TypeDoc

This plugin attempts to emulate TypeDoc's link resolution but it's important to point out that the plugin has no context when resolving symbols (meaning, it's a Markdown page outside your source code, so it cannot look hierarchically to resolve links). That means that you may need to fully-qualify methods, properties, and functions if they are not unique.

Classes, Interfaces, and Enums

class, enum, and interface symbols and their members only need to be qualified by the container name. Use ClassName#ctor for linking to the constructor of a class.

Examples:

Module functions

If a function is exported within a module, it can be linked to by name. However, if there are similarly named functions in different modules, the first match will be used. This could be fixed through fully-qualified module naming, see this note.

Examples:

Unsupported: Module indexes

When generating documentation with modules enabled in TypeDoc, it generates names like "ModuleName/SubmoduleName". Right now, the plugin is limited because it does not allow linking directly to a module index page, since it assumes you typically want to link to a symbol within a module. That is how it can avoid forcing you to always fully-qualify a symbol path with the module name.

Example, this won't work:

See [["ModuleName"]]

On the flip-side, you don't need to do this:

See [["ModuleName".myFunction]]

Since module symbols are all indexed, you can leave off the module qualifiers:

See [[myFunction]]

This is a limitation could be overcome but it needs some thought. For example, maybe to link to a module index, you could do:

See [[module:Module/SubModule]]

This could ignore quotes and allow linking to the module index page. If you think you need this, I welcome PRs!

The following Markdown:

Check out the [[Sword.slash]] source code!

Will be transformed into this HTML:

Check out the <a href="/classes/_module_.sword.html#slash" target="_blank" class="tsdoc-link" title="View 'Sword.slash'">Sword.slash</a> source code!

The following Markdown:

Check out the [[Sword.slash|slash helper]] source code!

Will be transformed into this HTML:

Check out the <a href="/classes/_module_.sword.html#slash" target="_blank" class="tsdoc-link tsdoc-link--aliased" title="View 'Sword.slash'">slash helper</a> source code!

The following Markdown:

Check out the [[abcdefg]] source code!

Will be transformed into this HTML:

Check out the <a target="_blank" class="tsdoc-link tsdoc-link--missing" title="Could not resolve link for 'abcdefg'">abcdefg</a> source code!

Contributing

See Contributing and the Code of Conduct

License

MIT