Object has circular references¶
objectHasCircularReferences is a built‑in scan rule that detects objects that contain circular (self‑referential) references.
It performs a depth‑first traversal using a WeakSet to track visited nodes. When the rule encounters an object that has already been seen, it emits a warn‑level object.has.circular-references scan event. If the value is not a non‑array object or no cycles are found, no events are emitted.
Signature¶
export const objectHasCircularReferences: ScanRule (raw: unknown, path: FieldPath) => JaneEvent[]
Events¶
| Event code | Description |
|---|---|
object.has.circular-references |
Object graph contains circular references. |
Design rationale¶
- Detects cyclic object graphs that can break serializers, diffing logic, or recursive analysis.
- Uses a
WeakSetto track visited objects and detect revisits efficiently. - Performs a stack‑based traversal to avoid unbounded recursion.
- Emits a warning when a cycle is detected.
- Surfaces structural hazards early so containment and policy layers can respond safely.
- Performs no mutation or restructuring of the input.
Invoke¶
objectHasCircularReferences runs automatically whenever the scan stage is enabled.
Activation methods:
- Enable scan explicitly:
jane.value(input).scan(). - Use a mode that enables scan:
strict()enables scan by default.moderate()andlax()do not enable scan unless.scan()is called.- Enable scan with policy:
jane.value(input).withPolicy({ mode: 'strict' }).
If scan is not enabled or if the value is not a plain object, objectHasCircularReferences does not run and no cycle detection occurs.
Examples¶
Circular reference detected¶
const obj: any = {};
obj.self = obj;
const result = objectHasCircularReferences(obj, "$");
// → [ JaneEvent{ kind: "warn", code: "object.has.circular-references", ... } ]
Nested but acyclic object¶
const result = objectHasCircularReferences({ a: { b: 1 } }, "$");
// → []
Non‑object or array value¶
const result = objectHasCircularReferences([1, 2, 3], "$");
// → []