mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
765e809e36
Remove forwarding wrappers and shadow aliases, migrate callers and verification scripts to their owners, and share one exhaustive semantic resource-bound projection.
106 lines
3.5 KiB
TypeScript
106 lines
3.5 KiB
TypeScript
import type {
|
|
JavaScriptSemanticProperty,
|
|
JavaScriptSemanticValue,
|
|
} from "./javascriptSemanticValueTypes.js";
|
|
|
|
/** Static container inventory; partial siblings do not weaken retained slots. */
|
|
export interface JavaScriptSemanticContainer {
|
|
readonly slots: readonly JavaScriptSemanticProperty[];
|
|
readonly coverage:
|
|
| { readonly status: "complete"; readonly omitted: 0 }
|
|
| { readonly status: "partial"; readonly omitted: number | null };
|
|
}
|
|
|
|
/** Read the same slot inventory for object, array, and return projections. */
|
|
export function semanticContainer(
|
|
value: Extract<
|
|
JavaScriptSemanticValue,
|
|
{ readonly status: "object" | "array" }
|
|
>,
|
|
): JavaScriptSemanticContainer;
|
|
export function semanticContainer(
|
|
value: JavaScriptSemanticValue,
|
|
): JavaScriptSemanticContainer | null;
|
|
export function semanticContainer(
|
|
value: JavaScriptSemanticValue,
|
|
): JavaScriptSemanticContainer | null {
|
|
if (value.status === "object")
|
|
return {
|
|
slots: value.properties,
|
|
coverage: value.unknownProperties
|
|
? { status: "partial", omitted: value.omittedProperties }
|
|
: { status: "complete", omitted: 0 },
|
|
};
|
|
if (value.status === "array")
|
|
return {
|
|
slots: value.items,
|
|
coverage: value.unknownItems
|
|
? { status: "partial", omitted: value.omittedItems }
|
|
: { status: "complete", omitted: 0 },
|
|
};
|
|
return null;
|
|
}
|
|
|
|
/** Resolve a full static own-property path without conflating missing siblings. */
|
|
export const semanticSlotAtPath = (
|
|
value: JavaScriptSemanticValue,
|
|
path: readonly string[],
|
|
): JavaScriptSemanticProperty => {
|
|
const leafName = path.at(-1) ?? "";
|
|
let current: JavaScriptSemanticProperty = {
|
|
name: "",
|
|
presence: "present",
|
|
value,
|
|
};
|
|
for (const [index, name] of path.entries()) {
|
|
const container = semanticContainer(current.value);
|
|
if (current.presence !== "present" || container === null)
|
|
return {
|
|
name: leafName,
|
|
presence: "unknown-coverage",
|
|
value:
|
|
"reason" in current.value
|
|
? {
|
|
...current.value,
|
|
reason: `${current.value.reason} Cannot continue ${semanticPropertyPointer(path)} through receiver ${semanticPropertyPointer(path.slice(0, index))}.`,
|
|
}
|
|
: {
|
|
status: "unknown",
|
|
reason: `Cannot resolve ${semanticPropertyPointer(path)} through ${current.value.status} receiver ${semanticPropertyPointer(path.slice(0, index))}.`,
|
|
},
|
|
};
|
|
// Array position inventories omit the intrinsic non-enumerable length slot.
|
|
// Its own presence is guaranteed even when no exact length is retained.
|
|
if (current.value.status === "array" && name === "length") {
|
|
current = {
|
|
name,
|
|
presence: "present",
|
|
value: {
|
|
status: "unknown",
|
|
reason: "Array length is present but its value is not retained.",
|
|
},
|
|
};
|
|
continue;
|
|
}
|
|
const observed = container.slots.find((slot) => slot.name === name);
|
|
current = observed ?? {
|
|
name,
|
|
presence:
|
|
container.coverage.status === "complete"
|
|
? "absent"
|
|
: "unknown-coverage",
|
|
value: {
|
|
status: "unknown",
|
|
reason: `Own property ${name} was not observed.`,
|
|
},
|
|
};
|
|
}
|
|
return current;
|
|
};
|
|
|
|
/** Encode path segments as an unambiguous JSON Pointer, preserving empty keys. */
|
|
export const semanticPropertyPointer = (path: readonly string[]): string =>
|
|
path
|
|
.map((key) => `/${key.replaceAll("~", "~0").replaceAll("/", "~1")}`)
|
|
.join("");
|