Skip to content

Commit d922816

Browse files
authored
Add a flag allowing api-documenter to sort functions by first param (#6623)
1 parent eea63dc commit d922816

File tree

4 files changed

+129
-12
lines changed

4 files changed

+129
-12
lines changed

.changeset/popular-beans-wonder.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@firebase/api-documenter': minor
3+
---
4+
5+
Add an option to sort functions by first param. (--sort-functions)

repo-scripts/api-documenter/src/cli/MarkdownAction.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
import { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine';
2222
import { BaseAction } from './BaseAction';
2323
import { MarkdownDocumenter } from '../documenters/MarkdownDocumenter';
24+
import { CommandLineStringParameter } from '@rushstack/ts-command-line';
2425

2526
export class MarkdownAction extends BaseAction {
27+
private _sortFunctions!: CommandLineStringParameter;
2628
public constructor(parser: ApiDocumenterCommandLine) {
2729
super({
2830
actionName: 'markdown',
@@ -33,10 +35,24 @@ export class MarkdownAction extends BaseAction {
3335
});
3436
}
3537

38+
protected onDefineParameters(): void {
39+
super.onDefineParameters();
40+
41+
this._sortFunctions = this.defineStringParameter({
42+
parameterLongName: '--sort-functions',
43+
argumentName: 'PRIORITY_PARAMS',
44+
description:
45+
`Sorts functions tables and listings by first parameter. ` +
46+
`Provide comma-separated strings for preferred params to be ` +
47+
`ordered first. Alphabetical otherwise.`
48+
});
49+
}
50+
3651
protected async onExecute(): Promise<void> {
3752
// override
3853
const { apiModel, outputFolder, addFileNameSuffix, projectName } =
3954
this.buildApiModel();
55+
const sortFunctions: string = this._sortFunctions.value || '';
4056

4157
if (!projectName) {
4258
throw new Error('No project name provided. Use --project.');
@@ -47,7 +63,8 @@ export class MarkdownAction extends BaseAction {
4763
documenterConfig: undefined,
4864
outputFolder,
4965
addFileNameSuffix,
50-
projectName
66+
projectName,
67+
sortFunctions
5168
});
5269
markdownDocumenter.generateFiles();
5370
}

repo-scripts/api-documenter/src/documenters/MarkdownDocumenter.ts

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export interface IMarkdownDocumenterOptions {
9393
outputFolder: string;
9494
addFileNameSuffix: boolean;
9595
projectName: string;
96+
sortFunctions: string;
9697
}
9798

9899
/**
@@ -108,13 +109,15 @@ export class MarkdownDocumenter {
108109
private readonly _pluginLoader: PluginLoader;
109110
private readonly _addFileNameSuffix: boolean;
110111
private readonly _projectName: string;
112+
private readonly _sortFunctions: string;
111113

112114
public constructor(options: IMarkdownDocumenterOptions) {
113115
this._apiModel = options.apiModel;
114116
this._documenterConfig = options.documenterConfig;
115117
this._outputFolder = options.outputFolder;
116118
this._addFileNameSuffix = options.addFileNameSuffix;
117119
this._projectName = options.projectName;
120+
this._sortFunctions = options.sortFunctions;
118121
this._tsdocConfiguration = CustomDocNodes.configuration;
119122
this._markdownEmitter = new CustomMarkdownEmitter(this._apiModel);
120123

@@ -834,11 +837,13 @@ page_type: reference
834837
headerTitles: ['Enumeration', 'Description']
835838
});
836839

837-
const functionsTable: DocTable = new DocTable({
840+
const finalFunctionsTable: DocTable = new DocTable({
838841
configuration,
839842
headerTitles: ['Function', 'Description']
840843
});
841844

845+
const functionsRowGroup: Record<string, DocTableRow[]> = {};
846+
842847
const interfacesTable: DocTable = new DocTable({
843848
configuration,
844849
headerTitles: ['Interface', 'Description']
@@ -859,7 +864,8 @@ page_type: reference
859864
headerTitles: ['Type Alias', 'Description']
860865
});
861866

862-
const functionsDefinitions: DocNode[] = [];
867+
const functionsDefinitionsGroup: Record<string, DocNode[]> = {};
868+
const finalFunctionsDefinitions: DocNode[] = [];
863869
const variablesDefinitions: DocNode[] = [];
864870
const typeAliasDefinitions: DocNode[] = [];
865871
const enumsDefinitions: DocNode[] = [];
@@ -899,10 +905,29 @@ page_type: reference
899905
break;
900906

901907
case ApiItemKind.Function:
902-
functionsTable.addRow(row);
903-
functionsDefinitions.push(
904-
...this._createCompleteOutputForApiItem(apiMember)
905-
);
908+
/**
909+
* If this option is set, group functions by first param.
910+
* Organize using a map where the key is the first param.
911+
*/
912+
if (this._sortFunctions) {
913+
const firstParam = (apiMember as ApiParameterListMixin)
914+
.parameters[0] || { name: '' };
915+
if (!functionsRowGroup[firstParam.name]) {
916+
functionsRowGroup[firstParam.name] = [];
917+
}
918+
if (!functionsDefinitionsGroup[firstParam.name]) {
919+
functionsDefinitionsGroup[firstParam.name] = [];
920+
}
921+
functionsRowGroup[firstParam.name].push(row);
922+
functionsDefinitionsGroup[firstParam.name].push(
923+
...this._createCompleteOutputForApiItem(apiMember)
924+
);
925+
} else {
926+
finalFunctionsTable.addRow(row);
927+
finalFunctionsDefinitions.push(
928+
...this._createCompleteOutputForApiItem(apiMember)
929+
);
930+
}
906931
break;
907932

908933
case ApiItemKind.TypeAlias:
@@ -921,9 +946,59 @@ page_type: reference
921946
}
922947
}
923948

924-
if (functionsTable.rows.length > 0) {
949+
/**
950+
* Sort the functions groups by first param. If priority params were
951+
* provided to --sort-functions, will put them first in the order
952+
* given.
953+
*/
954+
if (this._sortFunctions) {
955+
let priorityParams: string[] = [];
956+
if (this._sortFunctions.includes(',')) {
957+
priorityParams = this._sortFunctions.split(',');
958+
} else {
959+
priorityParams = [this._sortFunctions];
960+
}
961+
const sortedFunctionsFirstParamKeys = Object.keys(functionsRowGroup).sort(
962+
(a, b) => {
963+
if (priorityParams.includes(a) && priorityParams.includes(b)) {
964+
return priorityParams.indexOf(a) - priorityParams.indexOf(b);
965+
} else if (priorityParams.includes(a)) {
966+
return -1;
967+
} else if (priorityParams.includes(b)) {
968+
return 1;
969+
}
970+
return a.localeCompare(b);
971+
}
972+
);
973+
974+
for (const paramKey of sortedFunctionsFirstParamKeys) {
975+
// Header for each group of functions grouped by first param.
976+
// Doesn't make sense if there's only one group.
977+
const headerText = paramKey ? `function(${paramKey}...)` : 'function()';
978+
const formattedHeaderText = `<strong>${headerText}</strong>`;
979+
if (sortedFunctionsFirstParamKeys.length > 1) {
980+
finalFunctionsTable.addRow(
981+
new DocTableRow({ configuration }, [
982+
new DocTableCell({ configuration }, [
983+
new DocParagraph({ configuration }, [
984+
new DocPlainText({ configuration, text: formattedHeaderText })
985+
])
986+
])
987+
])
988+
);
989+
}
990+
for (const functionsRow of functionsRowGroup[paramKey]) {
991+
finalFunctionsTable.addRow(functionsRow);
992+
}
993+
for (const functionDefinition of functionsDefinitionsGroup[paramKey]) {
994+
finalFunctionsDefinitions.push(functionDefinition);
995+
}
996+
}
997+
}
998+
999+
if (finalFunctionsTable.rows.length > 0) {
9251000
output.push(new DocHeading({ configuration, title: 'Functions' }));
926-
output.push(functionsTable);
1001+
output.push(finalFunctionsTable);
9271002
}
9281003

9291004
if (classesTable.rows.length > 0) {
@@ -956,8 +1031,8 @@ page_type: reference
9561031
output.push(typeAliasesTable);
9571032
}
9581033

959-
if (functionsDefinitions.length > 0) {
960-
output.push(...functionsDefinitions);
1034+
if (finalFunctionsDefinitions.length > 0) {
1035+
output.push(...finalFunctionsDefinitions);
9611036
}
9621037

9631038
if (variablesDefinitions.length > 0) {

scripts/docgen/docgen.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,24 @@ https://github.com/firebase/firebase-js-sdk
3939
const tmpDir = `${projectRoot}/temp`;
4040
const EXCLUDED_PACKAGES = ['app-compat', 'util', 'rules-unit-testing'];
4141

42+
/**
43+
* When ordering functions, will prioritize these first params at
44+
* the top, in order.
45+
*/
46+
const PREFERRED_PARAMS = [
47+
'app',
48+
'analyticsInstance',
49+
'appCheckInstance',
50+
'db',
51+
'firestore',
52+
'functionsInstance',
53+
'installations',
54+
'messaging',
55+
'performance',
56+
'remoteConfig',
57+
'storage'
58+
];
59+
4260
yargs
4361
.command(
4462
'$0',
@@ -181,7 +199,9 @@ async function generateDocs(
181199
'--output',
182200
outputFolder,
183201
'--project',
184-
'js'
202+
'js',
203+
'--sort-functions',
204+
PREFERRED_PARAMS.join(',')
185205
],
186206
{ stdio: 'inherit' }
187207
);

0 commit comments

Comments
 (0)