feat: add util package for generating search indices (#8571)

This commit is contained in:
Suneet Tipirneni
2022-08-29 15:41:51 -04:00
committed by GitHub
parent 40324574eb
commit d5dcddd350
55 changed files with 384 additions and 93 deletions

View File

@@ -23,3 +23,5 @@ docs/**/*
# Miscellaneous
.tmp/
coverage/
searchIndex/

View File

@@ -4,7 +4,6 @@
"description": "A set of scripts that we use for our workflows",
"private": true,
"scripts": {
"test": "vitest run",
"build": "unbuild",
"lint": "prettier --check . && TIMING=1 eslint src --ext mjs,js,ts",
"format": "prettier --write . && TIMING=1 eslint src --ext mjs,js,ts --fix",
@@ -44,6 +43,9 @@
},
"homepage": "https://discord.js.org",
"dependencies": {
"@discordjs/api-extractor-utils": "workspace:^",
"@microsoft/api-extractor-model": "^7.23.3",
"@microsoft/tsdoc": "^0.14.1",
"commander": "^9.4.0",
"tslib": "^2.4.0"
},

View File

@@ -0,0 +1,91 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { generatePath } from '@discordjs/api-extractor-utils';
import { ApiDeclaredItem, ApiItem, ApiItemContainerMixin, ApiModel } from '@microsoft/api-extractor-model';
import { DocCodeSpan, DocNode, DocNodeKind, DocParagraph, DocPlainText } from '@microsoft/tsdoc';
export interface MemberJSON {
name: string;
kind: string;
summary: string | null;
path: string;
}
/**
* Attempts to resolve the summary text for the given item.
* @param item - The API item to resolve the summary text for.
*/
function tryResolveSummaryText(item: ApiDeclaredItem): string | null {
if (!item.tsdocComment) {
return null;
}
const { summarySection } = item.tsdocComment;
let retVal = '';
// Recursively visit the nodes in the summary section.
const visitTSDocNode = (node: DocNode) => {
switch (node.kind) {
case DocNodeKind.CodeSpan:
retVal += (node as DocCodeSpan).code;
break;
case DocNodeKind.PlainText:
retVal += (node as DocPlainText).text;
break;
case DocNodeKind.Section:
case DocNodeKind.Paragraph:
return (node as DocParagraph).nodes.forEach(visitTSDocNode);
default: // We'll ignore all other nodes.
break;
}
};
for (const node of summarySection.nodes) {
visitTSDocNode(node);
}
if (retVal === '') {
return null;
}
return retVal;
}
export function visitNodes(item: ApiItem, tag: string) {
const members: MemberJSON[] = [];
for (const member of item.members) {
if (!(member instanceof ApiDeclaredItem)) {
continue;
}
if (ApiItemContainerMixin.isBaseClassOf(member)) {
members.push(...visitNodes(member, tag));
}
members.push({
name: member.displayName,
kind: member.kind,
summary: tryResolveSummaryText(member),
path: generatePath(member.getHierarchy(), tag),
});
}
return members;
}
export async function generateIndex(model: ApiModel, packageName: string, tag: string) {
const members = visitNodes(model, tag);
const dir = 'searchIndex';
if (!(await fs.stat(dir)).isDirectory()) {
await fs.mkdir(dir);
}
await fs.writeFile(
path.join('searchIndex', `${packageName}-${tag}-doc-index.json`),
JSON.stringify(members, undefined, 2),
);
}

View File

@@ -1 +1 @@
export {};
export * from './generateIndex';