Skip to content
This repository was archived by the owner on May 14, 2021. It is now read-only.

Fix reported line numbers #140

Merged
merged 3 commits into from
Dec 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 30 additions & 10 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const path = require('path')
const parse = require('./parsers/index')

const interpolationLinesMap = {}
const sourceMapsCorrections = {}
const DEFAULT_OPTIONS = {
moduleName: 'styled-components'
Expand All @@ -12,11 +13,15 @@ module.exports = options => ({
try {
const absolutePath = path.resolve(process.cwd(), filepath)
sourceMapsCorrections[absolutePath] = {}
const { extractedCSS, sourceMap } = parse(
const { extractedCSS, interpolationLines, sourceMap } = parse(
input,
absolutePath,
Object.assign({}, DEFAULT_OPTIONS, options)
)
// Save dummy interpolation lines
interpolationLinesMap[absolutePath] = interpolationLines.concat(
interpolationLinesMap[absolutePath] || []
)
// Save source location, merging existing corrections with current corrections
sourceMapsCorrections[absolutePath] = Object.assign(
sourceMapsCorrections[absolutePath],
Expand All @@ -33,16 +38,31 @@ module.exports = options => ({
},
// Fix sourcemaps
result(stylelintResult, filepath) {
const interpolationLines = interpolationLinesMap[filepath] || []
const lineCorrection = sourceMapsCorrections[filepath]
const warnings = stylelintResult.warnings.map(warning =>
Object.assign({}, warning, {
// Replace "brace" with "backtick" in warnings, e.g.
// "Unexpected empty line before closing backtick" (instead of "brace")
text: warning.text.replace(/brace/, 'backtick'),
line: lineCorrection[warning.line]
})
)
const warnings = stylelintResult.warnings
.filter(
warning =>
// Filter indentation warnings generated by interpolations substitution
!(
warning.rule === 'indentation' &&
interpolationLines.indexOf(lineCorrection[warning.line]) >= 0
)
)
.map(warning =>
Object.assign({}, warning, {
// Replace "brace" with "backtick" in warnings, e.g.
// "Unexpected empty line before closing backtick" (instead of "brace")
text: warning.text.replace(/brace/, 'backtick'),
line: lineCorrection[warning.line]
})
)

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')) {
Copy link
Member

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 :)

delete result.errored
}
return result
}
})
15 changes: 14 additions & 1 deletion src/parsers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const processStyledComponentsFile = (ast, absolutePath, options) => {
injectGlobal: 'injectGlobal'
}
let sourceMap = {}
const interpolationLines = []
traverse(ast, {
noScope: true,
enter({ node }) {
Expand Down Expand Up @@ -74,8 +75,19 @@ 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)
Copy link
Member

Choose a reason for hiding this comment

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

Nice!

)
// Save dummy interpolation lines
node.quasi.expressions.forEach((expression, i) => {
// Skip the end line of previous text
// because the indentation is not generated by substitution
let l = node.quasi.quasis[i].loc.end.line + 1
while (l <= node.quasi.quasis[i + 1].loc.start.line) {
interpolationLines.push(l)
l += 1
}
})

/**
* All queued comments have been added to the file so we don't need to, and actually shouldn't
* add them to the file more than once
Expand All @@ -86,6 +98,7 @@ const processStyledComponentsFile = (ast, absolutePath, options) => {

return {
extractedCSS: extractedCSS.join('\n'),
interpolationLines,
sourceMap
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/utils/tagged-template-literal.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ const interleave = (quasis, expressions, absolutePath) => {
*/
substitute = '$dummyValue'
}
// Make sure substituted by same count of lines
Copy link
Member

Choose a reason for hiding this comment

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

This looks good

const targetLines = quasis[i + 1].loc.start.line - quasis[i].loc.end.line + 1
let currentLines = substitute.split('\n').length
while (currentLines < targetLines) {
substitute += '\n/* dummyComment */'
currentLines += 1
}

css += substitute
}
css += quasis[quasis.length - 1].value.raw
Expand Down
10 changes: 9 additions & 1 deletion test/fixtures/interpolations/invalid.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@ import styled from 'styled-components'
const color = 'red'

// ⚠️ BAD INDENTATION ⚠️
const Button2 = styled.button`
const Button2 = styled.button.attrs({
type: 'normal'
})`
display: block;
${
props => props.isHovering && interpolatedStyle
}
position: ${
props => props.position
};
color: ${color};
background: blue;
`
4 changes: 4 additions & 0 deletions test/interpolations.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ describe('interpolations', () => {
it('should have an indentation as the first warning', () => {
expect(data.results[0].warnings[0].rule).toEqual('indentation')
})

it('should have the indentation warning in the right line', () => {
expect(data.results[0].warnings[0].line).toEqual(16)
})
})

describe('complex interpolations', () => {
Expand Down
39 changes: 39 additions & 0 deletions test/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ const fixIndentation = require('../lib/utils/general').fixIndentation
const extrapolateShortenedCommand = require('../lib/utils/general').extrapolateShortenedCommand
const removeBaseIndentation = require('../lib/utils/general').removeBaseIndentation

const mockLoc = (startLine, endLine) => ({
start: {
line: startLine
},
end: {
line: endLine
}
})

describe('utils', () => {
describe('interleave', () => {
it('should return the value of the node if no interpolation exists', () => {
Expand All @@ -28,18 +37,21 @@ describe('utils', () => {
it('should variabelize an interpolation', () => {
const quasis = [
{
loc: mockLoc(1, 3),
value: {
raw: '\n display: block;\n color: '
}
},
{
loc: mockLoc(3, 5),
value: {
raw: ';\n background: blue;\n'
}
}
]
const expressions = [
{
loc: mockLoc(3, 3),
name: 'color'
}
]
Expand All @@ -51,18 +63,21 @@ describe('utils', () => {
it('converts interpolated expressions to dummy mixins', () => {
const quasis = [
{
loc: mockLoc(1, 3),
value: {
raw: '\n display: block;\n '
}
},
{
loc: mockLoc(3, 5),
value: {
raw: '\n background: blue;\n'
}
}
]
const expressions = [
{
loc: mockLoc(3, 3),
name: undefined
}
]
Expand All @@ -74,34 +89,41 @@ describe('utils', () => {
it('correctly converts several interpolations within a single property', () => {
const quasis = [
{
loc: mockLoc(1, 3),
value: {
raw: '\n display: block;\n border: '
}
},
{
loc: mockLoc(3, 3),
value: {
raw: ' '
}
},
{
loc: mockLoc(3, 3),
value: {
raw: ' '
}
},
{
loc: mockLoc(3, 5),
value: {
raw: ';\n background: blue;\n'
}
}
]
const expressions = [
{
loc: mockLoc(3, 3),
name: 'borderWidth'
},
{
loc: mockLoc(3, 3),
name: 'borderStyle'
},
{
loc: mockLoc(3, 3),
name: 'color'
}
]
Expand All @@ -113,26 +135,31 @@ describe('utils', () => {
it('correctly handles several interpolations in single line of css', () => {
const quasis1 = [
{
loc: mockLoc(1, 2),
value: {
raw: '\n display: '
}
},
{
loc: mockLoc(2, 2),
value: {
raw: '; background: '
}
},
{
loc: mockLoc(2, 3),
value: {
raw: ';\n'
}
}
]
const expressions1 = [
{
loc: mockLoc(2, 2),
name: 'display'
},
{
loc: mockLoc(2, 2),
name: 'background'
}
]
Expand All @@ -142,26 +169,31 @@ describe('utils', () => {

const quasis2 = [
{
loc: mockLoc(1, 2),
value: {
raw: '\n display: '
}
},
{
loc: mockLoc(2, 2),
value: {
raw: '; '
}
},
{
loc: mockLoc(2, 3),
value: {
raw: '\n'
}
}
]
const expressions2 = [
{
loc: mockLoc(2, 2),
name: 'display'
},
{
loc: mockLoc(3, 3),
name: undefined
}
]
Expand All @@ -176,34 +208,41 @@ describe('utils', () => {
*/
const quasis3 = [
{
loc: mockLoc(1, 2),
value: {
raw: '\n display: '
}
},
{
loc: mockLoc(2, 2),
value: {
raw: '; '
}
},
{
loc: mockLoc(2, 2),
value: {
raw: ' '
}
},
{
loc: mockLoc(2, 3),
value: {
raw: '\n'
}
}
]
const expressions3 = [
{
loc: mockLoc(2, 2),
name: 'display'
},
{
loc: mockLoc(2, 2),
name: undefined
},
{
loc: mockLoc(2, 2),
name: undefined
}
]
Expand Down