Extract sorting to separate functions

This commit is contained in:
Koen Vlaswinkel
2023-06-26 14:08:46 +02:00
parent 13a5b7854f
commit a8aee6a8e1
7 changed files with 106 additions and 75 deletions

View File

@@ -1,4 +1,4 @@
import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usage";
import { ExternalApiUsage } from "../external-api-usage";
export function calculateModeledPercentage(
externalApiUsages: Array<Pick<ExternalApiUsage, "supported">>,

View File

@@ -0,0 +1,88 @@
import { ExternalApiUsage } from "../external-api-usage";
import { Mode } from "./mode";
import { calculateModeledPercentage } from "./modeled-percentage";
export function groupMethods(
externalApiUsages: ExternalApiUsage[],
mode: Mode,
): Record<string, ExternalApiUsage[]> {
const groupedByLibrary: Record<string, ExternalApiUsage[]> = {};
for (const externalApiUsage of externalApiUsages) {
// Group by package if using framework mode
const key =
mode === Mode.Framework
? externalApiUsage.packageName
: externalApiUsage.library;
groupedByLibrary[key] ??= [];
groupedByLibrary[key].push(externalApiUsage);
}
return groupedByLibrary;
}
export function sortGroupNames(
methods: Record<string, ExternalApiUsage[]>,
): string[] {
return Object.keys(methods).sort((a, b) =>
compareGroups(methods[a], a, methods[b], b),
);
}
export function sortMethods(
externalApiUsages: ExternalApiUsage[],
): ExternalApiUsage[] {
const sortedExternalApiUsages = [...externalApiUsages];
sortedExternalApiUsages.sort((a, b) => compareMethod(a, b));
return sortedExternalApiUsages;
}
function compareGroups(
a: ExternalApiUsage[],
aName: string,
b: ExternalApiUsage[],
bName: string,
): number {
const supportedPercentageA = calculateModeledPercentage(a);
const supportedPercentageB = calculateModeledPercentage(b);
// Sort first by supported percentage ascending
if (supportedPercentageA > supportedPercentageB) {
return 1;
}
if (supportedPercentageA < supportedPercentageB) {
return -1;
}
const numberOfUsagesA = a.reduce((acc, curr) => acc + curr.usages.length, 0);
const numberOfUsagesB = b.reduce((acc, curr) => acc + curr.usages.length, 0);
// If the number of usages is equal, sort by number of methods descending
if (numberOfUsagesA === numberOfUsagesB) {
const numberOfMethodsA = a.length;
const numberOfMethodsB = b.length;
// If the number of methods is equal, sort by library name ascending
if (numberOfMethodsA === numberOfMethodsB) {
return aName.localeCompare(bName);
}
return numberOfMethodsB - numberOfMethodsA;
}
// Then sort by number of usages descending
return numberOfUsagesB - numberOfUsagesA;
}
function compareMethod(a: ExternalApiUsage, b: ExternalApiUsage): number {
// Sort first by supported, putting unmodeled methods first.
if (a.supported && !b.supported) {
return 1;
}
if (!a.supported && b.supported) {
return -1;
}
// Then sort by number of usages descending
return b.usages.length - a.usages.length;
}

View File

@@ -10,7 +10,7 @@ import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usag
import { ModeledMethod } from "../../data-extensions-editor/modeled-method";
import { assertNever } from "../../common/helpers-pure";
import { vscode } from "../vscode-api";
import { calculateModeledPercentage } from "./modeled";
import { calculateModeledPercentage } from "../../data-extensions-editor/shared/modeled-percentage";
import { LinkIconButton } from "../variant-analysis/LinkIconButton";
import { ViewTitle } from "../common";
import { DataExtensionEditorViewState } from "../../data-extensions-editor/shared/view-state";

View File

@@ -5,7 +5,7 @@ import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usag
import { ModeledMethod } from "../../data-extensions-editor/modeled-method";
import { pluralize } from "../../common/word";
import { ModeledMethodDataGrid } from "./ModeledMethodDataGrid";
import { calculateModeledPercentage } from "./modeled";
import { calculateModeledPercentage } from "../../data-extensions-editor/shared/modeled-percentage";
import { decimalFormatter, percentFormatter } from "./formatters";
import { Codicon } from "../common";
import { Mode } from "../../data-extensions-editor/shared/mode";

View File

@@ -9,6 +9,7 @@ import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usag
import { ModeledMethod } from "../../data-extensions-editor/modeled-method";
import { useMemo } from "react";
import { Mode } from "../../data-extensions-editor/shared/mode";
import { sortMethods } from "../../data-extensions-editor/shared/sorting";
type Props = {
externalApiUsages: ExternalApiUsage[];
@@ -26,21 +27,10 @@ export const ModeledMethodDataGrid = ({
mode,
onChange,
}: Props) => {
const sortedExternalApiUsages = useMemo(() => {
const sortedExternalApiUsages = [...externalApiUsages];
sortedExternalApiUsages.sort((a, b) => {
// Sort first by supported, putting unmodeled methods first.
if (a.supported && !b.supported) {
return 1;
}
if (!a.supported && b.supported) {
return -1;
}
// Then sort by number of usages descending
return b.usages.length - a.usages.length;
});
return sortedExternalApiUsages;
}, [externalApiUsages]);
const sortedExternalApiUsages = useMemo(
() => sortMethods(externalApiUsages),
[externalApiUsages],
);
return (
<VSCodeDataGrid>

View File

@@ -2,9 +2,12 @@ import * as React from "react";
import { useMemo } from "react";
import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usage";
import { ModeledMethod } from "../../data-extensions-editor/modeled-method";
import { calculateModeledPercentage } from "./modeled";
import { LibraryRow } from "./LibraryRow";
import { Mode } from "../../data-extensions-editor/shared/mode";
import {
groupMethods,
sortGroupNames,
} from "../../data-extensions-editor/shared/sorting";
type Props = {
externalApiUsages: ExternalApiUsage[];
@@ -22,62 +25,12 @@ export const ModeledMethodsList = ({
mode,
onChange,
}: Props) => {
const grouped = useMemo(() => {
const groupedByLibrary: Record<string, ExternalApiUsage[]> = {};
const grouped = useMemo(
() => groupMethods(externalApiUsages, mode),
[externalApiUsages, mode],
);
for (const externalApiUsage of externalApiUsages) {
// Group by package if using framework mode
const key =
mode === Mode.Framework
? externalApiUsage.packageName
: externalApiUsage.library;
groupedByLibrary[key] ??= [];
groupedByLibrary[key].push(externalApiUsage);
}
return groupedByLibrary;
}, [externalApiUsages, mode]);
const sortedGroupNames = useMemo(() => {
return Object.keys(grouped).sort((a, b) => {
const supportedPercentageA = calculateModeledPercentage(grouped[a]);
const supportedPercentageB = calculateModeledPercentage(grouped[b]);
// Sort first by supported percentage ascending
if (supportedPercentageA > supportedPercentageB) {
return 1;
}
if (supportedPercentageA < supportedPercentageB) {
return -1;
}
const numberOfUsagesA = grouped[a].reduce(
(acc, curr) => acc + curr.usages.length,
0,
);
const numberOfUsagesB = grouped[b].reduce(
(acc, curr) => acc + curr.usages.length,
0,
);
// If the number of usages is equal, sort by number of methods descending
if (numberOfUsagesA === numberOfUsagesB) {
const numberOfMethodsA = grouped[a].length;
const numberOfMethodsB = grouped[b].length;
// If the number of methods is equal, sort by library name ascending
if (numberOfMethodsA === numberOfMethodsB) {
return a.localeCompare(b);
}
return numberOfMethodsB - numberOfMethodsA;
}
// Then sort by number of usages descending
return numberOfUsagesB - numberOfUsagesA;
});
}, [grouped]);
const sortedGroupNames = useMemo(() => sortGroupNames(grouped), [grouped]);
return (
<>

View File

@@ -1,4 +1,4 @@
import { calculateModeledPercentage } from "../modeled";
import { calculateModeledPercentage } from "../../../../src/data-extensions-editor/shared/modeled-percentage";
describe("calculateModeledPercentage", () => {
it("when there are no external API usages", () => {