Update TypeDoc plugin to support 0.24. (#728)

This commit is contained in:
Natalie Weizenbaum 2023-05-18 16:59:30 -07:00 committed by GitHub
parent 56a39bc185
commit a812ad0985
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 1287 additions and 2469 deletions

View File

@ -12,7 +12,6 @@
'vendor/jquery-ui-custom/jquery-ui-theme',
'vendor/typedoc/style',
'vendor/typedoc/highlight',
'vendor/typedoc/icons',
'functions',
'breakpoints',

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,19 +5,6 @@ function bind(fn, first) {
}
class SassSiteRenderContext extends DefaultThemeRenderContext {
// Link to the external documentation of external APIs. Unfortunately, there's
// no way to use `addUnknownSymbolResolver` for names that don't come from npm
// packages.
attemptExternalResolution = function(symbol) {
if (symbol.escapedName === 'URL') {
return 'https://developer.mozilla.org/en-US/docs/Web/API/URL';
} else if (symbol.escapedName === 'Buffer') {
return 'https://nodejs.org/api/buffer.html';
} else {
return null;
}
};
// We don't include Typedoc's JS, so the default means of displaying overloads
// as multiple togglable definitions within a single member documentation
// doesn't work. Instead, we emit each overload as a separate entry with its
@ -38,100 +25,28 @@ class SassSiteRenderContext extends DefaultThemeRenderContext {
return context.oldMember(props);
}, this);
// Make categories visible in the sidebar as well as in the main page's index.
// Hopefully this will no longer be necessary once TypeStrong/typedoc#1532 is
// implemented.
oldNavigation = this.navigation;
navigation = bind(function(context, props) {
const navigation = context.oldNavigation(props);
const childrenByCategories = context._groupByCategory(props.model);
if (childrenByCategories.size === 0) return navigation;
const secondary = context._getNthChild(navigation, 1);
if (!secondary) return navigation;
const firstLI = context._getNthChild(context._getNthChild(secondary, 0), 0);
const ul = firstLI.props["class"].startsWith("current ")
? context._getNthChild(firstLI, 1)
: context._getNthChild(secondary, 0);
ul.children = Array.from(childrenByCategories).map(([title, children]) =>
JSX.createElement(JSX.Fragment, null,
JSX.createElement("li", {class: "sl-tsd-category-label"},
JSX.createElement("span", null, title)),
...children.map(child =>
JSX.createElement("li", {class: child.cssClasses},
JSX.createElement("a", {
href: context.urlTo(child), class: "tsd-kind-icon"
}, child.name)))));
return navigation;
}, this);
// Returns the `n`-th child of a JSX node. For some reason, JSX nodes created
// by TypeDoc can contain nested arrays, so this traverses them.
_getNthChild = (node, n) => {
let i = 0;
function traverse(array) {
for (const element of array) {
if (element instanceof Array) {
const result = traverse(element);
if (result != undefined) return result;
} else {
if (i === n) return element;
i++;
}
}
}
return traverse(node.children);
};
// Returns a map from category titles to the set of members of those
// categories.
_groupByCategory = (model) => {
const map = new Map();
function addCategoriesToMap(categories) {
for (const category of categories) {
const children = map.get(category.title);
if (children) {
children.push(...category.children);
} else {
map.set(category.title, [...category.children]);
}
}
}
if (model.categories) {
addCategoriesToMap(model.categories);
} else if (model.groups) {
for (const group of model.groups) {
if (group.categories) addCategoriesToMap(group.categories);
}
}
return map;
};
// Add compatibility indicators to the beginning of documentation blocks.
oldComment = this.comment;
comment = bind((context, props) => {
const compatibilityTags = props.comment?.tags
.filter(tag => tag.tagName === "compatibility");
props.comment?.removeTags("compatibility");
if (!props.comment) return;
const compatibilityTags = props.comment.blockTags
.filter(tag => tag.tag === "@compatibility");
props.comment.removeTags("@compatibility");
const parent = this.oldComment(props);
if (!parent) return;
parent.children.unshift(...compatibilityTags.map(compat => {
// Compatibility tags should have a single text block.
const text = compat.content[0].text;
// The first line is arguments to impl_status, anything after that is the
// contents of the block.
const lineBreak = compat.text.indexOf("\n");
const lineBreak = text.indexOf("\n");
const firstLine =
lineBreak === -1 ? compat.text : compat.text.substring(0, lineBreak);
lineBreak === -1 ? text : text.substring(0, lineBreak);
const rest =
lineBreak === -1 ? null : compat.text.substring(lineBreak + 1).trim();
lineBreak === -1 ? null : text.substring(lineBreak + 1).trim();
return JSX.createElement(JSX.Raw, {
html: `<% impl_status(${firstLine}) ${rest ? 'do' : ''} %>` +
@ -155,43 +70,33 @@ class SassSiteRenderContext extends DefaultThemeRenderContext {
/<p><strong>Fun fact!<\/strong>([^]*?)<\/p>/g,
'<% fun_fact do %>$1<% end %>'),
this);
// Relative URLs don't work well for index pages since they can be rendered at
// different directory levels, so we just convert all URLs to absolute to be
// safe.
oldUrlTo = this.urlTo;
urlTo = bind(function(context, reflection) {
const relative = context.oldUrlTo(reflection);
const absolute = new URL(
relative,
`relative:///documentation/js-api/${context.theme.markedPlugin.location}`
);
absolute.pathname = absolute.pathname
.replace(/\.html$/, '')
.replace(/\/index$/, '');
return absolute.toString().replace(/^relative:\/\//, '');
}, this);
}
class SassSiteTheme extends DefaultTheme {
constructor(renderer) {
super(renderer);
// This is an ugly monkeypatch but it's necessary to work around
// TypeStrong/typedoc#1731.
//
// Relative URLs don't work well for index pages since they can be rendered at
// different directory levels, so we just convert all URLs to absolute to be
// safe.
const ContextAwareRendererComponent =
Object.getPrototypeOf(this.markedPlugin.constructor);
const oldGetRelativeUrl =
ContextAwareRendererComponent.prototype.getRelativeUrl;
ContextAwareRendererComponent.prototype.getRelativeUrl = function(url) {
const relative = oldGetRelativeUrl.call(this, url);
const absolute = new URL(
relative,
`relative:///documentation/js-api/${this.location}`
);
absolute.pathname = absolute.pathname
.replace(/\.html$/, '')
.replace(/\/index$/, '');
return absolute.toString().replace(/^relative:\/\//, '');
};
}
getRenderContext() {
getRenderContext(page) {
this.contextCache ??=
new SassSiteRenderContext(this, this.application.options);
new SassSiteRenderContext(this, page, this.application.options);
return this.contextCache;
}
render(page) {
render(page, template) {
const context = this.getRenderContext(page);
// The default header includes a search bar that we don't want, so we just
@ -231,12 +136,12 @@ title: ${JSON.stringify(`${page.model.name} | JS API`)}
</header>
<div class="container container-main">
<div class="row">
<div class="col-8 col-content">
${JSX.renderElement(page.template(page))}
</div>
<div class="col-4 col-menu menu-sticky-wrap menu-highlight">
${JSX.renderElement(context.navigation(page))}
<div class="col-content">
${JSX.renderElement(template(page))}
</div>
<div class="col-sidebar">
<div class="site-menu">
${JSX.renderElement(context.sidebar(page))}
</div>
</div>
</div>
@ -258,11 +163,28 @@ title: ${JSON.stringify(`${page.model.name} | JS API`)}
// annotations as @-tags rather than needing to write out the HTML by hand.
exports.load = app => {
app.renderer.addUnknownSymbolResolver('immutable', (name) =>
`https://immutable-js.com/docs/latest@main/${name}/`);
app.renderer.addUnknownSymbolResolver('source-map-js', (name) => {
if (name === 'RawSourceMap') {
return 'https://github.com/mozilla/source-map/blob/58819f09018d56ef84dc41ba9c93f554e0645169/source-map.d.ts#L15-L23';
app.converter.addUnknownSymbolResolver((ref, refl, part, symbolId) => {
if (!symbolId) return;
const name = symbolId.qualifiedName;
switch (ref.moduleSource) {
case 'immutable': return `https://immutable-js.com/docs/latest@main/${name}/`;
case 'source-map-js':
if (name === 'RawSourceMap') {
return 'https://github.com/mozilla/source-map/blob/58819f09018d56ef84dc41ba9c93f554e0645169/source-map.d.ts#L15-L23';
}
case '@types/node':
if (name === 'Buffer') {
return 'https://nodejs.org/api/buffer.html';
}
break;
case 'typescript':
switch (name) {
case 'URL': return 'https://developer.mozilla.org/en-US/docs/Web/API/URL';
case 'Promise': return 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise';
}
break;
}
});