Replacing deprecated PG code automatically

Hey folks!

We have agreed with @RaananW to implement automatic code replacement of deprecated code in all existing PGs. (original post: BabylonJS 5 release - #18 by roland)

@RaananW if I get it correctly the code will run on the client after the PG loads the code. I propose to create a banner informing the user that the original code was replaced automatically and it’s an experimental feature. In case of issues there should be a link to report the problem. Any ideas how can we collect the reports? Maybe a dedicated e-mail address will be enough.

As I wrote it uses acorn js parser so we will introduce a new dependency in the PG and for now it will replace only js based PG code. I will share the code with you before starting to implement it in the PG so you can a look at it and propose changes if needed.

Thank you!

:vulcan_salute:

r.

1 Like

Great suggestion!

Note about external dependencies - we are trying our best to avoid adding external dependencies or use them in our code libraries. the playground could be a different story, but we only want well established and well maintained libraries, otherwise we are stuck with… well… npm-dependency-chaos.

Would be great if we can do this on our own instead of using an external library, or use already-existing tools. If it’s not possible, let’s introduce a new dependency :slight_smile:

Now about the code - I like the idea of notifying the user that the code has changed. It shouldn’t be too visible, and shouldn’t look like a warning. a form of a small toast message saying “code adjusted” would suffice.

And something to clear beforehand - the code in already-existing playground is immutable and will not change. Future saves of this playground will have the new syntax, which is nice.

I started with a plain String.indexOf and String.substring solution but after 5 or 10 minutes I’ve realized that there are so many edge cases mainly when using a function to get a value for a given option that it would be quite a pain in the ass to implement a custom parser. However I can try to elaborate more on this and try to avoid acorn. We will see :stuck_out_tongue:

EDIT: I started with opening and closing parenthesis counting to match blocks (I can recall once you told me that you simply want to avoid new dependecies at all costs :stuck_out_tongue: ) but there are arrow functions, classic functions, nested functions, etc. and I’ve already worked with acorn before so it was quite a predictable move from me to jump on the acorn bandwagon.

ACK

ACK as well :slight_smile:

I believe a simple <script> will do the job and we won’t need to introduce a new npm dependecy. However it’s a dependency as well :smiley: Maybe we can approach the problem from the other side and we could offer the user to replace the deprecated methods. If the user responds positively we can inject the script dynamically and run it. There is another solution I have in my mind. We could create a single API endpoint for doing this job. It’ll require resources on the server but we could use the API to replace any input code from any source with this solution…

Thanks! :slight_smile:

1 Like

the monaco editor already has a typescript worker in it by default. Typescript isn’t so easy to write transforms for though. ts-morph is good, but i don’t know if you can re-use the ts worker if you were to use ts-morph. anyway, ts-morph has an option to use an in memory file system , so you import {Project} from ts-morph and new Project(code, {fs: “in-memory”}) … something like that.

update:
did some fruitful googling.

good info generally, useful links at the top
.Sandbox: Support making customizations to monaco-typescript · Issue #191 · microsoft/TypeScript-Website · GitHub

specific implementation of extending the ts worker
.Sandbox: Support making customizations to monaco-typescript · Issue #191 · microsoft/TypeScript-Website · GitHub

public getCustomTransformers(): ts.CustomTransformers {
    return { 
        before: [ query ast similar to acorn here ]
    }
}

this is the demo playground code for the tuple record type where they just copy/pasted the ts worker and hand wrote their additions
.proposal-record-tuple/babel-plugin-experiment/packages/record-and-tuple-repl/src at 5a4a471740f8fec21d197f7ade3be8db8c566d89 · tc39/proposal-record-tuple · GitHub

another good one here as a ts language server plugin. not sure how this works with the monaco editor, but im pretty sure it does.
.TypeScript-TSServer-Plugin-Template/index.ts at main · orta/TypeScript-TSServer-Plugin-Template · GitHub

2 Likes

Hi Jeremy!
Thanks for your response! I will bookmark it for future reference.

I didn’t plan to transform the code using the Monaco Editor however it can be an alternative solution. We are talking about transforming the BABYLON.Mesh.CreateXXXX functions only in the first round so nothing fancy is really needed here. I believe the TS code can be replaced in the same manner as the JS code. If I can isolate the line with the function and tokenize it correctly (get the paramaters as string tokens) it is then very easy to transform the code by simply swapping/replacing the token positions and the token content. I’ll be trying to drop acorn and use a redneck style String.find / String.replace solution :slight_smile: Sometimes these solutions are the best ones :smiley:

1 Like

Hi @RaananW!
I ran into so many issues to solve the parsing without a parser that I might need to write a whole parser myself and we will end up where we started but with much more effort compared to using a ready made parser. I will try to find the lightest and most maintained js parser available and make a suggestion which one I find to most usable for us. Are you OK with that?

Thank you!

In case you’re interested here is a cool video about writing a js parser from scratch:

I feel like most, if not all of the deprecated functions can be replaced using a simple replace code. There is no need to integrate a parser to replace the CreateXXX functions. They should be relatively straight-forward to process, especially since we are talking about moving from a few function parameters to a single options parameter. We are actually already doing it for the deprecated functions, so it just required replacing. The other deprecated functions also require only a simple string replace. Do you see a real need for a parser right now?

Yes for simple statements. We may have nested functions to calculate the parameter values in complex statements.

Unfortunatelly No.

For example we have this input:

    const mesh = BABYLON.Mesh.CreateTube(
        "tube" + (idx =>  idx * 10) + `${"Webb, James"}`,
        () => {
            const path = calcPath(var1, var2)
            path.whatever()
            return path
        },
        radius * (() => {
            return Math.atan2(var1, var2)
        }),
        tesselation,
        function (i, distance) {
            return myArray[i] * distance
        },
        cap ?? 1,
        scene,
        sideOrientation,
        instance
    )

And there can be extra whitespaces too, etc. Yes, this is a quite unusal example and the most PGs will have much simpler code but there can be much more complex code as well.

I need to isolate all parameters, rebuild the options parameter as an object and I need to remove sideOrientation and instance if these two parameters were used. I can’t simply split the input by a comma. I believe you get the point that simple replace will not work here.

However I have a backup plan. If we want to cover only the majority of PGs not all of them I can simply find the start and the end of the function, split by comma and if tokens.length > maxParametersCount it means it’s a complex one an I can simply not to apply the code replacement.

Thank you!