Files
rea/src/domain/javascript/javascriptSemanticSlots.ts
T
morluto 765e809e36 refactor: use canonical implementations and types directly
Remove forwarding wrappers and shadow aliases, migrate callers and verification scripts to their owners, and share one exhaustive semantic resource-bound projection.
2026-10-09 23:35:19 +08:00

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("");