2026-07-22 20:38:26 +08:00
|
|
|
import type {
|
|
|
|
|
JavaScriptBindingProvenance,
|
|
|
|
|
JavaScriptModuleOrigin,
|
|
|
|
|
} from "./javascriptSemanticIr.js";
|
2026-10-09 22:45:18 +08:00
|
|
|
import type { JavaScriptSemanticPrimitive } from "./javascriptSemanticValueTypes.js";
|
2026-10-09 23:17:17 +08:00
|
|
|
import { compareUnicodeCodePoints } from "../unicodeCodePointOrder.js";
|
2026-07-22 20:38:26 +08:00
|
|
|
|
2026-08-10 14:57:44 +08:00
|
|
|
/** Construct exact local provenance without inventing module origins. */
|
|
|
|
|
export const semanticLocalProvenance = (): JavaScriptBindingProvenance => ({
|
|
|
|
|
status: "local",
|
|
|
|
|
origins: [],
|
|
|
|
|
reason: null,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/** Construct an unresolved provenance outcome with an actionable reason. */
|
|
|
|
|
export const semanticUnresolvedProvenance = (
|
2026-09-29 15:30:43 +08:00
|
|
|
status: "unknown" | "cycle",
|
2026-08-10 14:57:44 +08:00
|
|
|
reason: string,
|
|
|
|
|
): JavaScriptBindingProvenance => ({ status, origins: [], reason });
|
|
|
|
|
|
2026-09-29 13:57:24 +08:00
|
|
|
/** Construct ambiguous provenance while retaining every origin. */
|
2026-08-10 14:57:44 +08:00
|
|
|
export const semanticAmbiguousProvenance = (
|
2026-07-22 20:38:26 +08:00
|
|
|
origins: readonly JavaScriptModuleOrigin[],
|
2026-08-10 14:57:44 +08:00
|
|
|
reason: string,
|
|
|
|
|
): JavaScriptBindingProvenance => ({ status: "ambiguous", origins, reason });
|
2026-07-22 20:38:26 +08:00
|
|
|
|
2026-09-29 13:57:24 +08:00
|
|
|
/** Normalize exact module origins into one provenance classification. */
|
2026-07-22 20:38:26 +08:00
|
|
|
export const semanticOriginsProvenance = (
|
|
|
|
|
origins: readonly JavaScriptModuleOrigin[],
|
|
|
|
|
): JavaScriptBindingProvenance => {
|
|
|
|
|
const unique = uniqueSemanticOrigins(origins);
|
2026-08-10 14:57:44 +08:00
|
|
|
const origin = unique[0];
|
|
|
|
|
return unique.length === 1 && origin !== undefined
|
|
|
|
|
? { status: "module", origins: [origin], reason: null }
|
|
|
|
|
: semanticAmbiguousProvenance(unique, "Multiple module origins.");
|
2026-07-22 20:38:26 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** Deduplicate and canonically order module origins. */
|
|
|
|
|
export const uniqueSemanticOrigins = (
|
|
|
|
|
origins: readonly JavaScriptModuleOrigin[],
|
|
|
|
|
): JavaScriptModuleOrigin[] =>
|
|
|
|
|
[
|
|
|
|
|
...new Map(
|
|
|
|
|
origins.map((origin) => [semanticOriginKey(origin), origin]),
|
|
|
|
|
).values(),
|
|
|
|
|
].sort((left, right) =>
|
2026-10-09 23:17:17 +08:00
|
|
|
compareUnicodeCodePoints(semanticOriginKey(left), semanticOriginKey(right)),
|
2026-07-22 20:38:26 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const semanticOriginKey = (origin: JavaScriptModuleOrigin): string =>
|
2026-10-09 12:09:42 -04:00
|
|
|
JSON.stringify([origin.specifier, origin.importedPath]);
|
2026-07-22 20:38:26 +08:00
|
|
|
|
|
|
|
|
/** Canonically distinguish primitive values across type boundaries. */
|
|
|
|
|
export const semanticPrimitiveKey = (
|
|
|
|
|
value: JavaScriptSemanticPrimitive,
|
|
|
|
|
): string =>
|
|
|
|
|
`${value === null ? "null" : typeof value}:${JSON.stringify(value)}`;
|
2026-10-06 21:25:59 -05:00
|
|
|
|
|
|
|
|
/** Match namespace paths only after the caller has identified a Node built-in. */
|
|
|
|
|
export const semanticBuiltinNamespacePath = (
|
|
|
|
|
importedPath: readonly string[],
|
|
|
|
|
): boolean =>
|
|
|
|
|
importedPath.length === 0 ||
|
|
|
|
|
(importedPath.length === 1 && importedPath[0] === "default");
|