Skip to content

reflection#649

Closed
robinfehr wants to merge 1 commit intomobxjs:masterfrom
robinfehr:feature/reflection
Closed

reflection#649
robinfehr wants to merge 1 commit intomobxjs:masterfrom
robinfehr:feature/reflection

Conversation

@robinfehr
Copy link
Copy Markdown
Contributor

No description provided.

processor(node.storedValue)
}

export interface IReflected {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe IModelReflectionData?

export function reflect(target: IStateTreeNode): IReflected {
// check all arguments
if (process.env.NODE_ENV !== "production") {
if (!isStateTreeNode(target))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also check if it is a model type specifically? (not array or map)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently it also works with a map - that's also why the subtype

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, you made that work as well :)

fail("expected first argument to be a mobx-state-tree node, got " + target + " instead")
}
const node: any = getStateTreeNode(target)
const type = node.type.subType || node.type
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remind me: why is the subType needed here :)?

properties: type.properties,
actions: Object.keys(node.type.actions || {}),
volatile: Object.keys(node.type.volatile || {}),
views: Object.keys(node.type.views || {})
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the views, should we somehow make clear whether a view is a function or a property? Or separately expose as viewProperties and viewFunctions? (implementation wise you could check whether the property descriptor has get )

if (!isPlainObject(actions))
fail(`actions initializer should return a plain object containing actions`)

if (node.type) addReadOnlyProp(node.type, "actions", actions)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 questions about this approach

  1. potentially several instances could expose different actions (I mean you could return actions conditionally). However I don't think that matters much, as that would be bad practice anyway
  2. I think this will break for multiple chained actions calls? Or no, probably, it doesn't because each time a new type is produced 🤔 . Let's make sure that is verified by some test.

Copy link
Copy Markdown
Contributor Author

@robinfehr robinfehr Feb 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's verify both 👍

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you make sure that the fields like actions are predeclared on ComplexType? (initialized as utils.EMPTY_ARRAY)

Copy link
Copy Markdown
Contributor Author

@robinfehr robinfehr Feb 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might want to change the name to indicate that it is not a reflection of the type a bit more and make it easier to guess what it does e.g. getMembers(node)

might be easier to understand the eventual sugar around it too

e.g.

getMembers(node, !!publicOnly)
getPrivateMembers(node) // if such ever would be introduced
getActions(node)
...

}))

test("reflection model", t => {
const node = Model.create()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a test that model({ x: types.string} and then assert reflect(type).properties.x === types.string?

@mweststrate
Copy link
Copy Markdown
Member

Great stuff @robinfehr! I left a bunch of comments & questions, but overal looking great :)

@robinfehr
Copy link
Copy Markdown
Contributor Author

robinfehr commented Feb 21, 2018

@mweststrate I rewrote that so it's all on the node since with how we currently initialise the members (on the node creation) it's cleaner like that. would be glad if you could review that again.

  • support for conditional member returns added
  • chaining members works

@mweststrate
Copy link
Copy Markdown
Member

Hey @robinfehr, thanks! I like that the reflection is now correct. The risk however is that we make creating object nodes even more expensive (which is already problem). So I played with making the whole reflection api lazy, so that the pain is postponed until somebody actually needs the reflection. The reflection itself is more expensive now (one might want to cache it), but it won't slow down object construction.

What do you think? 3184f26

@robinfehr
Copy link
Copy Markdown
Contributor Author

@mweststrate looking good. cool idea to check for isComputed etc.

@mweststrate
Copy link
Copy Markdown
Member

Merged!

@mweststrate mweststrate closed this Mar 7, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants