Repository: sjbarag/brs (js)

Issue:
`no active host node: (internal):(-1)` occurs when attempting to observe a node that was passed in via callFunc
```
Assuming nodeA has field `field1`, and nodeB has function field `func1`

if we attempt to do this inside nodeB's func1:

' // some other component
nodeB.callFunc("func1", nodeA)

' // nodeB.brs
sub func1(nodeA as object)
    m.nodeA = nodeA
    m.nodeA.observeField("field1", "onField1Changed")       ' this emits "BRIGHTSCRIPT: ERROR: roSGNode.ObserveField: no active host node: (internal):(-1)" error in the log
end func
```

Pull request:
fix(rsg): Ensure hostNode set in <function> implementation
When a function is executed via `callFunc(name, ...args)`, we were accidentally losing the hostNode because we use interpreter.inSubEnv with the optional second parameter to pass in a custom environment. That environment is based on the prototype-like environment created for each component's definition, which can't include an accurate hostnode
based on runtime control flow.  Manually set a hostNode when calling functions via `callFunc`.

fixes #585

Patch:
diff --git a/src/brsTypes/components/RoSGNode.ts b/src/brsTypes/components/RoSGNode.ts
index 8b2b252..4f93405 100644
--- a/src/brsTypes/components/RoSGNode.ts
+++ b/src/brsTypes/components/RoSGNode.ts
@@ -636,6 +636,7 @@ export class RoSGNode extends BrsComponent implements BrsValue, BrsIterable {
 
                         subInterpreter.environment.setM(this.m);
                         subInterpreter.environment.setRootM(this.m);
+                        subInterpreter.environment.hostNode = this;
 
                         try {
                             // Determine whether the function should get arguments or not.


Test patch:
diff --git a/test/e2e/CallFunc.test.js b/test/e2e/CallFunc.test.js
index b89f1a9..0d77b0a 100644
--- a/test/e2e/CallFunc.test.js
+++ b/test/e2e/CallFunc.test.js
@@ -52,6 +52,7 @@ describe("callFunc", () => {
             "component: inside privateFunction",
             "private return value",
             "component: overriding parent func",
+            "callFunc can trigger observeField",
             "main: mocked component voidFuncNoArgs return value:",
             "this is a mock",
         ]);
diff --git a/test/e2e/resources/components/call-func/CallFuncTestbed.xml b/test/e2e/resources/components/call-func/CallFuncTestbed.xml
index a455549..2b6b2ae 100644
--- a/test/e2e/resources/components/call-func/CallFuncTestbed.xml
+++ b/test/e2e/resources/components/call-func/CallFuncTestbed.xml
@@ -6,5 +6,6 @@
         <function name="voidFuncFiveArgs" />
         <function name="returnValFuncOneArg" />
         <function name="overridenParentFunc" />
+        <function name="testObserve" />
     </interface>
 </component>
diff --git a/test/e2e/resources/components/call-func/scripts/CallFuncTestbed.brs b/test/e2e/resources/components/call-func/scripts/CallFuncTestbed.brs
index 8c98454..cd02956 100644
--- a/test/e2e/resources/components/call-func/scripts/CallFuncTestbed.brs
+++ b/test/e2e/resources/components/call-func/scripts/CallFuncTestbed.brs
@@ -1,5 +1,9 @@
 sub init()
     m.componentField = "componentField value"
+    m.emptyNode = createObject("roSGNode", "ContentNode")
+    m.emptyNode.update({
+        observeMe: false
+    }, true)
 end sub
 
 function returnValFuncOneArg(args as object) as object
@@ -31,3 +35,12 @@ end function
 function overridenParentFunc() as string
     return "component: overriding parent func"
 end function
+
+sub testObserve()
+    m.emptyNode.observeField("observeMe", "onObserveMeChanged")
+    m.emptyNode.observeMe = true
+end sub
+
+sub onObserveMeChanged(event as object)
+    print "callFunc can trigger observeField"
+end sub
diff --git a/test/e2e/resources/components/call-func/scripts/main.brs b/test/e2e/resources/components/call-func/scripts/main.brs
index adeddfd..959b3a2 100644
--- a/test/e2e/resources/components/call-func/scripts/main.brs
+++ b/test/e2e/resources/components/call-func/scripts/main.brs
@@ -19,6 +19,8 @@ sub main()
 
     print node.callFunc("overridenParentFunc")
 
+    node.callFunc("testObserve")
+
     _brs_.mockComponent("CallFuncTestbed", {
         voidFuncNoArgs: function() as string
             return "this is a mock"