
Show HN: A library to record and intercept JavaScript at runtime - Schampu
http://maierfelix.github.io/Iroh/
======
ldd
I'm not sure how relevant my code is, but I did something similar using
Proxies[0] for a game engine built on javascript (RPG Maker MV) following some
useful advice I found online[1].

I presume that the same type of logic could be used to make more powerful
loggers.

[0]:[https://github.com/ldd/plugin-analyzer](https://github.com/ldd/plugin-
analyzer) [1]:[http://exploringjs.com/es6/ch_proxies.html#sec_proxies-
expla...](http://exploringjs.com/es6/ch_proxies.html#sec_proxies-explained)

~~~
Schampu
Proxies are definitely a nice catch, but won't allow full code
instrumentation. Iroh doesn't use proxies but patches the submitted code to
allow full code instrumentation including call tree recording and full ES5
code support.

If you're wondering what the patched code looks like:

 _Input_ :

    
    
      function add(a, b) {
        return a + b;
      };
      add(2, 4);
    

_Output_ :

    
    
      const $$STx1 = Iroh.stages["$$STx1"];
      var $$frameValue = void 0;
      $$STx1.$45(5)
      function add(a, b) {
        $$STx1.$4(6, this, add, arguments);
        return $$STx1.$1(1, "add", $$STx1.$32(7, 1, a, b));
        $$STx1.$5(6, this);
      }
      ;
      $$STx1.$44($$frameValue = $$STx1.$2(4, this, add, null, [$$STx1.$30(2, 2), $$STx1.$30(3, 4)]));
      $$STx1.$46(5, $$frameValue)

~~~
ldd
partial call tree recording is supported, I think. Take a look at section
"28.3.2 Intercepting method calls" from the link I posted above.

More importantly, you are entirely right about ES5 support. Babel doesn't
polyfill Proxies, and the google polyfill is not as powerful.

~~~
Schampu
Interesting! One of the main challenges of Iroh was to always keep track of
all branches (calls, ifs, loops..) correctly. All listeners provide an
_indent_ value which represents the level of branch deepness and can be used
in _code flow_ visualizations. When your program is inside a _function-
>loop->if_ and a return is inside there, then you have to manually leave _if-
>loop_ until you get to according function to return on.

------
Schampu
Hi there,

the code for the example is just ~100 LOC - it's a showcase of a library
called "Iroh", which brings dynamic code analysis to the whole ES5 syntax. If
you're wondering what the essence behind the example is, then I really
recommend to give these links a try:

Github:
[https://github.com/maierfelix/Iroh](https://github.com/maierfelix/Iroh)

More examples:
[https://maierfelix.github.io/Iroh/examples/index.html](https://maierfelix.github.io/Iroh/examples/index.html)

Cheers!

~~~
dang
Since the big project is more interesting and didn't get much attention, we've
changed the URL to that from [https://maierfelix.github.io/Iroh/examples/type-
checking/](https://maierfelix.github.io/Iroh/examples/type-checking/). We also
adopted your title from
[https://news.ycombinator.com/item?id=15040182](https://news.ycombinator.com/item?id=15040182)
as a way of fending off the title nitpicks re 'polymorphism'. (Submitted title
was "JavaScript: Tracing Polymorphism at Runtime".)

------
SOLAR_FIELDS
This is great. Is there anything similar for Scala applications? I had wanted
to do something similar to reverse an ETL pipeline of a codebase I do not have
control of. The idea would be to send some data through the pipeline and watch
it as it is stored in variables and transformed.

------
lozzo
awesome stuff. I took a look at the code and I was marvelling on how clever
the solution is. In particular in creating the 'mock' code.

//> const $$STx89 = Iroh.stages["$$STx89"]; //> var $$frameValue = void 0; //>
$$STx89.$45(27) //> $$STx89.$44($$frameValue = i = $$STx89.$35(25, 0, "i",
null, $$STx89.$30(26, 23))); //> $$STx89.$46(27, $$frameValue) //>

Well done.

[https://sequential.js.org/live.html#DYewhgJgFA5AFgFwQBwM4C4D...](https://sequential.js.org/live.html#DYewhgJgFA5AFgFwQBwM4C4D0mC2YCWApgE4Bmhw+AHgHQDm+CcArgEY34iYCSxIcmCPlQJM+PnAC0rPgHdUJGgCtUMAJQBuAFABjEADtUIYIRqg6UfYVkACXvxoBlBGDqFY+ALwAmAMzqaVB1ifGQETS0gA)

------
z3t4
This is awesome! I wonder if it will be possible to find undefined object
properties with this !?

~~~
Schampu
[https://jsfiddle.net/yurctL2c/3/](https://jsfiddle.net/yurctL2c/3/)

~~~
z3t4
I mean like misspelled properties eg. obj.x

edit: I figured it out myself, just replace ASSIGN with MEMBER ! Awesome!

I've been thinking of how to do this statically for a while now, but
dynamically is good enough, as it still will be able to point out the bug
before you even start debugging. I think this is game changing and will make
things like Typescript feel like stone-age. I'm currently working on an
editor/IDE for JavaScript and I can just add a check-box like "static typing"
and you'll get warnings every time a variable or function parameter change
type.

~~~
ldd
proxies can do this relatively easily.[0]

Here's a minimal fiddle doing just that:
[https://jsfiddle.net/6v82dj01/](https://jsfiddle.net/6v82dj01/)

As for actual implementations, I used it in a small analyzer for RPG Maker MV
plugins[1] that roughly does what you want with very little actual code[2].

[0]: [http://exploringjs.com/es6/ch_proxies.html#sec_proxies-
expla...](http://exploringjs.com/es6/ch_proxies.html#sec_proxies-explained)
[1]: [https://github.com/ldd/plugin-analyzer](https://github.com/ldd/plugin-
analyzer) [2]:[https://github.com/ldd/plugin-analyzer/blob/master/plugin-
an...](https://github.com/ldd/plugin-analyzer/blob/master/plugin-
analyzer.js#L22-L49)

~~~
z3t4
yes, but you have to manually select which objects to watch, eg in your
script, it goes through the window object and adds the Proxy observer to a set
of classes. But Iroh doesn't use Proxies. With Iroh you can trigger an event
for example "Iroh.MEMBER" and check if the property is undefined.

~~~
ldd
I only observe certain classes because observing anything and everything is
not convenient. Nothing prevents you from doing

`window = new Proxy(window, handler)`

(or more generally, to Proxy the global object) where the handler replaces
anything with a Proxied version of it either once a trap triggers (yu-gi-oh
style) or immediately.

Then again, I did not write the specification for `Proxy` and Iroh is cool. It
probably has plenty of use-cases where Proxy would not do a good job. I'm just
showing what we have right now.

------
Tade0
Pretty cool. I was meaning to create something like this for a while now, but
never got to the point where it started being usable in larger projects.

------
Felz
Very neat! I could definitely use this for one of my side projects, which
injects this sort of instrumentation into a webpage through a script tag.

------
javajosh
I think the interest for the HN crowd should be the enabling technology, which
is Proxy[0]. It provides a way for user code to trigger on property definition
& access, as well as function invocation. Dynamic debugging is a good first
application of this technology, but is by no means comprehensive.

0 - [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)

------
devdoomari
+1 seems to be useful for investigating unit-test failures!

------
astral303
This is not polymorphism. This is type coercion.

~~~
k__
Why not?

you have a function that takes something that is polymorphic in the sense that
I can be added. A string and a number aren't the same type, but they share
some kind of interface.

------
alistproducer2
"Polymorphism" is being used incorrectly here. Please see here [0] for a good
explanation.

[0]:
[https://docs.oracle.com/javase/tutorial/java/IandI/polymorph...](https://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html)

~~~
leeoniya
as with a lot of js terminology, it's been re-appropirated:

[http://mrale.ph/blog/2015/01/11/whats-up-with-
monomorphism.h...](http://mrale.ph/blog/2015/01/11/whats-up-with-
monomorphism.html)

also, polyfill (hip) === shim (no longer hip)

~~~
nickfargo
The term is not merely a recent appropriation. Parametric polymorphism is a
concept from functional programming and formal type theory, with application
far beyond just JavaScript.

~~~
leeoniya
tbh, polymorphism makes more sense to me in the parametric definition [in the
context of weak types/signatures] than in the standard oop def.

