Migrating to Max 9 - how to find all js max objects

soundyi's icon

What is the proper way to find all [js] objects in a patcher, so that I can migrate them ALL to [v8]?

Using the searchbar of the patcher via "cmd + f" (on mac) and "js" as the search term brings up all kinds of max objects that have "js" in their box - even max abstractions whose filename have "js" somewhere in their name.

I hope there is some special encoding to narrow the results down to the max object type - I tried to use square bracket ([js, [js]) with no success.

Reason being : I use TypeScript for my JavaScript stuff and I want to upgrade the transpilation from ES5 to ES6 to make use of the Map type and all the other v8 goodies.

I have to migrate all js Max object of a Max project and cannot go one by one as needed, as all JavaScript files are rooted in 1 TypeScript project and hence share the same "build process".

TFL's icon

Did you try the Patcher List View? It doesn't search in subpatchers but seems better at finding specific objects.

Another approach would be to open the patcher file in an IDE and search for .js or "text" : "js .

Or consolidate your patch as a Project which will bring all used js files into the same place. But then you'll still need to replace [js] by [v8].

Small hint just in case, when upgrading your codebase from ES5 to ES6, make sure to keep your attribute variables as var instead of let or const, otherwise they won't work as attributes! It is distreectly stated in the v8 help file, under the "attributes" tab.

soundyi's icon

Thanks @TFL - yes I tried the Patcher List View, but the root patchers in my project are more like a complex ecosystem and hence are quite spacious and nested, so the Patcher List View (as helpful it is in daily patching life) does not help that much.

And yes, I also thought about to build a little parses to pick things up, because looking at search results in an IDE is of course an option, but drains my eyes & focus. Migrating a codebase is one of the tasks in a developers life that calls for a holiday after finishing it (and that's one reason I waited to switch to Max 9 for so long) ... but I hope I can make it more like a breeze ;-).

I think I will go for a traditional checklist alike approach by navigating through the main / root patchers of the max project in a visual meaningful way and make the IDE search at the end to verify that I've picked up everything.

As I used [js] mainly in max abstractions this should be approachable - a nightmare it would be to go through a land of copy & pasted subpatchers.

But there are other Max projects that will have to follow in some time in the future - so maybe its worth to think about a parser / half-automated workflow again.

Your hint regarding attribute varibables / var is great - but luckily I don't use this feature and to be honest I have no spontaneous idea how to tackle this with a single TypeScript project to JavaScript transpilation.

I assume that if the TS compiler uses ES6+ as a target there is no easy way to mark certain variables to "come out" as var - everything will be translated to let & const.

So the only the thing I can imagine is to use a 2 layer TypeScript project approach, one of which is just the "max patcher facing js", which uses ES5 as its target and the other project as a library build with a ES6 target.

Joshua Kit Clayton's icon

You may find something like this color replacement utility for performing batch editing operations on patchers a helpful starting point for scripting. You'll likely need to script replace the js objects with v8 objects, rather than reset patcher colors, but hopefully the basic idea is clear.

As for var vs let, since var is a valid keyword in both Typescript and ES6, you can simply use var when defining attributes in your typescript and it will transpile to var in both ES5 and ES6.

soundyi's icon

Thanks for your hints @Joshua - in the past I did not even try to explore odd (& ancient) JavaScript techniques in TypeScript (to keep my brain storage free for the stuff that matters ;-), so your hint "var is a valid keyword in both Typescript and ES6" has broadened my knowledge & focus ;-).

Sometimes its worth to know the "odd ways" to shortcut otherwise clumsy implementations - hence your hint is really valuable - I already gave it a try and it works fine with ES6 compiler options in tsconfig.json.

Giving this a try and seeing [attrui] working way better on "attribute declarations" with [v8] than with [js] makes me think of using JavaScript (respectively TypeScript) in other ways than I used to, and build complete "attrui configurable" JS/TS Objects ... in the object-oriented way of code design.

+++

Building further on this idea as Max 9 gives more value and options to code via codeboxes - what is your proposal for a JS/TS library approach?

In way of building a set of TS classes / class library for the application domain once, and using them in several JavaScripts via [v8] objects, that import those classes, each implementing a different feature from the "fundamentals of the class library".

With ES5 I got trouble to configure esbuild in such a way that it worked with [js] - otherwise it worked fine with [node.script].

So my workaround was a second library project that build into another directory that I included in the search path of the Max project - but this can get tricky by the nature of how the Max search path works, so e.g. having files with the same name creates errors ... that can be circumvented using the bundler approach.

As the [v8] help patcher (on the modern-js tab) says that the current version of the v8 engine used in Max 9 is the one found in node 18, I hope that a bundle strategy is possible - although [node.script] in Max 8.6.x uses Node v20.6 , so problems could still arise using my existing esbuild configurations for [node.script] in Max 8.

But bundled codes bloats memory - shared sources are loaded several times for each [v8] although it could be only once. On the other side I don't know if there are any "cross v8 max objects" optimization, in the sense that a shared source is effectively only loaded once - or using a shared code approach for several [v8] objects ends up in loading the shared source for each one anyways.

Or in other words : as JavaScript code is compiled by Max 9 for each [v8] individually and there is no concept or technique (?) of a compiled shared library (.dll alike), we end up in bundled code anyway, hence using a bundler is the best approach when using [v8]?

+++

But things change when we want to use [v8.codebox] - using [v8.codebox] with bundled code does not make that much sense, as you get lost in the amounts of code visible in the codebox (it's not an IDE), but this is only an option when coding immediately in JavaScript anyway. I don't see a route for using TypeScript via [v8.codebox], or do i miss something?

But anyway - coding small chunks of code in JavaScript does not hurt that much ;-), so how to go about a shared library approach for [v8.codebox]?

Any thoughts & inside on this are very much appreciated - building a Max project structure, especially the JavaScript side of things, that build upon how Max 9 & its new v8 integration is designed and meant to be used, is not a thing can be researched by some hours of try & error ... this would take the very long way home ;-) ... hence knowing the best practices for this is more than a time saver - as having an odd patcher & architecture in place stalls creativity and blocks bringing our ideas to life.

soundyi's icon

@Joshua, I took a look at your patcher and JavaScript for migration max patcher and it looks interesting.

I discuss this a little bit, so that this might trigger a discussion with other users or help others to get some ideas for their way to migrate from [js] to [v8].

The file i/o stuff in your [v8.codebox] JavaScript makes me scary ;-), but this can be replaced via a [node.script] and fully documented "fs" goodness - creating an array with filenames to operate on.

I think I got your technique to modify a patcher on the fly via [pcontrol] and "max.frontpatcher", which is one of these beautiful hacks that maybe only an insider can come up with - cool technique!

The challenge with my Max patchers are, that they are more like a landscape and quite nested - the [js] objects are inside bpatchers that load a max abstraction ... a lot of UI exposing bpatcher in an ocean of a Max patcher, so to speak.

So there would be a lot of patcher & maxobj traversal to code, if I do it the "top down" way.

+++

But I could also go the other way around and easily generate a list with all filenames of the max abstractions that have to be processed - easily done with [node.script].

From there I have a single patcher (the max abstraction) to work with and apply the patcher technique you have shown, but still this can get tricky as there might be some nested subpatcher path to take until the [js] is accessible.

Recursive traversal is not that hard to implement, but what makes me doubt that this is a good idea respectively makes me feel that it might become a "time absorbing thingy" : I cannot debug the JavaScript while its executing in [v8] or is there a similar approach to what's available for [node.script] that I am not aware of?

+++

Leading to a third option : using a [node.script] and operating on the .maxpat files as JSON files.

The challenge : a well defined JavaScript object path I can traverse down and find all the [js] "boxes" - what @TFL mentioned with the search pattern

"text" : "js 

and replace them with a [v8] version.

Taken a quick look, it seems that replacing "js" with "v8" maybe not enough, as [v8] has new features and properties and I'm not sure if they are optional.

But I got a feeling that this might be the easiest way for me, especially as NodeJS can be debugged - not only the [node.script] way in Max, but also the VS code way, so I can code this in a transparent way and not the "black box" way (dumping log statements would sheds some light into the black box, but its by far not that convenient as using a "step by step empowering" debugger ... floods of log statements are not that kind of waves I love ;-).

So the "final question" is : are there well defined "traversal patterns" to navigate the .maxpat JSON down to the [js] boxes?