diff --git a/src/utils/result.js b/src/utils/result.js index 4ee6de1..e4fbb89 100644 --- a/src/utils/result.js +++ b/src/utils/result.js @@ -2,7 +2,11 @@ exports.isCausedBySubstitution = (warning, line, interpolationLines) => interpolationLines.some(({ start, end }) => { if (line > start && line < end) { // Inner interpolation lines must be - return true + return ( + ['value-list-max-empty-lines', 'comment-empty-line-before', 'indentation'].indexOf( + warning.rule + ) >= 0 + ) } else if (line === start) { return ['value-list-max-empty-lines', 'comment-empty-line-before'].indexOf(warning.rule) >= 0 } else if (line === end) { diff --git a/src/utils/styled.js b/src/utils/styled.js index bb2707f..8ee9b20 100644 --- a/src/utils/styled.js +++ b/src/utils/styled.js @@ -5,7 +5,8 @@ const { isTaggedTemplateLiteral } = require('./tagged-template-literal') * Check if something is a styled-components import declaration */ const isStyledImport = (node, moduleName) => - node.type === 'ImportDeclaration' && path.basename(node.source.value) === moduleName + node.type === 'ImportDeclaration' && + (Array.isArray(moduleName) ? moduleName : [moduleName]).includes(path.basename(node.source.value)) /** * Check if something is a styled shorthand call diff --git a/test/fixtures/hard/invalid-properties.js b/test/fixtures/hard/invalid-properties.js new file mode 100644 index 0000000..4d88e18 --- /dev/null +++ b/test/fixtures/hard/invalid-properties.js @@ -0,0 +1,35 @@ +import styled, { css } from 'styled-components'; +import React from 'react' + +export default props => { + const CirclePrimitive = styled.div` + // next line has wrong property + widthh: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + ${props.rotate && css` + -webkit-transform: rotate(${props.rotate}deg); + -ms-transform: rotate(${props.rotate}deg); + transform: rotate(${props.rotate}deg); + `} + + &:before { + content: ''; + display: block; + margin: 0 auto; + width: 15%; + height: 15%; + // next line has wrong property + background-colorr: #333; + border-radius: 100%; + animation: ${animations.spinnerCircle} 1.2s infinite ease-in-out both; + ${props.delay && css` + -webkit-animation-delay: ${props.delay}s; + animation-delay: ${props.delay}s; + `} + } + ` + return React.createElement(CirclePrimitive) +} diff --git a/test/fixtures/hard/invalid-substitution-properties.js b/test/fixtures/hard/invalid-substitution-properties.js new file mode 100644 index 0000000..bd10758 --- /dev/null +++ b/test/fixtures/hard/invalid-substitution-properties.js @@ -0,0 +1,35 @@ +import styled, { css } from 'styled-components'; +import React from 'react' + +export default props => { + const CirclePrimitive = styled.div` + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + ${props.rotate && css` + -webkit-transform: rotate(${props.rotate}deg); + -ms-transform: rotate(${props.rotate}deg); + // next line has wrong property + transformm: rotate(${props.rotate}deg); + `} + + &:before { + content: ''; + display: block; + margin: 0 auto; + width: 15%; + height: 15%; + background-color: #333; + border-radius: 100%; + animation: ${animations.spinnerCircle} 1.2s infinite ease-in-out both; + ${props.delay && css` + -webkit-animation-delay: ${props.delay}s; + // next line has wrong property + animation-delayy: ${props.delay}s; + `} + } + ` + return React.createElement(CirclePrimitive) +} diff --git a/test/fixtures/options/module-name-two.js b/test/fixtures/options/module-name-two.js new file mode 100644 index 0000000..1f21c03 --- /dev/null +++ b/test/fixtures/options/module-name-two.js @@ -0,0 +1,6 @@ +import emotion from 'some-module' + +// ⚠️ EMPTY BLOCK ⚠️ +const Button = emotion.div` + +` diff --git a/test/fixtures/options/relative-module-name-two.js b/test/fixtures/options/relative-module-name-two.js new file mode 100644 index 0000000..20deb97 --- /dev/null +++ b/test/fixtures/options/relative-module-name-two.js @@ -0,0 +1,6 @@ +import emotion from '../../some-module' + +// ⚠️ EMPTY BLOCK ⚠️ +const Button = emotion.div` + +` diff --git a/test/hard.test.js b/test/hard.test.js index 42f1da9..eee7d61 100644 --- a/test/hard.test.js +++ b/test/hard.test.js @@ -166,4 +166,54 @@ describe('hard', () => { }) }) }) + + describe('invalid properties', () => { + describe('valid', () => { + beforeAll(() => { + fixture = slash(path.join(__dirname, './fixtures/hard/invalid-properties.js')) + }) + + it('should have one result', () => { + expect(data.results.length).toEqual(1) + }) + + it('should use the right file', () => { + expect(slash(data.results[0].source)).toEqual(fixture) + }) + + it('should have errored', () => { + expect(data.errored).toEqual(true) + }) + + it('should not have any warnings', () => { + console.log(data) + expect(data.results[0].warnings.length).toEqual(2) + }) + }) + }) + + describe('invalid substitution properties', () => { + describe('valid', () => { + beforeAll(() => { + fixture = slash(path.join(__dirname, './fixtures/hard/invalid-substitution-properties.js')) + }) + + it('should have one result', () => { + expect(data.results.length).toEqual(1) + }) + + it('should use the right file', () => { + expect(slash(data.results[0].source)).toEqual(fixture) + }) + + it('should have errored', () => { + expect(data.errored).toEqual(true) + }) + + it('should not have any warnings', () => { + console.log(data) + expect(data.results[0].warnings.length).toEqual(2) + }) + }) + }) }) diff --git a/test/options.test.js b/test/options.test.js index 05e7dfe..a625b29 100644 --- a/test/options.test.js +++ b/test/options.test.js @@ -18,6 +18,7 @@ const rules = { describe('options', () => { let fixture + let fixtures let data describe('moduleName', () => { @@ -116,6 +117,94 @@ describe('options', () => { }) }) + describe('moduleName array', () => { + beforeEach(done => { + stylelint + .lint({ + files: fixtures, + config: { + // Set moduleName option to "emotion" + processors: [[processor, { moduleName: ['emotion', 'some-module'] }]], + rules + } + }) + .then(result => { + data = result + done() + }) + .catch(err => { + // eslint-disable-next-line no-console + console.log(err) + data = err + done() + }) + }) + + describe('moduleName', () => { + beforeAll(() => { + fixtures = [ + slash(path.join(__dirname, './fixtures/options/module-name.js')), + slash(path.join(__dirname, './fixtures/options/module-name-two.js')) + ] + }) + + it('should have one result', () => { + expect(data.results.length).toEqual(2) + }) + + it('should use the right file', () => { + expect([slash(data.results[0].source), slash(data.results[1].source)]).toEqual(fixtures) + }) + + it('should have errored', () => { + expect([data.results[0].errored, data.results[1].errored]).toEqual([true, true]) + }) + + it('should have one warning (i.e. wrong lines of code)', () => { + expect([data.results[0].warnings.length, data.results[1].warnings.length]).toEqual([1, 1]) + }) + + it('should have a block-no-empty as the first warning', () => { + expect([data.results[0].warnings[0].rule, data.results[1].warnings[0].rule]).toEqual([ + 'block-no-empty', + 'block-no-empty' + ]) + }) + }) + + describe('relative moduleName', () => { + beforeAll(() => { + fixtures = [ + slash(path.join(__dirname, './fixtures/options/relative-module-name.js')), + slash(path.join(__dirname, './fixtures/options/relative-module-name-two.js')) + ] + }) + + it('should have one result', () => { + expect(data.results.length).toEqual(2) + }) + + it('should use the right file', () => { + expect([slash(data.results[0].source), slash(data.results[1].source)]).toEqual(fixtures) + }) + + it('should have errored', () => { + expect([data.results[0].errored, data.results[1].errored]).toEqual([true, true]) + }) + + it('should have one warning (i.e. wrong lines of code)', () => { + expect([data.results[0].warnings.length, data.results[1].warnings.length]).toEqual([1, 1]) + }) + + it('should have a block-no-empty as the first warning', () => { + expect([data.results[0].warnings[0].rule, data.results[1].warnings[0].rule]).toEqual([ + 'block-no-empty', + 'block-no-empty' + ]) + }) + }) + }) + describe('importName', () => { // NOTE beforeEach() runs _after_ the beforeAll() hooks of the describe() blocks, so `fixture` // will have the right path diff --git a/test/utils.test.js b/test/utils.test.js index 52a302b..306f14a 100644 --- a/test/utils.test.js +++ b/test/utils.test.js @@ -632,7 +632,9 @@ html { { start: 5, end: 5 } ] it("returns true if real warning line is between some interpolation's start and end", () => { - expect(fn({ rule: 'any rule' }, 3, interpolationLines)).toEqual(true) + expect(fn({ rule: 'value-list-max-empty-lines' }, 3, interpolationLines)).toEqual(true) + expect(fn({ rule: 'comment-empty-line-before' }, 3, interpolationLines)).toEqual(true) + expect(fn({ rule: 'indentation' }, 3, interpolationLines)).toEqual(true) }) it("returns false if real warning line is beyond any interpolation's start and end", () => { expect(fn({ rule: 'any rule' }, 1, interpolationLines)).toEqual(false)