|
| 1 | +// DAS atom-handle hashing, a faithful port of the Python reference `hyperon_das/hasher.py`. |
| 2 | +// Handles are deterministic MD5 hashes of joined strings; getting these byte-identical to the |
| 3 | +// Python/Rust clients is the prerequisite for every query (a wrong handle means every match misses). |
| 4 | +// Node-only (uses node:crypto), like the rest of the bus client. |
| 5 | +import { createHash } from "node:crypto"; |
| 6 | + |
| 7 | +const JOINING_CHAR = " "; |
| 8 | +const MAX_LITERAL_OR_SYMBOL_SIZE = 10000; |
| 9 | +const MAX_HASHABLE_STRING_SIZE = 100000; |
| 10 | + |
| 11 | +export function computeHash(input: string): string { |
| 12 | + return createHash("md5").update(input, "utf8").digest("hex"); |
| 13 | +} |
| 14 | + |
| 15 | +/** Hash of a named type (`named_type_hash`). */ |
| 16 | +export function namedTypeHash(name: string): string { |
| 17 | + return computeHash(name); |
| 18 | +} |
| 19 | + |
| 20 | +/** Hash of a terminal node `(type, name)` (`terminal_hash`). */ |
| 21 | +export function terminalHash(type: string, name: string): string { |
| 22 | + if (type.length + name.length >= MAX_HASHABLE_STRING_SIZE) |
| 23 | + throw new Error("Invalid (too large) terminal name"); |
| 24 | + return computeHash(`${type}${JOINING_CHAR}${name}`); |
| 25 | +} |
| 26 | + |
| 27 | +/** Hash of a composite of element handles (`composite_hash`). */ |
| 28 | +export function compositeHash(elements: readonly string[]): string { |
| 29 | + let total = 0; |
| 30 | + for (const e of elements) { |
| 31 | + if (e.length > MAX_LITERAL_OR_SYMBOL_SIZE) |
| 32 | + throw new Error("Invalid (too large) composite elements"); |
| 33 | + total += e.length; |
| 34 | + } |
| 35 | + if (total >= MAX_HASHABLE_STRING_SIZE) throw new Error("Invalid (too large) composite elements"); |
| 36 | + return computeHash(elements.join(JOINING_CHAR)); |
| 37 | +} |
| 38 | + |
| 39 | +/** Hash of an expression: the type hash followed by the element handles (`expression_hash`). */ |
| 40 | +export function expressionHash(typeHash: string, elements: readonly string[]): string { |
| 41 | + return compositeHash([typeHash, ...elements]); |
| 42 | +} |
0 commit comments