import { compareCodePoints } from "../../domain/canonicalOrdering.js"; import type { JavaScriptSemanticGraphNode } from "../../domain/javascriptSemanticGraph.js"; import { JAVASCRIPT_SEMANTIC_RELATION_FAMILIES } from "../../domain/javascriptSemanticGraphSchemas.js"; import type { JavaScriptSemanticIr } from "../../domain/javascriptSemanticIr.js"; import type { JavaScriptSourceRange } from "../../domain/javascriptStaticAnalysisTypes.js"; import type { JavaScriptArtifactAnalysis } from "./JavaScriptArtifactAnalysisTypes.js"; /** Find the innermost callable that contains one exact source range. */ export const owningSemanticCallableNode = ( location: JavaScriptSourceRange | null, ir: JavaScriptSemanticIr, nodes: ReadonlyMap, ): JavaScriptSemanticGraphNode | undefined => { if (location === null) return undefined; return ir.callables .filter((callable) => contains(callable.location, location)) .sort((left, right) => compareCodePoints( positionKey(right.location), positionKey(left.location), ), ) .map(({ callableId }) => nodes.get(callableId)) .find((node) => node !== undefined); }; /** Find retained semantic nodes whose exact ranges are within one expression. */ export const semanticNodesWithinRange = ( nodes: readonly JavaScriptSemanticGraphNode[], range: JavaScriptSourceRange, ): JavaScriptSemanticGraphNode[] => nodes.filter( (node) => node.identity.source_range !== null && contains(range, node.identity.source_range), ); /** Report extractor support without treating missing families as absence. */ export const semanticFamilyStatus = ( family: (typeof JAVASCRIPT_SEMANTIC_RELATION_FAMILIES)[number], analysis: JavaScriptArtifactAnalysis, ): "complete" | "partial" | "unknown" | "unsupported" => { if ( ![ "call-flow", "boundary", "child-process", "closure", "configuration", "data-flow", "event", "object-flow", "promise-ownership", "request", "resource-lifecycle", "timer", ].includes(family) ) return "unsupported"; return analysis.truncated_scopes === 0 ? "partial" : "unknown"; }; const contains = ( outer: JavaScriptSourceRange, inner: JavaScriptSourceRange, ): boolean => pointCompare(outer.start, inner.start) <= 0 && pointCompare(outer.end, inner.end) >= 0; const pointCompare = ( left: JavaScriptSourceRange["start"], right: JavaScriptSourceRange["start"], ): number => left.line - right.line || left.column - right.column; const positionKey = (range: JavaScriptSourceRange): string => `${String(range.start.line).padStart(12, "0")}:${String(range.start.column).padStart(12, "0")}`;