refactor(javascript): centralize source range comparison

This commit is contained in:
morluto
2026-07-24 13:43:13 +00:00
parent 4e8aa98267
commit c9500d32f6
5 changed files with 22 additions and 29 deletions
@@ -11,6 +11,7 @@ import type {
JavaScriptSemanticCallArgument,
JavaScriptSemanticIr,
} from "../domain/javascriptSemanticIr.js";
import { sourceRangesEqual as rangesEqual } from "../domain/javascriptStaticAnalysisHelpers.js";
import type { JavaScriptApplicationGraph } from "../domain/javascriptApplicationGraph.js";
import type { JavaScriptArtifactAnalysis } from "./JavaScriptArtifactAnalysisTypes.js";
import type { JavaScriptArtifactFile } from "./JavaScriptArtifactFiles.js";
@@ -41,7 +42,6 @@ import {
owningSemanticCallableNode,
semanticFamilyStatus,
semanticNodesWithinRange,
semanticRangesEqual as rangesEqual,
} from "./JavaScriptSemanticGraphProjection.js";
import {
addSemanticFallbackRoot as addFallbackRoot,
@@ -1,6 +1,7 @@
import { createJavaScriptSemanticGraphUnknown } from "../domain/javascriptSemanticGraph.js";
import type { JavaScriptSemanticGraphNode } from "../domain/javascriptSemanticGraph.js";
import type { JavaScriptSemanticIr } from "../domain/javascriptSemanticIr.js";
import { sourceRangesEqual } from "../domain/javascriptStaticAnalysisHelpers.js";
import type { JavaScriptSourceRange } from "../domain/javascriptStaticAnalysisTypes.js";
import type { JavaScriptArtifactAnalysis } from "./JavaScriptArtifactAnalysisTypes.js";
import type { JavaScriptArtifactFile } from "./JavaScriptArtifactFiles.js";
@@ -15,10 +16,7 @@ import {
inferredSemanticEvidenceAt,
unknownSemanticEvidence,
} from "./JavaScriptSemanticGraphEvidence.js";
import {
semanticNodesWithinRange,
semanticRangesEqual,
} from "./JavaScriptSemanticGraphProjection.js";
import { semanticNodesWithinRange } from "./JavaScriptSemanticGraphProjection.js";
/** File-local graph state needed by return, capture, and frontier projection. */
export interface SemanticFlowProjectionContext {
@@ -39,7 +37,7 @@ export const semanticCallSiteAt = (
location: JavaScriptSourceRange,
): JavaScriptSemanticGraphNode | undefined => {
const call = context.ir.callSites.find(({ location: candidate }) =>
semanticRangesEqual(candidate, location),
sourceRangesEqual(candidate, location),
);
return call === undefined
? undefined
@@ -231,7 +229,7 @@ export const projectSemanticReturnValues = (
relation: "aliases",
resolution:
site.identityReferenceLocation !== null &&
semanticRangesEqual(
sourceRangesEqual(
reference.identity.source_range,
site.identityReferenceLocation,
)
@@ -62,17 +62,6 @@ export const semanticFamilyStatus = (
return analysis.truncated_scopes === 0 ? "partial" : "unknown";
};
/** Compare two exact semantic source ranges. */
export const semanticRangesEqual = (
left: JavaScriptSourceRange | null,
right: JavaScriptSourceRange,
): boolean =>
left !== null &&
left.start.line === right.start.line &&
left.start.column === right.start.column &&
left.end.line === right.end.line &&
left.end.column === right.end.column;
const contains = (
outer: JavaScriptSourceRange,
inner: JavaScriptSourceRange,
+6 -11
View File
@@ -15,7 +15,11 @@ import {
type JavaScriptSemanticAnalysisState,
} from "./javascriptSemanticState.js";
import { traverseJavaScriptAst } from "./javascriptSemanticTraversal.js";
import { compareCodePoints, range } from "./javascriptStaticAnalysisHelpers.js";
import {
compareCodePoints,
range,
sourceRangesEqual,
} from "./javascriptStaticAnalysisHelpers.js";
type PromiseMethod = JavaScriptSemanticPromiseOperation["method"];
type PromiseKind = JavaScriptSemanticPromiseOperation["kind"];
@@ -327,7 +331,7 @@ const matchingReturnSite = (
callables
.find(({ callableId: candidate }) => candidate === callableId)
?.returnSites.find(({ location: candidate }) =>
rangesEqual(candidate, location),
sourceRangesEqual(candidate, location),
)?.returnSiteId ?? null;
const promiseSources = (
@@ -467,12 +471,3 @@ const isObviouslyNonPromise = (node: t.Node): boolean =>
t.isObjectExpression(node) ||
t.isFunction(node) ||
t.isClassExpression(node);
const rangesEqual = (
left: JavaScriptSemanticPromiseOperation["location"],
right: JavaScriptSemanticPromiseOperation["location"],
): boolean =>
left.start.line === right.start.line &&
left.start.column === right.start.column &&
left.end.line === right.end.line &&
left.end.column === right.end.column;
@@ -388,6 +388,17 @@ export const rangeForOffsets = (
end: pointForOffset(source, end),
});
/** Compare two exact source ranges. */
export const sourceRangesEqual = (
left: JavaScriptSourceRange | null,
right: JavaScriptSourceRange,
): boolean =>
left !== null &&
left.start.line === right.start.line &&
left.start.column === right.start.column &&
left.end.line === right.end.line &&
left.end.column === right.end.column;
const pointForOffset = (source: string, offset: number) => {
const before = source.slice(0, offset);
const lines = before.split("\n");