rea/src/application/javascript/JavaScriptReturnShapeProjec...

111 lines
3.9 KiB
TypeScript

import { jsonObjectSchema, jsonValueSchema } from "../../domain/jsonValue.js";
import {
partialApplicationCoverage,
truncatedApplicationCoverage,
} from "../../domain/javascriptApplicationEvidenceSchemas.js";
import type {
JavaScriptSemanticIr,
JavaScriptSemanticCallable,
JavaScriptSemanticModuleLink,
} from "../../domain/javascriptSemanticIr.js";
import { flattenSemanticReturnValue } from "../../domain/javascriptSemanticReturns.js";
import type { JavaScriptSourceRange } from "../../domain/javascriptStaticAnalysisTypes.js";
import type { JavaScriptArtifactGraphCoverage } from "./JavaScriptArtifactGraphContext.js";
export interface JavaScriptReturnShapeProjection {
readonly properties: ReturnType<typeof jsonObjectSchema.parse>;
readonly range: JavaScriptSourceRange;
readonly coverage: JavaScriptArtifactGraphCoverage;
readonly limitations: readonly string[];
}
/** Project one exact export/callable link into shallow bounded graph values. */
export const projectJavaScriptExportReturnShapes = (input: {
readonly ir: JavaScriptSemanticIr;
readonly link: JavaScriptSemanticModuleLink;
readonly modulePath: string;
readonly baseCoverage: JavaScriptArtifactGraphCoverage;
}): JavaScriptReturnShapeProjection | null => {
if (input.link.callableId === null || input.link.exportedName === null)
return null;
const callable = input.ir.callables.find(
({ callableId }) => callableId === input.link.callableId,
);
if (callable === undefined) return null;
const projection = projectReturnSites(callable);
const projectionOmitted =
projection.omittedSites +
projection.omittedFields +
projection.omittedCoverage;
const semanticOmitted = callable.returnCoverage.omittedCount;
const complete =
input.baseCoverage.status === "complete" &&
callable.returnCoverage.status === "complete" &&
projectionOmitted === 0;
const limits = input.baseCoverage.limits;
const omitted =
semanticOmitted === null ? null : semanticOmitted + projectionOmitted;
const coverage = complete
? input.baseCoverage
: projectionOmitted > 0
? truncatedApplicationCoverage(limits, omitted)
: partialApplicationCoverage(limits, omitted);
const limitations = [
...input.ir.limitations,
"Return shapes are inferred from inert syntax and do not prove runtime behavior.",
...(callable.returnSites.length === 0
? [
"No direct return value was retained; runtime return behavior remains unknown.",
]
: []),
];
return {
properties: jsonObjectSchema.parse({
semantic_role: "export-return-shapes",
module_path: input.modulePath,
exported_name: input.link.exportedName,
callable_id: callable.callableId,
callable_kind: callable.kind,
static_return_shapes: projection.shapes,
return_shape_coverage: {
status: callable.returnCoverage.status,
retained_return_sites: projection.shapes.length,
omitted_return_sites:
semanticOmitted === null
? null
: semanticOmitted + projection.omittedSites,
omitted_fields: projection.omittedFields,
omitted_property_coverage: projection.omittedCoverage,
projection_complete: projectionOmitted === 0,
},
}),
range: callable.location,
coverage,
limitations,
};
};
const projectReturnSites = (callable: JavaScriptSemanticCallable) => {
const retainedSites = callable.returnSites;
const shapes = retainedSites.map((site) => {
const flattened = flattenSemanticReturnValue(site.value);
const fields = flattened.fields.map((field) => ({
...field,
value: jsonValueSchema.parse(field.value),
}));
const propertyCoverage = flattened.propertyCoverage;
return {
source_range: site.location,
value_status: site.value.status,
fields,
property_coverage: propertyCoverage,
};
});
return {
shapes,
omittedSites: 0,
omittedFields: 0,
omittedCoverage: 0,
};
};