Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fix(eslint-plugin): [no-unnecessary-template-expression] add missing parentheses in autofix#8673

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

Conversation

developer-bandi
Copy link
Contributor

PR Checklist

Overview

Fix no consider precedence when fixer function is excution using util function.

@typescript-eslint
Copy link
Contributor

Thanks for the PR,@developer-bandi!

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.

@netlifyNetlify
Copy link

netlifybot commentedMar 14, 2024
edited
Loading

Deploy Preview fortypescript-eslint ready!

NameLink
🔨 Latest commit1d536b6
🔍 Latest deploy loghttps://app.netlify.com/sites/typescript-eslint/deploys/66c3789a07a1300008113bce
😎 Deploy Previewhttps://deploy-preview-8673--typescript-eslint.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 99 (🔴 down 1 from production)
Accessibility: 100 (no change from production)
Best Practices: 92 (no change from production)
SEO: 90 (no change from production)
PWA: 80 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to yourNetlify site configuration.

@nx-cloudNx Cloud
Copy link

nx-cloudbot commentedMar 14, 2024
edited
Loading

☁️ Nx Cloud Report

CI is running/has finished running commands for commit1d536b6. As they complete they will appear below. Click to see the status, the terminal output, and the build insights.

📂 See all runs for this CI Pipeline Execution


✅ Successfully ran 2 targets

Sent with 💌 fromNxCloud.

@codecovCodecov
Copy link

codecovbot commentedMar 14, 2024
edited
Loading

Codecov Report

Attention: Patch coverage is84.61538% with2 lines in your changes missing coverage. Please review.

Project coverage is 88.01%. Comparing base(05d1ddb) to head(1d536b6).
Report is 2 commits behind head on main.

FilesPatch %Lines
...ackages/eslint-plugin/src/util/getWrappingFixer.ts81.81%2 Missing⚠️
Additional details and impacted files
@@            Coverage Diff             @@##             main    #8673      +/-   ##==========================================- Coverage   88.02%   88.01%   -0.01%==========================================  Files         406      406                Lines       13871    13881      +10       Branches     4053     4056       +3     ==========================================+ Hits        12210    12218       +8- Misses       1352     1354       +2  Partials      309      309
FlagCoverage Δ
unittest88.01% <84.61%> (-0.01%)⬇️

Flags with carried forward coverage won't be shown.Click here to find out more.

FilesCoverage Δ
...in/src/rules/no-unnecessary-template-expression.ts100.00% <100.00%> (ø)
...ackages/eslint-plugin/src/util/getWrappingFixer.ts93.42% <81.81%> (-2.04%)⬇️

Copy link
Member

@JoshuaKGoldbergJoshuaKGoldberg left a comment

Choose a reason for hiding this comment

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

I like the approach here of usinggetWrappingFixer! 👏

I also think the code can be refactored a bit to remove the extra layer of indirection & theas. Requesting changes on that please. :)

@JoshuaKGoldbergJoshuaKGoldberg added the awaiting responseIssues waiting for a reply from the OP or another party labelMar 25, 2024
@github-actionsgithub-actionsbot removed the awaiting responseIssues waiting for a reply from the OP or another party labelMar 30, 2024
@bradzacherbradzacher added the bugSomething isn't working labelApr 4, 2024
Comment on lines 22 to 28
const replaceResult = getWrappingFixer({
sourceCode: context.sourceCode,
node: node.expressions[0],
wrap: (...code: string[]) => {
return code.join('');
},
})(fixer);
Copy link
Member

Choose a reason for hiding this comment

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

[Refactor] Coming from#8673 (comment):

Instead of adding the overhead of the rest ofgetWrappingFixer(), suggestion: the specific text generation stuff should be extracted out and used here. Like, you could move the text generation from thegetWrappingFixer into a separate function, and use that separate helper here.

I think this means that we should extract codegen partfromgetWrappingFixer implementation to the separate utility function, not extract wholegetWrappingFixer call to the separate function. WDYT?

developer-bandi reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I think I misunderstood the explanation. thank you The code generation part that generates parentheses was separated and made into a function.

@JoshuaKGoldbergJoshuaKGoldberg added the awaiting responseIssues waiting for a reply from the OP or another party labelApr 8, 2024
@@ -207,7 +207,7 @@ ruleTester.run('no-useless-template-literals', rule, {

{
code: noFormat`\`\${ 'a' + 'b' }\`;`,
output: `'a' + 'b';`,
output: `('a' + 'b');`,

Choose a reason for hiding this comment

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

How come this test case gains parens? Is that just thegetWrappingFixer being overly cautions?

Choose a reason for hiding this comment

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

I also have this question. Feels like a bug to me?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

At first, I thought it would be good for the expression to be wrapped, but as you said, I think it's excessive and looks like a bug.

However, in order to restore the test code, the getWrappingFixer function must be modified. Would it be a good idea to modify this function?

export function getWrappingFixer(
params: WrappingFixerParams,
): TSESLint.ReportFixFunction {
export function getWrappingCode(params: WrappingFixerParams): string {

Choose a reason for hiding this comment

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

One thing worth noting is that this uses the parent node to infer whether parens are needed (seeif (isWeakPrecedenceParent(node))). So I'm wondering if that could give mistaken results for a scenario where we're reparenting code?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I understand that you are using the above node to infer whether parentheses are needed, but I don't understand this part (So I'm wondering if that could give mistaken results for a scenario where we're reparenting code?). Can you tell me in more detail what the scenario is for reparenting the code?

Choose a reason for hiding this comment

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

Sorry for taking a bit to get back to you - took me a while to figure out what I meant 😆 . Basically,getWrappingFixer() allows you to transform a node whose parent did not change.

// input<stuff before> nodeToBeModified <stuff after>// output<stuff before> modifiedNode <stuff after>

But,now that getWrappingCode has been extracted, it can be used instead like

// input<stuff before> nodeToBeModified <stuff after>// getWrappingCode outputmodifiedNode// used in fixer as<DIFFERENT stuff before> modifiedNode <DIFFERENT stuff after>

In fact, that's the whole reason that you've extracted it in this PR.

// inputcondition ?`${'left'||'right'}`.trim() :'lol';// getWrappingCodeOutput('left'||'right')// used in fixer ascondition ?('left'||'right').trim() :'lol';

So,getWrappingCode needs to deduce whether to wrap the expression in parentheses based on theNEW parent, not the existing one.

Used within thegetWrappingFixer those were the one and the same, so the lineif (isWeakPrecedenceParent(node)) was justified, butnow that getWrappingCode may be used indepdently, we'd need something likeif (isWeakPrecedenceNewParent(node, newParent)), in order for the function to give expected resultsin general.

I'd have to have a longer think to come up with test cases where this discrepancy would manifest, but hopefully this gets you started? If it's still unclear let me know and I can think up some test cases. The bottom line is that we need to be aware of whether parens are needed for thenew parent, not theexisting parent, in order forgetWrappingCode to be safe for general use outside ofgetWrappingFixer.

developer-bandi reacted with thumbs up emoji

Choose a reason for hiding this comment

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

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I apologize for not clear question. But the answers were the best!

If my understanding is correct, the parent that theisWeakPrecedenceNewParent function checks must be the new parent. In fact, the previous code was checking the parent of the expression, so it was always checking the templete literal node as the parent, so it was not getting normal results.

However, if i slightly modify the code to satisfy the above conditions, i will get the following results depending on the conditions of innerNode and parents condition.

// beforetrue ? `${'test' || ''}`.trim() : undefined;// aftertrue ? (('test' || '')).trim() : undefined;

In my opinion, it seems better to use parentheses when both the logic of applying parentheses to innerNode and the logic of examining the state of the parent are satisfied. so i revertgetWrappingFixer and make newgetWrappingCode function

I think we're just getting started, so i appreciate your feedback.

kirkwaiblinger reacted with thumbs up emoji
@JoshuaKGoldbergJoshuaKGoldberg added the awaiting responseIssues waiting for a reply from the OP or another party labelApr 23, 2024
@github-actionsgithub-actionsbot removed the awaiting responseIssues waiting for a reply from the OP or another party labelApr 28, 2024
export function getWrappingFixer(
params: WrappingFixerParams,
): TSESLint.ReportFixFunction {
export function getWrappingCode(params: WrappingFixerParams): string {

Choose a reason for hiding this comment

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

Sorry for taking a bit to get back to you - took me a while to figure out what I meant 😆 . Basically,getWrappingFixer() allows you to transform a node whose parent did not change.

// input<stuff before> nodeToBeModified <stuff after>// output<stuff before> modifiedNode <stuff after>

But,now that getWrappingCode has been extracted, it can be used instead like

// input<stuff before> nodeToBeModified <stuff after>// getWrappingCode outputmodifiedNode// used in fixer as<DIFFERENT stuff before> modifiedNode <DIFFERENT stuff after>

In fact, that's the whole reason that you've extracted it in this PR.

// inputcondition ?`${'left'||'right'}`.trim() :'lol';// getWrappingCodeOutput('left'||'right')// used in fixer ascondition ?('left'||'right').trim() :'lol';

So,getWrappingCode needs to deduce whether to wrap the expression in parentheses based on theNEW parent, not the existing one.

Used within thegetWrappingFixer those were the one and the same, so the lineif (isWeakPrecedenceParent(node)) was justified, butnow that getWrappingCode may be used indepdently, we'd need something likeif (isWeakPrecedenceNewParent(node, newParent)), in order for the function to give expected resultsin general.

I'd have to have a longer think to come up with test cases where this discrepancy would manifest, but hopefully this gets you started? If it's still unclear let me know and I can think up some test cases. The bottom line is that we need to be aware of whether parens are needed for thenew parent, not theexisting parent, in order forgetWrappingCode to be safe for general use outside ofgetWrappingFixer.

developer-bandi reacted with thumbs up emoji
@kirkwaiblingerkirkwaiblinger added the awaiting responseIssues waiting for a reply from the OP or another party labelMay 8, 2024
@github-actionsgithub-actionsbot removed the awaiting responseIssues waiting for a reply from the OP or another party labelMay 12, 2024
@kirkwaiblinger
Copy link
Member

kirkwaiblinger commentedJun 3, 2024
edited
Loading

FYI@developer-bandi - This will have a semantic merge conflict with#8821, which has now been merged. When this is ready to go, you'll want to duplicate the fix to theno-unnecessary-template-expression copy of the rule

Also, I'm sorry for taking so long to do another review pass. I'm setting an intention for myself to get another pass in this week. Please bug me if I don't get to it within that time!

developer-bandi reacted with thumbs up emoji

Copy link
Member

@kirkwaiblingerkirkwaiblinger left a comment

Choose a reason for hiding this comment

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

I spent a long time playing around with this on my machine.... this is adifficult area of the code. Requesting a few changes for clarity, but I think the essential logic is in place! 🙂

Also, would like to tag in another member of @typescript-eslint/triage-team to help make sure we're on the right track.

const parent = node.parent!;
function isWeakPrecedenceParent(
node: TSESTree.Node,
parent = node.parent,

Choose a reason for hiding this comment

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

Let's keep the parent deduced by thenode... so,

functionisWeakPrecedenceParent(node:TSESTree.Node):boolean{constparent=node.parent;if(!parent){returnfalse;}

developer-bandi reacted with thumbs up emoji
@@ -75,6 +75,23 @@ export function getWrappingFixer(
};
}

export function getWrappingCode(params: {

Choose a reason for hiding this comment

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

What do you think of reframing this function to look something like this?

/** * Useful jsdoc here */exportfunctiongetMovedNodeCode(params:{sourceCode:Readonly<TSESLint.SourceCode>;nodeToMove:TSESTree.Node;destinationNode:TSESTree.Node;}):string{const{ sourceCode,nodeToMove:existingNode, destinationNode}=params;constcode=sourceCode.getText(existingNode);if(isStrongPrecedenceNode(existingNode)){// Moved node never needs parensreturncode;}if(!isWeakPrecedenceParent(destinationNode)){// Destination would never needs parens, regardless what node moves therereturncode;}// Parens may be necessaryreturn`(${code})`;}

developer-bandi reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

It looks much more intuitive and good. We will reflect it appropriately

@kirkwaiblingerkirkwaiblinger requested a review froma teamJune 21, 2024 05:06
@kirkwaiblingerkirkwaiblinger added the awaiting responseIssues waiting for a reply from the OP or another party labelJun 21, 2024
Copy link
Member

@JoshuaKGoldbergJoshuaKGoldberg left a comment

Choose a reason for hiding this comment

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

I agree with@kirkwaiblinger 🙂

developer-bandi reacted with thumbs up emoji
Copy link
Member

@kirkwaiblingerkirkwaiblinger left a comment

Choose a reason for hiding this comment

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

teamwork

]),
];
fix(fixer): TSESLint.RuleFix | null {
const wrappingCode = getMovedNodeCode({

Choose a reason for hiding this comment

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

(nit) the namewrappingCode is slightly stale with the rename, but I don't have many good ideas for a better name 🙃. Any ideas?codeToReplaceTemplate? Up to you if you want to change this or leave it 🤷‍♂️

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Since the function name is getMovedNodeCode, how about changing the variable name to movedNodeCode? If you don't think it's appropriate, it might be a good idea to keep the current name.

kirkwaiblinger reacted with thumbs up emoji

Choose a reason for hiding this comment

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

Makes sense to me 👍

Copy link
Member

@kirkwaiblingerkirkwaiblinger left a comment
edited
Loading

Choose a reason for hiding this comment

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

Ah - reminder to duplicate these changes to theno-unnecessary-template-expressions copy of the rule. Otherwise I think I'm happy!

@kirkwaiblingerkirkwaiblinger changed the titlefix(eslint-plugin): [no-useless-template-literals] add parentheses consider precedencefix(eslint-plugin): [no-unnecessary-template-expression] add parentheses consider precedenceJul 14, 2024
@kirkwaiblingerkirkwaiblinger changed the titlefix(eslint-plugin): [no-unnecessary-template-expression] add parentheses consider precedencefix(eslint-plugin): [no-unnecessary-template-expression] add missing parentheses in autofixJul 14, 2024
@JoshuaKGoldberg
Copy link
Member

👋@developer-bandi just checking in, is this something you still have time and energy for?

@JoshuaKGoldbergJoshuaKGoldberg added the stalePRs or Issues that are at risk of being or have been closed due to inactivity for a prolonged period labelAug 12, 2024
@developer-bandi
Copy link
ContributorAuthor

@JoshuaKGoldberg I haven't been able to proceed with the work recently due to lack of time. �I plan to start working on it this weekend.

JoshuaKGoldberg reacted with thumbs up emojiJoshuaKGoldberg reacted with heart emoji

@github-actionsgithub-actionsbot removed the awaiting responseIssues waiting for a reply from the OP or another party labelAug 18, 2024
@developer-bandi
Copy link
ContributorAuthor

copy work to [no-unnecessary-template-expression] and delete no-useless-template-literals to resolve conflict

@JoshuaKGoldbergJoshuaKGoldberg removed the stalePRs or Issues that are at risk of being or have been closed due to inactivity for a prolonged period labelAug 19, 2024
Copy link
Member

@kirkwaiblingerkirkwaiblinger left a comment

Choose a reason for hiding this comment

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

ship it

@kirkwaiblingerkirkwaiblinger added the 1 approval>=1 team member has approved this PR; we're now leaving it open for more reviews before we merge labelAug 19, 2024
return code;
}

if (!isWeakPrecedenceParent(destinationNode)) {

Choose a reason for hiding this comment

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

[Praise] Great reuse of the existing functions!

Copy link
Member

@JoshuaKGoldbergJoshuaKGoldberg left a comment

Choose a reason for hiding this comment

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

Nice!!

@JoshuaKGoldbergJoshuaKGoldberg merged commit90655d1 intotypescript-eslint:mainAug 19, 2024
59 of 61 checks passed
@github-actionsgithub-actionsbot locked asresolvedand limited conversation to collaboratorsAug 27, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.
Reviewers

@JoshuaKGoldbergJoshuaKGoldbergJoshuaKGoldberg approved these changes

@kirkwaiblingerkirkwaiblingerkirkwaiblinger approved these changes

@auvredauvredAwaiting requested review from auvred

Assignees
No one assigned
Labels
1 approval>=1 team member has approved this PR; we're now leaving it open for more reviews before we mergebugSomething isn't working
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

Bug: [no-unnecessary-template-expression] Auto fix will change meaning of code
5 participants
@developer-bandi@kirkwaiblinger@JoshuaKGoldberg@auvred@bradzacher

[8]ページ先頭

©2009-2025 Movatter.jp