Skip to content

Commit

Permalink
Refactor generateToc.ts to not use dictionary type (#1259)
Browse files Browse the repository at this point in the history
Prework for #1256. It was
confusing how we pass both `tocModules: TocEntry[]` and
`tocModulesByTitle: Dictionary<TocEntry>`. It wasn't clear how those
values relate, and `Dictionary` is an under-documented API by Lodash.

Also adds `hasPrefix`, which we will need in
#1256.
  • Loading branch information
Eric-Arellano authored Apr 30, 2024
1 parent c27da73 commit d9330b3
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 10 deletions.
30 changes: 20 additions & 10 deletions scripts/lib/api/generateToc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// copyright notice, and modified files need to carry a notice indicating
// that they have been altered from the originals.

import { Dictionary, isEmpty, keyBy, keys, orderBy } from "lodash";
import { isEmpty, orderBy } from "lodash";

import { getLastPartFromFullIdentifier } from "../stringUtils";
import { HtmlToMdResultWithUrl } from "./HtmlToMdResult";
Expand Down Expand Up @@ -38,15 +38,17 @@ function nestModule(id: string): boolean {
export function generateToc(pkg: Pkg, results: HtmlToMdResultWithUrl[]): Toc {
const [modules, items] = getModulesAndItems(results);
const tocModules = generateTocModules(modules);
const tocModulesByTitle = keyBy(tocModules, (toc) => toc.title);
const tocModuleTitles = keys(tocModulesByTitle);
const tocModulesByTitle = new Map(
tocModules.map((entry) => [entry.title, entry]),
);
const tocModuleTitles = Array.from(tocModulesByTitle.keys());

addItemsToModules(items, tocModulesByTitle, tocModuleTitles);

// Most packages don't nest submodules because their module list is so small,
// so it's more useful to show them all and have less nesting.
const sortedTocModules = pkg.nestModulesInToc
? getNestedTocModulesSorted(tocModules, tocModulesByTitle, tocModuleTitles)
? getNestedTocModulesSorted(tocModulesByTitle, tocModuleTitles)
: sortAndTruncateModules(tocModules);
generateOverviewPage(tocModules);

Expand Down Expand Up @@ -89,7 +91,7 @@ function generateTocModules(modules: HtmlToMdResultWithUrl[]): TocEntry[] {

function addItemsToModules(
items: HtmlToMdResultWithUrl[],
tocModulesByTitle: Dictionary<TocEntry>,
tocModulesByTitle: Map<string, TocEntry>,
tocModuleTitles: string[],
) {
for (const item of items) {
Expand All @@ -100,7 +102,7 @@ function addItemsToModules(
);

if (itemModuleTitle) {
const itemModule = tocModulesByTitle[itemModuleTitle];
const itemModule = tocModulesByTitle.get(itemModuleTitle) as TocEntry;
if (!itemModule.children) itemModule.children = [];
const itemTocEntry: TocEntry = {
title: getLastPartFromFullIdentifier(item.meta.apiName!),
Expand All @@ -111,13 +113,17 @@ function addItemsToModules(
}
}

/** Nest modules so that only top-level modules like qiskit.circuit are at the top
* and submodules like qiskit.circuit.library are nested.
*
* This function sorts alphabetically at every level.
*/
function getNestedTocModulesSorted(
tocModules: TocEntry[],
tocModulesByTitle: Dictionary<TocEntry>,
tocModulesByTitle: Map<string, TocEntry>,
tocModuleTitles: string[],
): TocEntry[] {
const nestedTocModules: TocEntry[] = [];
for (const tocModule of tocModules) {
for (const tocModule of tocModulesByTitle.values()) {
if (!nestModule(tocModule.title)) {
nestedTocModules.push(tocModule);
continue;
Expand All @@ -129,7 +135,7 @@ function getNestedTocModulesSorted(
);

if (parentModuleTitle) {
const parentModule = tocModulesByTitle[parentModuleTitle];
const parentModule = tocModulesByTitle.get(parentModuleTitle) as TocEntry;
if (!parentModule.children) parentModule.children = [];
parentModule.children.push(tocModule);
} else {
Expand All @@ -140,6 +146,10 @@ function getNestedTocModulesSorted(
return orderEntriesByTitle(nestedTocModules);
}

/** Sorts all modules and truncates the package name, e.g. `qiskit_ibm_runtime.options` -> `...options`.
*
* Returns a flat list of modules without any nesting.
*/
function sortAndTruncateModules(entries: TocEntry[]): TocEntry[] {
const sorted = orderEntriesByTitle(entries);
sorted.forEach((entry) => {
Expand Down
9 changes: 9 additions & 0 deletions scripts/lib/stringUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
removeSuffix,
getLastPartFromFullIdentifier,
capitalize,
hasPrefix,
} from "./stringUtils";

test("removePart()", () => {
Expand Down Expand Up @@ -55,3 +56,11 @@ test("capitalize()", () => {
const input = "hello world!";
expect(capitalize(input)).toEqual("Hello world!");
});

test("hasPrefix()", () => {
expect(hasPrefix("abc", ["a", "z"])).toBe(true);
expect(hasPrefix("abc", ["x", "z"])).toBe(false);
expect(hasPrefix("abc", ["x", "a"])).toBe(true);
expect(hasPrefix("abc", [])).toBe(false);
expect(hasPrefix("abc", ["abc"])).toBe(true);
});
4 changes: 4 additions & 0 deletions scripts/lib/stringUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ export function getLastPartFromFullIdentifier(fullIdentifierName: string) {
export function capitalize(text: string) {
return text.charAt(0).toUpperCase() + text.slice(1);
}

export function hasPrefix(text: string, prefixes: string[]): boolean {
return prefixes.some((prefix) => text.startsWith(prefix));
}

0 comments on commit d9330b3

Please sign in to comment.