Skip to content
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

Destructuring in styled interpolation functions #403

Merged
merged 7 commits into from
Dec 15, 2020

Conversation

pgmanutd
Copy link
Contributor

This closes #397

font-size: ${(props) => props.textSize}px;
background-color: ${(props) => {
return props.bgColor;
}};
border: 5px ${(props) => props.borderStyle} black;
border: 5px ${({ borderStyle }) => borderStyle} black;
Copy link
Collaborator

@itsdouges itsdouges Dec 11, 2020

Choose a reason for hiding this comment

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

can we add these tests as well please 😄

({ borderStyle: bs }) => bs
propz => propz.borderStyle

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure sure

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks little bit tricky. Damn. We have hardcoded props check as of now. propz is now dynamic 😅

Copy link
Collaborator

@itsdouges itsdouges Dec 12, 2020

Choose a reason for hiding this comment

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

yeah 😅

make it work, make it right, make it fast? hehe

if its a lot of effort to allow props to be dynamically named e.g. propz we can leave it for now. we can potentially force it to be called props and just rename any member expressions to props? clever workarounds.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Was lil bit tricky. Damn! Finally 😅

@pgmanutd pgmanutd force-pushed the destructuring-in-styled-interpolation-functions branch from a3add01 to 1a727b9 Compare December 14, 2020 15:30
* 1. `propz.loading` in `border-color: \${(propz) => (propz.loading ? colors.N100 : colors.N200)};`
* Outcome: It will replace `propz.loading` with `props.loading`.
*
* 2. `prop.notValidProp` in `border-color: \${(props) => (props.notValidProp ? colors.N100 : colors.N200)};`
Copy link
Collaborator

@itsdouges itsdouges Dec 14, 2020

Choose a reason for hiding this comment

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

what is the edge case here? that the arg is props but we're using prop?

in this case should we just do nothing? could we delete some of this code and get away with it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oops..it should be props.notValidProp. Sorry 😅

expect(actual).toIncludeMultiple([
'{as:C="span",style,isLoading,loading,...props}',
'isLoading?colors.N20:colors.N40',
'loading?colors.N50:colors.N10',
Copy link
Collaborator

Choose a reason for hiding this comment

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

hmm i think this is smart (instead of using l you use loading) - because it gets around the potential of naming collisions

can we have one test that asserts that so the knowledge is passed onto the next developer?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🎉 yups sure

@@ -145,6 +145,109 @@ const traverseStyledBinaryExpression = (node: t.BinaryExpression, nestedVisitor:
return node;
};

/**
* Handles cases like:
* 1. `propz.loading` in `border-color: \${(propz) => (propz.loading ? colors.N100 : colors.N200)};`
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: could we handle this in an enter() visitor instead? so the logic of "rename propz to props" only needs to function once - instead of needing to traverse up the parent

🤔 thinking about it i see we check for arrow function or binary expression on L273/L277. perhaps this is fine?

Copy link
Contributor Author

@pgmanutd pgmanutd Dec 15, 2020

Choose a reason for hiding this comment

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

So we are already traversing down. Here we are making sure propz is coming from function params. We picked member expression property, traversed to make sure it is coming from function params, and renamed it. Earlier we hardcoded the check to props.

* @param path MemberExpression path
* @param propsToDestructure Array which gets mutated with props which are not valid eg. props.notValidProp
*/
const handleMemberExpressionInStyledInterpolations = (
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit:

-handleMemberExpressionInStyledInterpolations
+handleMemberExpressionInStyledInterpolation

* @param path Identifier path
* @param propsToDestructure Array which gets mutated with props which extracted from destructuring
*/
const handleDestructuringInStyledInterpolations = (
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit:

-handleDestructuringInStyledInterpolations
+handleDestructuringInStyledInterpolation

const traversedUpFunctionPath = path.find((parentPath) => parentPath.isFunction());
const memberExpressionKeyName = memberExpressionKey.name;

const isMemberExpressionKeyNameEqualsFunctionParams =
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: isMemberExpressionNameTheSameAsFunctionFirstParam?

return;
}

if (!propsToDestructure.includes(memberExpressionValueName)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

can we add some comments here explaining what we're doing

(if valid html attribute let it through - else destructure to prevent)


if (isPropValid(memberExpressionValueName)) {
// Convert cases like propz.color to props.color
if (memberExpressionKeyName !== 'props') {
Copy link
Collaborator

Choose a reason for hiding this comment

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

can we move 'props' to module scope and reuse it? or move to constants.tsx? 🤔

path: NodePath<t.Identifier>,
propsToDestructure: string[]
) => {
// We are not interested in parent object property like `({ loading: l }) => l`
Copy link
Collaborator

@itsdouges itsdouges Dec 14, 2020

Choose a reason for hiding this comment

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

is this comment wrong? im not following unfortunately. more context?

Copy link
Contributor Author

@pgmanutd pgmanutd Dec 15, 2020

Choose a reason for hiding this comment

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

So in this statement, ({ loading: l }) => l when we are checking for Identifier, both : l and => l are identifiers and function is parent for both. We are not interested in modifying : l. We just need to modify => l to => loading. If we don't skip, => l will not be modified because we have modified : l earlier and second identifier is nowhere to be found inside function params.
Hope this makes sense 😅

Copy link
Collaborator

Choose a reason for hiding this comment

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

ahhh 🤔

so why don't we add loading to props to de-structure here?

alternatively now that i think about it - should we be adding destructured props anyway? currently the behaviour should be

  1. am i a valid HTML element? you will be passed down to the raw HTML element
  2. am i not valid? you will be destructured

do we need to rework anything to support this behaviour? 🤔

*/
const handleDestructuringInStyledInterpolations = (
path: NodePath<t.Identifier>,
propsToDestructure: string[]
Copy link
Collaborator

Choose a reason for hiding this comment

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

instead of leaking props to destructure can we instead return any identifiers we've found that we want to destructure?

*/
const handleMemberExpressionInStyledInterpolations = (
path: NodePath<t.MemberExpression>,
propsToDestructure: string[]
Copy link
Collaborator

Choose a reason for hiding this comment

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

instead of leaking props to destructure can we instead return any identifiers we've found that we want to destructure?

}: {
name: string;
node: t.Expression | undefined;
resolveFor?: 'key' | 'value';
Copy link
Collaborator

Choose a reason for hiding this comment

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

what if we just returned both?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yups we can 😃

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another thought. Here we are traversing until we hit dead end. We either need to search for key or value. I mean where we will break the recursion. When either key is found or value is found?

Copy link
Collaborator

Choose a reason for hiding this comment

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

no worries then :)

Copy link
Collaborator

@itsdouges itsdouges left a comment

Choose a reason for hiding this comment

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

hey! left some comments have a look :)

looking pretty great! biggest thoughts are:

  1. reworking the need to pass through propsToDestructure, and
  2. seeing if we can do something about needing to traverse back up the AST to find the parent function

for 2) its more of a thought than anything, if it makes the code shittier then let's not bother

:fingerguns:

@pgmanutd
Copy link
Contributor Author

pgmanutd commented Dec 15, 2020

hey! left some comments have a look :)

looking pretty great! biggest thoughts are:

  1. reworking the need to pass through propsToDestructure, and
  2. seeing if we can do something about needing to traverse back up the AST to find the parent function

for 2) its more of a thought than anything, if it makes the code shittier then let's not bother

:fingerguns:

First is fine. Second one hmm 🤔. Problem is how we can find where it is coming from. Looks like scope won't work because parent for loading ? color1: color2 will be ConditionalExpression and not the function. We need destructuring key in cases like { loading: l }.

@pgmanutd pgmanutd force-pushed the destructuring-in-styled-interpolation-functions branch from 1a727b9 to ebaca9a Compare December 15, 2020 05:50
Copy link
Collaborator

@itsdouges itsdouges left a comment

Choose a reason for hiding this comment

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

lgtm

@pgmanutd pgmanutd merged commit 492aee7 into master Dec 15, 2020
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.

Destructuring in styled interpolation functions aren't handled
2 participants