mirror of
https://github.com/BillyOutlast/rea.git
synced 2026-10-12 02:26:55 +00:00
perf(javascript): cache canonical export comparison sort keys (#1028)
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
import { uniqueSorted } from "../canonicalOrdering.js";
|
||||
import { digestExportShapeValue } from "./javascriptExportShapeComparisonIdentity.js";
|
||||
import { compareCodePoints, uniqueSorted } from "../canonicalOrdering.js";
|
||||
import {
|
||||
canonicalExportShapeValue,
|
||||
digestExportShapeValue,
|
||||
} from "./javascriptExportShapeComparisonIdentity.js";
|
||||
import {
|
||||
javaScriptExportShapeComparisonResultSchema,
|
||||
type JavaScriptExportShapeComparisonChange,
|
||||
@@ -14,7 +17,6 @@ import {
|
||||
} from "./javascriptExportShapeSelection.js";
|
||||
import {
|
||||
buildJavaScriptExportShapeChanges,
|
||||
compareJavaScriptExportShapeChanges,
|
||||
hasPartialJavaScriptExportPropertyCoverage,
|
||||
pairJavaScriptExportShapeVariants,
|
||||
type JavaScriptExportShapePairing,
|
||||
@@ -42,14 +44,16 @@ export const compareJavaScriptExportShapes = (
|
||||
input.left.evidenceId,
|
||||
input.right.evidenceId,
|
||||
);
|
||||
const allChanges = buildJavaScriptExportShapeChanges({
|
||||
leftSelection: left,
|
||||
rightSelection: right,
|
||||
pairing,
|
||||
leftShapes: leftRetained.shapes,
|
||||
rightShapes: rightRetained.shapes,
|
||||
evidenceLinks,
|
||||
}).sort(compareJavaScriptExportShapeChanges);
|
||||
const allChanges = sortChanges(
|
||||
buildJavaScriptExportShapeChanges({
|
||||
leftSelection: left,
|
||||
rightSelection: right,
|
||||
pairing,
|
||||
leftShapes: leftRetained.shapes,
|
||||
rightShapes: rightRetained.shapes,
|
||||
evidenceLinks,
|
||||
}),
|
||||
);
|
||||
const changes = allChanges;
|
||||
const omittedChanges = 0;
|
||||
const coverage = comparisonCoverage({
|
||||
@@ -78,6 +82,29 @@ export const compareJavaScriptExportShapes = (
|
||||
});
|
||||
};
|
||||
|
||||
const sortChanges = (
|
||||
changes: readonly JavaScriptExportShapeComparisonChange[],
|
||||
): JavaScriptExportShapeComparisonChange[] =>
|
||||
changes
|
||||
.map((change, index) => ({
|
||||
change,
|
||||
index,
|
||||
sortKey: canonicalExportShapeValue({
|
||||
discriminant: change.discriminant,
|
||||
path: change.path,
|
||||
status: change.status,
|
||||
left_source_range: change.left_source_range,
|
||||
right_source_range: change.right_source_range,
|
||||
change_id: change.change_id,
|
||||
}),
|
||||
}))
|
||||
.sort(
|
||||
(left, right) =>
|
||||
compareCodePoints(left.sortKey, right.sortKey) ||
|
||||
left.index - right.index,
|
||||
)
|
||||
.map(({ change }) => change);
|
||||
|
||||
interface CoverageInput {
|
||||
readonly input: JavaScriptExportShapeComparisonProjectionInput;
|
||||
readonly left: SelectedJavaScriptExport;
|
||||
|
||||
@@ -112,16 +112,6 @@ export const buildJavaScriptExportShapeChanges = (
|
||||
return [...paired, ...unpairedLeft, ...unpairedRight];
|
||||
};
|
||||
|
||||
/** Sort changes by semantic content rather than traversal order. */
|
||||
export const compareJavaScriptExportShapeChanges = (
|
||||
left: JavaScriptExportShapeComparisonChange,
|
||||
right: JavaScriptExportShapeComparisonChange,
|
||||
): number =>
|
||||
compareCodePoints(
|
||||
canonicalExportShapeValue(changeSortKey(left)),
|
||||
canonicalExportShapeValue(changeSortKey(right)),
|
||||
);
|
||||
|
||||
/** Report whether any retained shape lacks complete property coverage. */
|
||||
export const hasPartialJavaScriptExportPropertyCoverage = (
|
||||
shapes: readonly Shape[],
|
||||
@@ -429,15 +419,6 @@ const changeWithId = (
|
||||
change_id: `jesc_change_${digestExportShapeValue(semantic)}`,
|
||||
});
|
||||
|
||||
const changeSortKey = (change: JavaScriptExportShapeComparisonChange) => ({
|
||||
discriminant: change.discriminant,
|
||||
path: change.path,
|
||||
status: change.status,
|
||||
left_source_range: change.left_source_range,
|
||||
right_source_range: change.right_source_range,
|
||||
change_id: change.change_id,
|
||||
});
|
||||
|
||||
const literalValue = (
|
||||
field: Field,
|
||||
):
|
||||
|
||||
@@ -135,9 +135,13 @@ describe("source-produced export comparison inventories", () => {
|
||||
`export const candidate${String(index)} = ${String(index)};`,
|
||||
).join("\n");
|
||||
const inventorySource = `export default function parse(value) {\n${returnSites}\n throw new Error("no match");\n}\n${extraExports}`;
|
||||
const pairedVariantsSource = `export default function parse(value) {
|
||||
${returnSites}
|
||||
throw new Error("no match");
|
||||
}`;
|
||||
const [inventoryLeft, inventoryRight] = await Promise.all([
|
||||
analyzeSourceEvidence(inventorySource),
|
||||
analyzeSourceEvidence(inventorySource),
|
||||
analyzeSourceEvidence(pairedVariantsSource),
|
||||
]);
|
||||
const variants = compareEvidence(inventoryLeft, inventoryRight);
|
||||
expect(variants.left).toMatchObject({ status: "selected" });
|
||||
|
||||
@@ -88,6 +88,21 @@ describe("JavaScript export return-shape comparison", () => {
|
||||
expect(result.coverage.status).toBe("partial");
|
||||
});
|
||||
|
||||
it("orders multiple changed paths deterministically across Unicode names", async () => {
|
||||
const graphs = await analyzeSources({
|
||||
left: `export default () => ({ type: "item", zeta: 1, alpha: 1, "éclair": 1 });`,
|
||||
right: `export default () => ({ type: "item", zeta: 2, alpha: 2, "éclair": 2 });`,
|
||||
});
|
||||
const first = compare(...graphs);
|
||||
const second = compare(...graphs);
|
||||
|
||||
expect(new Set(first.changes.map(({ path }) => path))).toEqual(
|
||||
new Set(["/alpha", "/zeta", "/éclair"]),
|
||||
);
|
||||
expect(first.changes).toEqual(second.changes);
|
||||
expect(first.comparison_id).toBe(second.comparison_id);
|
||||
});
|
||||
|
||||
it("does not pair discriminants that an unknown trailing spread can overwrite", async () => {
|
||||
const [left, right] = await analyzeSources({
|
||||
left: `
|
||||
|
||||
Reference in New Issue
Block a user