Repository: automerge/automerge (language: rust)

Issue:
[BUG] ReferenceError: context is not defined in `proxies.ts`
If you manage to trigger a range error, you get another exception instead, namely:

`ReferenceError: context is not defined`

The issue is on [this line](https://github.com/automerge/automerge/blob/4999578a7ca138e59efa12a90a1dd9380472e9f1/javascript/src/proxies.ts#L170), where the variable context is not defined.


Discussion / hints:

Fix patch:
diff --git a/javascript/src/proxies.ts b/javascript/src/proxies.ts
index 9240d034e..23b8ed46a 100644
--- a/javascript/src/proxies.ts
+++ b/javascript/src/proxies.ts
@@ -142,6 +142,7 @@ function import_value(
   value: any,
   textV2: boolean,
   path: Prop[],
+  context: Automerge,
 ): ImportedValue {
   switch (typeof value) {
     case "object":
@@ -255,7 +256,8 @@ const MapHandler = {
     if (key === CLEAR_CACHE) {
       return true
     }
-    const [value, datatype] = import_value(val, textV2, [...path, key])
+
+    const [value, datatype] = import_value(val, textV2, [...path, key], context)
     switch (datatype) {
       case "list": {
         const list = context.putObject(objectId, key, [])
@@ -374,7 +376,7 @@ const ListHandler = {
     if (typeof index == "string") {
       throw new RangeError("list index must be a number")
     }
-    const [value, datatype] = import_value(val, textV2, [...path, index])
+    const [value, datatype] = import_value(val, textV2, [...path, index], context)
     switch (datatype) {
       case "list": {
         let list: ObjID
@@ -588,7 +590,7 @@ function listMethods<T extends Target>(target: T) {
     },
 
     fill(val: ScalarValue, start: number, end: number) {
-      const [value, datatype] = import_value(val, textV2, [...path, start])
+      const [value, datatype] = import_value(val, textV2, [...path, start], context)
       const length = context.length(objectId)
       start = parseListIndex(start || 0)
       end = parseListIndex(end || length)
@@ -680,7 +682,7 @@ function listMethods<T extends Target>(target: T) {
       }
       const values = vals.map((val, index) => {
         try {
-          return import_value(val, textV2, [...path])
+          return import_value(val, textV2, [...path], context)
         } catch (e) {
           if (e instanceof RangeError) {
             throw new RangeError(`${e.message} at index ${index} in the input`)


Test patch:
diff --git a/javascript/test/proxies.ts b/javascript/test/proxies.ts
index 757cefca0..f2590eb95 100644
--- a/javascript/test/proxies.ts
+++ b/javascript/test/proxies.ts
@@ -12,6 +12,18 @@ describe("Proxies", () => {
     doc = from({ list: ["a", "b", "c"] })
   })
 
+  describe("recursive document", () => {
+    it("should throw a useful RangeError when attempting to set a document inside itself", () => {
+      type RecursiveDoc = { [key: string]: RecursiveDoc };
+      const doc = from<RecursiveDoc>({});
+      change(doc, d => {
+        assert.throws(() => {
+          d.doc = doc
+        }, /Cannot create a reference to an existing document object/)
+      })
+    })
+  })
+
   describe("List Iterators", () => {
     it("should return iterable entries", () => {
       change(doc, d => {