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

feat(rules): prefer-valid-title (#273) #433

Merged
merged 1 commit into from Oct 22, 2019

Conversation

suganya-sangith
Copy link
Contributor

As part of this, added a valid-title rule which checks for accidental space and duplicate prefix

@G-Rath Kindly review the PR and let me know if there are any changes

@suganya-sangith suganya-sangith changed the title feat(rules): prefer-hooks-on-top (#273) feat(rules): prefer-valid-title (#273) Oct 17, 2019
Copy link
Collaborator

@G-Rath G-Rath left a comment

Choose a reason for hiding this comment

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

Looking good! Thanks a ton for this - I've been after this for a while, but not gotten the time to tackle it myself 😄

I've done an initial review, and so far it's all looking pretty good - I've left a few changes, but will do a second review once I'm home from work.

src/rules/utils.ts Outdated Show resolved Hide resolved
src/rules/utils.ts Outdated Show resolved Hide resolved
src/rules/valid-title.ts Outdated Show resolved Hide resolved
@suganya-sangith
Copy link
Contributor Author

@G-Rath Thanks for taking time to review it, will work on the suggested changes 👍

@suganya-sangith suganya-sangith force-pushed the valid-title-rule-273 branch 2 times, most recently from 83e4754 to 83fee7d Compare October 18, 2019 00:52
@suganya-sangith
Copy link
Contributor Author

@G-Rath Made all the changes, expect getAccessorValue for which I could not find an alternate function to get the title.

Copy link
Collaborator

@G-Rath G-Rath left a comment

Choose a reason for hiding this comment

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

Looking good!

I've left a few change requests around, but nothing major - I did a look over the codebase, and found some places where we can definitely break out a utility method.

I'll look to do that once this PR is merged :)

src/rules/valid-title.ts Outdated Show resolved Hide resolved
src/rules/valid-title.ts Outdated Show resolved Hide resolved
return null;
}

return getAccessorValue(argument);
Copy link
Collaborator

@G-Rath G-Rath Oct 18, 2019

Choose a reason for hiding this comment

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

This should be getStringValue rather than getAccessorValue.

A StringNode is a union type of either StringLiteral or TemplateLiteral, where as an AccessorNode is either a StringNode OR a KnownIdentifier.

AccessorNodes represent nodes that are accessing a property of an object, which isn't what you want in this case :)


This is totally on me btw: I checked the code base, and I've used getAccessorValue in a few places where I should have used getStringValue 😬

I'm happy if you want to leave this one, and I can look to clean it up when I do my refactor later this weekend :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the explanation 👍 Will spend time to understand the types available 😁

Copy link
Collaborator

@G-Rath G-Rath Oct 18, 2019

Choose a reason for hiding this comment

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

No problem - I wrote all of the types and guards, and still get confused.

It's actually why I wrote them so grainaulay: The nature of AST parsing means it's best to not try and do fancy things, and instead layer everything to build on the previous type.

As such, the types are something like:

A StringLiteral is a Literal whose value is of type String (i.e 'hello world').
A TemplateLiteral is a Template Literal, that has only one quasis (i.e `hello world`)

  • quasis is a property on TemplateLiterals, that is an array of TemplateElements.
    • No idea why it's quasis - it's called that in the spec, but I can't find a definition of the word.
  • In theory this should mean only "simple" template literals that don't have any expressions, as a TemplateElement sort of represents the "stringy" bits of a template literal i.e `hello ${world}` has 2 TemplateElements, the first being hello ${ (w/ a value of hello ) and the second being } (w/ a value of '').
  • In practice, this does work, but I think it might be better to check the length of expression, to see if it's 0
    • I know no-identical-title checks both isStringNode & the expression length if it's a template, and fails if I remove the expression length check, which iirc means isStringNode isn't doing its job right.

A StringNode is a node that's either a StringLiteral OR a TemplateLiteral.


That ends the "string" side of nodes. You then have Identifiers, which are pretty much what they say on the tin: they're something that "identifies" as something - best way to think of them is as plaintext "names" or "words" - anything else is another expression, i.e [] is an ArrayExpression.

Identifiers are what you use to access properties, methods, fields, etc via dot notation. They're also how variables are used.

A KnownIdentifier is an Identifier whose name we "known"

  • This is actually a bit of a cheeky one - when we say "known", the "least known" Identifier has a name of type string; that's it. Which the case for all Identifiers anyway, and is the default. The name was more about reducing confusion between our generically typed Identifier and TSESTree.Identifier, of which ours extends.

An AccessorNode is then either a StringNode OR a KnownIdentifier.

The whole backstory behind AccessorNode is that you can access things in two ways in JS: Dot notation, and Bracket notation.

Dot accessors are Identifiers - nice and easy. Bracket accessors however are done using "a string" in square brackets; so they're StringNodes (b/c they could be string literals or template expressions - they can also be Identifiers themselves, b/c variables but we don't support that b/c we're not trying to be TS 😉).

As such, we have isSupportedAccessor, which guards on if a node is an AccessorNode that we "support" - which simply means we have an implementation for resolving the value of the node, which can be done via getAccessorValue, which acts like a normaliser for getting of the node you're working w/.


And there you go, that's pretty much it in a nutshell 😄

While on the surface it can look very complex, it's actually pretty simple to the point of being elegant (IMO at least 😉) - it's done as just a composition chain, which means you just have to follow the type chain down each step to get an idea of what the previous step is made up of.

In saying that, once you throw the actual AST tree into the mix, it's very easy to get confused & mentally tongue tied. The above is covering only the property accessor side; theres also the expect/modifier/matcher utils, which are also hopefully as elegant, but still their own kettle of fish.

Finally, I'm meant to be writing a whole new set of parsers/guards for the jest globals (describe, test, it, etc), but that's slow going for now (plus what we have is working, so it's less needed).


This is pretty much the best write up I've done on this so far, and something I've been meaning to do for a while. Cheers!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wow, that's so much of information, Thank you very much for taking time to write this up 😊

Copy link
Collaborator

@G-Rath G-Rath Oct 22, 2019

Choose a reason for hiding this comment

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

No problem! I've tried to write this up a few times before, but didn't get very far, so when I started writing this comment I just let it snowball so that as much info as possible is on paper 😂

Copy link
Collaborator

@G-Rath G-Rath left a comment

Choose a reason for hiding this comment

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

LGTM 👍

So glad we're going to have this!

I'll probably chuck it into the recommended rules at some point, unless @SimenB or @jeysal have any objections?
I can't think why you'd recommend having tests that are test('test something', ... or it(' should not throw', ....

@suganya-sangith Thanks again! If you don't mind me meddling so soon after merging, I'll probably look to expand this rule over this weekend, as it's opened the way to resolve some issues that've been open for a while, as well as give the code base a good clean :D

@jeysal
Copy link
Member

jeysal commented Oct 19, 2019

Yeah seems like a recommended candidate for next major version to me as well

@G-Rath G-Rath merged commit 1b2d24b into jest-community:master Oct 22, 2019
@SimenB
Copy link
Member

SimenB commented Oct 22, 2019

🎉 This PR is included in version 22.20.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@@ -0,0 +1,65 @@
# Disallow duplicate setup and teardown hooks (no-duplicate-hooks)
Copy link
Contributor

Choose a reason for hiding this comment

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

This title seems to be invalid. 😊 (probably copy-paste mistake)

Copy link
Contributor

Choose a reason for hiding this comment

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

Addressed here: #434 🎉

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mrtnzlml Thanks for catching it. I have used the template from other read me to maintain the consistency, but missed to change the title 😬

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants