-
Notifications
You must be signed in to change notification settings - Fork 61
Fix reported line numbers #140
Fix reported line numbers #140
Conversation
Changes Unknown when pulling 0760875 on chinesedfan:fix_lineno into ** on styled-components:master**. |
At a glance it looks pretty cool, I'll have to take a bit more time later to look into the code more thoroughly though, but for one, since you say it passes #129 what about we just copy paste that test case into this PR then? :). The more tests the better! |
@emilgoldsmith I just added some unit tests in this PR, but tested locally with #129. My idea is that merging this PR first, and #129 later. After all, #129 belongs to another author. Waiting for your review feedbacks. :) |
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.
Hey! Thanks again for your contributions, when you find the time if you could just get back to me on my concerns, if I'm wrong about anything please have patience with me :)
@@ -74,7 +74,7 @@ const processStyledComponentsFile = (ast, absolutePath, options) => { | |||
extractedCSS.push(stylelintCommentsAdded) | |||
sourceMap = Object.assign( | |||
sourceMap, | |||
getSourceMap(extractedCSS.join('\n'), wrappedContent, processedNode.loc.start.line) | |||
getSourceMap(extractedCSS.join('\n'), wrappedContent, processedNode.quasi.loc.start.line) |
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.
Nice!
src/utils/tagged-template-literal.js
Outdated
@@ -141,6 +141,17 @@ const interleave = (quasis, expressions, absolutePath) => { | |||
*/ | |||
substitute = '$dummyValue' | |||
} | |||
// Make sure substituted by same count of lines | |||
const intentCount = prevText.split('\n').pop().length |
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.
By intent you mean indent right? That confused me for so long, can we please change that?
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.
And on another note, I'm pretty sure you have some indentation edge cases here with examples such as:
styled.div`
color: ${colorVariable}
`
right? Your length here would include all the color:
part
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.
And of course adding a test for this as you fix it would also be great!
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.
Yes, it's a typo. intent
should be indent
.
src/utils/tagged-template-literal.js
Outdated
@@ -141,6 +141,17 @@ const interleave = (quasis, expressions, absolutePath) => { | |||
*/ | |||
substitute = '$dummyValue' | |||
} | |||
// Make sure substituted by same count of lines | |||
const intentCount = prevText.split('\n').pop().length | |||
const intent = new Array(intentCount).fill(' ').join('') |
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.
Hmm, I think we might also be making similar mistakes like this other places in the code (I don't quite remember if we handle it perfectly everywhere, such as in our indentation fixers) but would this break some indentation Stylelint rules if someone was using tabs? Adding a test that tests that would definitely be great whether this is a breaking test or not :)
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 very much for correcting me! A better way may be selecting all left spaces from the last line, i.e. prevText.split('\n').pop().replace(/^(\s*).*$/, '$1')
.
src/utils/tagged-template-literal.js
Outdated
const intent = new Array(intentCount).fill(' ').join('') | ||
const targetLines = quasis[i + 1].loc.start.line - quasis[i].loc.end.line + 1 | ||
let currentLines = substitute.split('\n').length | ||
while (currentLines < targetLines) { |
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.
Okay, so just to make sure I understand what you're doing here, you're just making sure that we substitute the correct amount of lines in so we don't have propagating line errors further down, yes? As in, we make sure that the length of our processed CSS is the same as the length of their actual TTL (Tagged Template Literal). Right?
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.
Right. But it's a little hard to keep line counts without introducing new styling errors. How about padding lines by /* stylelint-disable-line */
?
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.
Hey, that's quite a good idea. I like it. It would make the logic so much easier, just add x empty lines that only say /* stylelint-disable-line */
and we'll be golden, right?
Make sure there aren't any edge cases with the indentation rules / empty lines before blocks etc. that are introduced as I'm not sure exactly how stylelint works with the indentation rules, but yeah I like that idea, the simpler the better!
@emilgoldsmith Sorry for my late responses. I am busy these days, so I leave some comments to you first. This feature is really important and I think I will implement it finally. :) |
Yes it is :) |
@emilgoldsmith |
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 getting back to us @chinesedfan! And interesting new approach, at first I was a bit skeptical about the modifying of the stylelintResult object, but now that I looked at it thoroughly I think this could actually be made to work quite well. Just a few comments here and there where I think the main one is making sure that we're handling updating the errored
key on the stylelintResult object properly
src/index.js
Outdated
.filter( | ||
warning => | ||
// Filter indentation warnings generated by interpolations substitution | ||
warning.rule !== 'indentation' || |
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.
I think this would be a lot more readable if you wrote it in the negative way, so the focus is on when we filter it out:
!(warning.rule === 'indentation' &&
interpolationLines.indexOf(lineCorrection[warning.line]) >= 0)
src/index.js
Outdated
return Object.assign({}, stylelintResult, { warnings }) | ||
return Object.assign({}, stylelintResult, { | ||
warnings, | ||
// Remember to fix |
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.
Is this a note to yourself to remember something, or is it an explanatory comment? If it's an explanatory comment maybe make it a bit more verbose, such as // Undo errored if all warnings were caused by interpolation substitutions
src/parsers/index.js
Outdated
// Save interpolation lines | ||
node.quasi.expressions.forEach((expression, i) => { | ||
let l = node.quasi.quasis[i].loc.end.line + 1 | ||
while (l <= node.quasi.quasis[i + 1].loc.start.line) { |
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.
Doesn't this throw an error when i === node.quasi.expressions.length - 1
??
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.
No, quasis.length
should be always greater 1 than expressions.length
. I learned from similar codes here.
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.
Ahh yes, you're iterating over expressions not quasis. Makes sense, my bad!
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.
It'd be an okay idea to add a comment about that, not super urgent, as it's not that unclear, but no harm in documenting code well!
@@ -146,6 +146,14 @@ const interleave = (quasis, expressions, absolutePath) => { | |||
*/ | |||
substitute = '$dummyValue' | |||
} | |||
// Make sure substituted by same count of lines |
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.
This looks good
src/index.js
Outdated
return Object.assign({}, stylelintResult, { | ||
warnings, | ||
// Remember to fix | ||
errored: warnings.length ? true : undefined |
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.
This modifying of the stylelintResult definitely makes me a bit nervous in general, but I think your filter is mostly pretty contained so I think I can be okay with it, we need to be really accurate though. Are you sure that this behaviour you wrote here conforms with how Stylelint does it exactly? The only documentation I can find that's the most reliable is these two: https://stylelint.io/user-guide/node-api/ https://stylelint.io/developer-guide/processors/ and this code https://github.com/stylelint/stylelint/blob/master/lib/createStylelintResult.js which may or may not be the object we're passed as I didn't dig deeper into it.
Could you please dig into it deeper and come back with a bit of "proof of correctness" as I could imagine that we may need to check if the rules have severity: 'error'
or something like that, though the thing is I'm not sure so just want to make sure we don't screw something up here
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.
This really makes me unhappy here. I found that errored
can be undefined/null/true
. See stylelint#createStylelintResult.js.
It is hard to recover errored
unless authors of stylelint
can give us a reasonable explanation in stylelint#3041.
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.
Hmm yes that does seem pretty messy indeed, let's wait a bit and see if you get a reply there, but one thing that I can definitely see from your research (this part in particular) is that we need to be doing a check here whether any of the warnings have severity level "error", but yeah, maybe we also need to check the null and other stuff.
One way would also be to check whether the errored
flag is currently set, if it is not we know we don't have to change anything (as we're only removing errors in our modifications so it would never cause an error to show up, only to be removed), if it is set to true though, then check if any of the remaining warnings have severity level "error", and if they don't change errored
to undefined
I guess right? It should be undefined
not false
according to your research yeah?
I think this would handle the case where it's null etc. as well, what do you think?
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.
Right, I should check severity levels. Good news is that ignored files will not invoke our processor, so we can do not consider the null
case.
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.
Nice :).
Yeah so I think the method I proposed above should work yeah? Don't do anything if it's falsy, if it is truthy check if any warnings with severity level error, and if there aren't any change it to undefined
.
src/parsers/index.js
Outdated
) | ||
// Save interpolation lines | ||
node.quasi.expressions.forEach((expression, i) => { | ||
let l = node.quasi.quasis[i].loc.end.line + 1 |
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.
I was actually just about to comment that maybe we should not include the first line, but that's actually also what you're doing here right? The +1
is excluding the line where the interpolation starts yeah? So if I for example did a single line interpolation ${someVariable}
I would still be checked for indentation errors yeah? If so all good and good on you for considering it as well
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.
Right, the indentation warning caused by the first line of the interpolations will not be filtered. Because indentations are wrote by users themselves, instead of generated by dummy comments padding.
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.
Yep, I agree that's exactly the behaviour we would want.
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.
I am thinking about renaming interpolationLinesMap
as another name. How about dummyCommentsMap
or something else?
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.
Hmm yeah, that's probably a fine idea to rename. So the purpose is to save where we have put in space filling comments in interpolation substitutions right... I feel like we should be able to come up with something better/even more specific than dummyCommentsMap
, I guess it's also not really even a mapping right? More like a list. How about dummyInterpolationLines
? Or dummyInterpolationLinesList
?
This is definitely a subjective issue though, no real answer to this.
@emilgoldsmith Comments mentioned above have been handled. I gave up renaming the variable because naming is really the hardest problem in programming. The current |
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.
Looks great!
Let's just squash these commits into like 1-3 commits though yeah? Whatever you feel creates a good history, I'm okay with 1, but if you feel there's a natural way to split it into several commits to look nicer on your Github graph I'm okay with that as well haha ;).
return Object.assign({}, stylelintResult, { warnings }) | ||
const result = Object.assign({}, stylelintResult, { warnings }) | ||
// Undo `errored` if no warnings with error severity any more | ||
if (result.errored && !warnings.some(warning => warning.severity === 'error')) { |
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.
Really nicely and succinctly written :)
@emilgoldsmith Haha, my Github graph doesn't matter. You can simply select "squash and merge". Thanks for your sweet reviews during these days! |
No problem haha! Actually "squash and merge" isn't enabled for this repo, so yeah if you find time to squash it at any point we can merge it right in :) |
14d313e
to
ca14148
Compare
@emilgoldsmith I rebased and squashed as 3 commits. |
Awesome. Thanks again for the hard work and several revisions! This is a nice addition to the repo :) |
@emilgoldsmith Last question, what's the publish strategy of this repository? I want to know when I can use the version with this fix. 😄 |
I'll publish it right now :). No defined strategy, more like the three publishers publish whenever they see fit / new changes are merged in |
Done :). Update to 1.2.0 and you'll have your changes |
Great! I will upgrade it in my project and keep observing. |
Fixes #128. And also able to pass #129.
processedNode.loc.start.line
, which is line 6. But it should be line 8.