Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork2.8k
feat: add support for decorator metadata in scope analysis and in consistent-type-imports#2751
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
Thanks for the PR,@Frezc! typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community. The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately. Thanks again! 🙏Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently onhttps://opencollective.com/typescript-eslint. As a thank you, your profile/company logo will be added to our main README which receives thousands of unique visitorsper day. |
codecovbot commentedNov 10, 2020 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Codecov Report
@@ Coverage Diff @@## master #2751 +/- ##==========================================- Coverage 92.76% 92.68% -0.08%========================================== Files 310 312 +2 Lines 10393 10584 +191 Branches 2943 3004 +61 ==========================================+ Hits 9641 9810 +169- Misses 347 353 +6- Partials 405 421 +16
Flags with carried forward coverage won't be shown.Click here to find out more.
|
bradzacher left a comment• edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
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.
Thanks for looking into this!
Quick eyeball of the code - a few comments:
requiring type information in the rule is a breaking change.
We should not be making this change as it hugely limits the usability of the rule.
This is the wrong approach to fix this - this should be fixed in the scope analyser - not in the rule.
Fixing this in the scope analyser would benefitall consumers of scope information, and not just this specific rule.
I set
emm.. I have no idea what is scope analyser. Can you give me a brief explanation? |
Thescope analyser is the tooling which runs over the AST and figures out what's a variable and where it is used. Right now it doesn't understand that the decorators can consume values when So when it analyses constructor(privatereadonlyconfig:ConfigService,privatereadonlyusersService:UsersService,privatereadonlylogger:Logger,privatereadonlyauthService:AuthService, @InjectRepository(UserSessionRepository)privatereadonlyuserSessionRepository:UserSessionRepository,) It doesn't understand that Because it doesn't understand this - it just creates a type-only reference to Fix the source of the data (the scope analyser) and the rule will "just work". |
bradzacher left a comment• edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
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.
Definitely heading in the right direction!
This is looking great so far!
Instead of intermingling all of this logic withReferencer
, I think we should separate it out into its ownClassVisitor
- similar to how we currently haveTypeVisitor
andPatternVisitor
.
Classes are a pretty strict set of things, so we can more easily isolate the logic and setup the appropriate state there.
I mention this as there is one case that you haven't yet handled with your implementation code:
importThingfrom'thing';@decoratorclassFoo{constructor(arg:Thing,){}}
In this example, the decorator on the class with a constructor creates a similar reference to that of a decorated method.
Handling this case will involve another piece of local state and things could get messy at that point, because you can nest class declarations within methods:
@decoratorclassBar{constructor(arg:React.Component,){ @decoratorclassFoo{constructor(arg:React.Component,){}}}}
So being able to doClassVisitor.visit(clazz)
will be much nicer as we can construct one ClassVisitor per class and thus isolate the state entirely.
It's also worth noting that decorators are only ever valid for class declarations - so we could do some cleaner separation of logic to ignore bad cases:
@decoratorclassFoo{constructor(arg:React.Component,){}}@decorator// this is invalid (TS semantic error)constclassExpr=class{ @decorator// this is invalid (TS semantic error)method( @decorator// this is invalid (TS semantic error)arg:React.Component,){}}constobj={ @decorator// this is invalid (syntax error)method( @decorator// this is invalid (TS semantic error)arg:React.Component,){}}
One other case I don't see tested, is this:
classFoo{method( @decoratorarg1:Thing1,arg2:Thing2,){}}
In this instance - TS will emit metadata aboutbothThing1
andThing2
, even though onlyarg1
is decorated.
All of the cases that I found TS to emit metadata are listed in my comment here:#2559 (comment)
I missed this, thanks for hint. |
bradzacher commentedDec 15, 2020 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
One thing I didn't mention - please add some snapshot tests! Your tests so far are great as they are explicit assertions of how it works, but as you've probably found out they're super cumbersome to write. A snapshot test is less strict/safe as you have to manually eyeball the output, but they're nice because they're so easy to write. It means you can create isolated cases for each case and have a granular regression test. They're also nice because they create a visual representation of the scope, which I found invaluable in figuring out how it all works. You can add the new scope manager optionhere And then add this to the top of your fixture to turn on the option (example). ////@emitDecoratorMetadata = trueclassFixture{...} |
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.
Almost there! The code's looking good I think.
could you also add some snapshots for the nested class cases:
functiondeco(...param:any){}@decoclassA{constructor(foo:b.Foo){classB{constructor(bar:c.Foo){}}}}
functiondeco(...param:any){}classA{constructor(foo:b.Foo){ @decoclassB{constructor(bar:c.Foo){}}}}
functiondeco(...param:any){}@decoclassA{constructor(foo:b.Foo){ @decoclassB{constructor(bar:c.Foo){}}}}
They should all work fine - but a few extra snapshots to prevent regressions would be ace.
Thanks for sticking with this! We're almost there!
packages/scope-manager/tests/fixtures/class/declaration/emit-metadata.ts OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
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.
LGTM - thanks heaps for all of your work here and following this through to the end.
You've done a great job!
packages/scope-manager/tests/fixtures/class/emit-metadata/method-deco.ts.shotShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
packages/scope-manager/tests/fixtures/class/emit-metadata/nested-class-both.ts.shotShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
Reference$9 { | ||
identifier: Identifier<"T">, | ||
isRead: true, | ||
isTypeReference: true, | ||
isValueReference: false, | ||
isWrite: false, | ||
resolved: Variable$5, | ||
}, |
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.
From the looks of it - this one is wrong.
This reference is for the pair:
set[keyName](a:T){} @decoget[keyName](){}
TS will emitthe following code:
__decorate([deco,__metadata("design:type",T),__metadata("design:paramtypes",[])],A.prototype,_a,null);
So whilst it hasn't referenced the param type - it did reference the return type.
I don't think it's worth spending any time fixing this - it's a super rare usecase. Also it'll be a pretty hard case to reliably fix I think.
I'm 100% okay with just marking this as a KP and only looking at fixing it if someone runs into the issue.
packages/scope-manager/tests/fixtures/class/emit-metadata/accessor-deco.ts.shotShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
packages/scope-manager/tests/fixtures/class/emit-metadata/nested-class-inner.ts.shotShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
packages/scope-manager/tests/fixtures/class/emit-metadata/nested-class-outer.ts.shotShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
packages/scope-manager/tests/fixtures/class/emit-metadata/parameters-deco.ts.shotShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
packages/scope-manager/tests/fixtures/class/emit-metadata/parameters-deco.ts.shotShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
packages/scope-manager/tests/fixtures/class/emit-metadata/property-deco.ts.shotShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
miluoshi commentedJan 19, 2021 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I think this change broke After updating
|
And as linked above, this was fixed in#2943 |
pmstss commentedJan 28, 2021
bradzacher commentedJan 28, 2021 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Don't comment on old, closed PRs. The comments are not easily discoverable by other users, and PRs do not show up in the "issues" tab - further hiding them from other users. There is a pinned issue to follow, which is easily discoverable by using theissue search for |
Fixes#2559
Changes: