paulbartrum / jurassic

A .NET library to parse and execute JavaScript code.
MIT License
868 stars 121 forks source link

3.2.1 backward compatibility issues #204

Closed ertant closed 3 years ago

ertant commented 3 years ago

Hi, i have tried to upgrade 3.2.1. It has of great and modern JS features but has some of code level backward compatibility issues.

paulbartrum commented 3 years ago

ObjectInstance.Properties method marked as "internal"

Not sure why I changed this; I will make it public again.

There is no overload for JavaScriptException takes a innerException parameter without line number and file name.

Sure, I can add that.

ObjectInstance.GetMissingPropertyValue(object) virtual function is completely gone.

This functionality has been replaced by the ECMAScript 6 Proxy class. You can intercept property reads and writes and much more besides. :-)

JSON.stringify(input) throws error if input set to null instead of returning "null" string value

You should use Null.Value, which represents the JavaScript null value, instead of using null directly. Jurassic doesn't handle null consistently.

lsim commented 2 years ago

If anyone else was wondering how to replace invocations to the now removed ObjectInstance.GetMissingPropertyValue(object) virtual function, an override of object GetPropertyValue(object key, object thisValue) seems to do the trick.

I was messing about trying to figure out how to use the new ES6 Proxy functionality for this, but I couldn't figure out how it relates to ObjectInstance.GetMissingPropertyValue(object) as suggested by Paul above.

paulbartrum commented 2 years ago

ES6 proxies allow you to wrap objects and use the wrapper to intercept operations. For example:

const target = {
    value: 'original value'
};

const handler = {
    get: function(target, prop, receiver) {
        if (prop === 'nonexistent') {
            return 'it exists now!';
        }
        // If the property name is not 'nonexistent' then return whatever property value is on the original object.
        return Reflect.get(target, prop, receiver);
    }
};

const proxy = new Proxy(target, handler);
console.log(proxy.value + ', ' + proxy.nonexistent);    // prints 'original value, it exists now!'

The proxy method should be more robust (less prone to change) then using GetPropertyValue(object, object) since it is part of the ECMAScript 6 standard, but realistically this project is in maintenance mode so it probably won't matter either way.

lsim commented 2 years ago

Right.

One problem I was previously solving with ObjectInstance.GetMissingPropertyValue(object) was about transparently providing access to the properties of a C# object with hundreds of properties without proxying each property individually. Both to save typing and to remove the need for maintenance when new properties were added to the proxied object.

I suppose it would be possible to change our setup to have parts of the current .net api actually be JS proxies which rely on a new GetADynamicPropertyValue(string) method on the .net side. I think such a hybrid approach might complicate our API maintenance a bit though.