New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor and test custom marshalling logic #15113
Conversation
@@ -300,8 +239,12 @@ export function marshalNativeToInterpreter(interpreter, nativeVar, nativeParentO | |||
if (typeof maxDepth === "undefined") { | |||
maxDepth = Infinity; // default to infinite levels of depth | |||
} | |||
if (shouldCustomMarshalObject(nativeVar, nativeParentObj)) { | |||
return createCustomMarshalObject(interpreter, nativeVar, nativeParentObj); | |||
// TODO (pcardune): remove circular dependency |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: Address now, or in a near-future PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This TODO is still around after your last batch of changes. I assume you'd like to address it in the future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes :)
@@ -0,0 +1,69 @@ | |||
|
|||
module.exports = class CustomMarshaler { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not export default
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good question, will add a comment explaining. tl;dr: to make it work natively with node.js
nativeParentObj[marshalObj.requiredMethod] !== undefined) { | ||
return marshalObj.methodOpts || {}; | ||
} else { | ||
return {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having just extracted this helper, it'd be nice for it to have 100% test coverage.
isPrimitive: false, | ||
isCustomMarshal: true, | ||
type: typeof nativeObj, | ||
parent: nativeParentObj, // TODO (cpirich): replace with interpreter object? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this TODO worth keeping around anymore? (@cpirich?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this might break in strange ways with the latest interpreter version, which gets rid of the parent property entirely in favor of something a bit more complicated for which nativeParentObj probably doesn't make any sense.
|
||
constructor(code, customMarshaler, opt_initFunc) { | ||
super(code); | ||
if (!customMarshaler) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe better? if (!(customMarshaler instanceof CustomMarshaler))
constructor(code, customMarshaler, opt_initFunc) { | ||
super(code); | ||
if (!customMarshaler) { | ||
throw new Error("You must provide a CustomMarshaler to CustomMarshalingInterpreter"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be nice to cover this error case.
// this work from the parent class's constructor because it needs | ||
// customMarshaler to have been set before-hand. Unfortunately, javascript | ||
// does not allow us to set customMarshaler until after the parent constructor | ||
// has finished. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This TODO does not actually describe an action item. It should maybe be updated to describe a desired outcome (refactor constructors to do less work, deduplicate code with parent constructor by extracting a helper, etc).
obj === this.globalScope && | ||
!!(nativeParent = this.customMarshaler.globalProperties[name]) && | ||
!this.shouldBlockCustomMarshalling_(name, obj, nativeParent)) { | ||
customMarshalValue = nativeParent[name]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😆 I love that this one case of this method is not covered, especially because I can't really tell what this case is. Something about getting a custom-marshaled property from the interpreter's global scope?
if (!hasProperty && | ||
obj === this.globalScope && | ||
!!(nativeParent = this.customMarshaler.globalProperties[name]) && | ||
!this.shouldBlockCustomMarshalling_(name, obj, nativeParent)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This complex conditional gets reused in getProperty
, hasProperty
and setProperty
. Let's extract a helper.
} | ||
return; | ||
} | ||
scope = scope.parentScope; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It really seems like we should have a test over this method walking up the scope chain.
set customMarshalObjectList(customMarshalObjectList) { | ||
// TODO: perform validation on this | ||
this._customMarshalObjectList = customMarshalObjectList; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can these go away yet? They appear to get/set a property that's not used at all within the class, meaning anything calling them is probably broken anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hooray for better naming and new test coverage! 🎉 I've made some comments on cleanup and tightening up tests, but I see that you'd like to use this as a checkpoint. My only real concern before merge is whether the vestigial _customMarshalObjectList
property in the interpreter is going to cause problems.
I think this got better since the last time you looked at this. PTAL? |
* 4. If the property being looked up has been explicitly blocked from custom | ||
* marshalling, then don't return the native parent. | ||
*/ | ||
!this.shouldBlockCustomMarshalling_(name, obj, nativeParent) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤣 Great commenting here. Scary to even have a conditional this complicated and subtle, but great explanation.
} else { | ||
const nativeParent = this.getNativeParent_(obj, name); | ||
if (nativeParent) { | ||
customMarshalValue = nativeParent[name]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not seeing coverage for these new files from the browser extension, not sure why. Anyway, it looks like this line still isn't covered. Have trouble tracking down this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great!
@pcardune This change shipped yesterday. We got a Zendesk ticket this morning saying that the |
Looks like |
} | ||
} else { | ||
if (this.getNativeParent_()) { | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like getNativeParent should be called with parameters, like this: this.getNativeParent_(obj, name)
@islemaster is working on a fix
Here's what happened in the following commits:
codegen.marshalNativeToInterpreter
There are probably still some more tests to write, but I think this represents a good checkpoint that is worth merging into staging.