fix(app): avoid unsupported Android array sorting (#3241)
Hermes in the production Android app does not provide Array.prototype.toSorted. Multi-host project selection and provider cache eviction could therefore crash when they reached deterministic sorting paths.
This commit is contained in:
@@ -136,7 +136,7 @@ export function createProviderSnapshotCache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let totalBytes = entries.reduce((total, entry) => total + entry.bytes, 0);
|
let totalBytes = entries.reduce((total, entry) => total + entry.bytes, 0);
|
||||||
const retainedEntries = entries.toSorted(oldestFirst);
|
const retainedEntries = [...entries].sort(oldestFirst);
|
||||||
while (totalBytes > maxBytes) {
|
while (totalBytes > maxBytes) {
|
||||||
const evicted = retainedEntries.shift();
|
const evicted = retainedEntries.shift();
|
||||||
if (!evicted) break;
|
if (!evicted) break;
|
||||||
@@ -186,7 +186,7 @@ export function createProviderSnapshotCache(
|
|||||||
if (canStoreIncoming) projectedBytes += incomingBytes;
|
if (canStoreIncoming) projectedBytes += incomingBytes;
|
||||||
|
|
||||||
const keysToRemove: string[] = [];
|
const keysToRemove: string[] = [];
|
||||||
for (const candidate of retainedEntries.toSorted(oldestFirst)) {
|
for (const candidate of [...retainedEntries].sort(oldestFirst)) {
|
||||||
if (projectedBytes <= maxBytes) break;
|
if (projectedBytes <= maxBytes) break;
|
||||||
projectedBytes -= candidate.bytes;
|
projectedBytes -= candidate.bytes;
|
||||||
keysToRemove.push(candidate.key);
|
keysToRemove.push(candidate.key);
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ export function resolveEquivalentHostProjectCandidate(input: {
|
|||||||
(project) => project.projectKey === input.candidate.projectKey,
|
(project) => project.projectKey === input.candidate.projectKey,
|
||||||
);
|
);
|
||||||
if (equivalents.length === 0) return null;
|
if (equivalents.length === 0) return null;
|
||||||
return equivalents.toSorted((left, right) =>
|
return equivalents.sort((left, right) =>
|
||||||
compareHostProjectsForServer(left, right, input.serverId),
|
compareHostProjectsForServer(left, right, input.serverId),
|
||||||
)[0]!;
|
)[0]!;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
getWorktreeSupportForHostProject,
|
getWorktreeSupportForHostProject,
|
||||||
hostProjectFromRoute,
|
hostProjectFromRoute,
|
||||||
hostProjectFromWorkspace,
|
hostProjectFromWorkspace,
|
||||||
|
resolveEquivalentHostProjectCandidate,
|
||||||
} from "./host-project-model";
|
} from "./host-project-model";
|
||||||
import { normalizeWorkspaceDescriptor } from "@/stores/session-store";
|
import { normalizeWorkspaceDescriptor } from "@/stores/session-store";
|
||||||
|
|
||||||
@@ -36,6 +37,31 @@ function project(): HostProjectListItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("host project lookups", () => {
|
describe("host project lookups", () => {
|
||||||
|
test("resolves equivalent projects without Array.prototype.toSorted", () => {
|
||||||
|
const descriptor = Object.getOwnPropertyDescriptor(Array.prototype, "toSorted");
|
||||||
|
Reflect.deleteProperty(Array.prototype, "toSorted");
|
||||||
|
const first = project();
|
||||||
|
first.viewKey = "view:first";
|
||||||
|
first.projectName = "First";
|
||||||
|
const second = project();
|
||||||
|
second.viewKey = "view:second";
|
||||||
|
second.projectName = "Second";
|
||||||
|
const projects = [second, first];
|
||||||
|
|
||||||
|
try {
|
||||||
|
expect(
|
||||||
|
resolveEquivalentHostProjectCandidate({
|
||||||
|
candidate: first,
|
||||||
|
projects,
|
||||||
|
serverId: "host-a",
|
||||||
|
}),
|
||||||
|
).toBe(first);
|
||||||
|
expect(projects).toEqual([second, first]);
|
||||||
|
} finally {
|
||||||
|
if (descriptor) Reflect.defineProperty(Array.prototype, "toSorted", descriptor);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("returns host-local ids and roots without falling back to the grouping key", () => {
|
test("returns host-local ids and roots without falling back to the grouping key", () => {
|
||||||
expect(getHostProjectId(project(), "host-b")).toBe("prj_b");
|
expect(getHostProjectId(project(), "host-b")).toBe("prj_b");
|
||||||
expect(getHostProjectSourceDirectory(project(), "host-b")).toBe("/repo/b");
|
expect(getHostProjectSourceDirectory(project(), "host-b")).toBe("/repo/b");
|
||||||
|
|||||||
Reference in New Issue
Block a user