diff --git a/README.md b/README.md index 8575565..aaaa123 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,6 @@ Now use those in your `.stylelintrc` and run stylelint with your JavaScript file - [sc-custom](https://www.styled-components.com/docs/tooling#sc-custom) - [Syntax Notes](https://www.styled-components.com/docs/tooling#syntax-notes) - ## License Licensed under the MIT License, Copyright © 2017 Maximilian Stoiber. See [LICENSE.md](./LICENSE.md) for more information! diff --git a/package-lock.json b/package-lock.json index b0567fd..2a74110 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5171,6 +5171,15 @@ "integrity": "sha1-Rb8dny19wJvtgfHDB8Qw5ouEz/4=", "dev": true }, + "string_decoder": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz", + "integrity": "sha1-sp4fThEl+pehA4K4pTNze3SR4Xk=", + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, "string-length": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", @@ -5191,15 +5200,6 @@ "strip-ansi": "3.0.1" } }, - "string_decoder": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz", - "integrity": "sha1-sp4fThEl+pehA4K4pTNze3SR4Xk=", - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", diff --git a/src/index.js b/src/index.js index 56a6f3e..ca41f64 100644 --- a/src/index.js +++ b/src/index.js @@ -2,13 +2,20 @@ const path = require('path') const parse = require('./parsers/index') const sourceMapsCorrections = {} +const DEFAULT_OPTIONS = { + moduleName: 'styled-components' +} -module.exports = (/* options */) => ({ +module.exports = options => ({ // Get string for stylelint to lint code(input, filepath) { const absolutePath = path.resolve(process.cwd(), filepath) sourceMapsCorrections[absolutePath] = {} - const { extractedCSS, sourceMap } = parse(input, absolutePath) + const { extractedCSS, sourceMap } = parse( + input, + absolutePath, + Object.assign({}, DEFAULT_OPTIONS, options) + ) // Save source location, merging existing corrections with current corrections sourceMapsCorrections[absolutePath] = Object.assign( sourceMapsCorrections[absolutePath], diff --git a/src/parsers/index.js b/src/parsers/index.js index 6f16486..390c5ff 100644 --- a/src/parsers/index.js +++ b/src/parsers/index.js @@ -17,7 +17,7 @@ const getTTLContent = require('../utils/tagged-template-literal.js').getTaggedTe const parseImports = require('../utils/parse').parseImports const getSourceMap = require('../utils/parse').getSourceMap -const processStyledComponentsFile = (ast, absolutePath) => { +const processStyledComponentsFile = (ast, absolutePath, options) => { const extractedCSS = [] let ignoreRuleComments = [] let importedNames = { @@ -37,7 +37,7 @@ const processStyledComponentsFile = (ast, absolutePath) => { } }) } - if (isStyledImport(node)) { + if (isStyledImport(node, options.moduleName)) { importedNames = parseImports(node) return } @@ -90,7 +90,7 @@ const processStyledComponentsFile = (ast, absolutePath) => { } } -module.exports = (input, absolutePath) => { +module.exports = (input, absolutePath, options) => { let ast = null if (absolutePath.endsWith('.ts') || absolutePath.endsWith('.tsx')) { // We import it dynamically in order to be able to not include typescript as a dependency @@ -101,5 +101,5 @@ module.exports = (input, absolutePath) => { } else { ast = estreeParse(input) } - return processStyledComponentsFile(ast, absolutePath) + return processStyledComponentsFile(ast, absolutePath, options) } diff --git a/src/utils/styled.js b/src/utils/styled.js index b33b58f..b498c12 100644 --- a/src/utils/styled.js +++ b/src/utils/styled.js @@ -1,10 +1,11 @@ +const path = require('path') const isTaggedTemplateLiteral = require('./tagged-template-literal').isTaggedTemplateLiteral /** * Check if something is a styled-components import declaration */ -const isStyledImport = node => - node.type === 'ImportDeclaration' && node.source.value === 'styled-components' +const isStyledImport = (node, moduleName) => + node.type === 'ImportDeclaration' && path.basename(node.source.value) === moduleName /** * Check if something is a styled shorthand call diff --git a/test/fixtures/options/invalid-module-name.js b/test/fixtures/options/invalid-module-name.js new file mode 100644 index 0000000..f64ab87 --- /dev/null +++ b/test/fixtures/options/invalid-module-name.js @@ -0,0 +1,8 @@ +import something from 'some-lib' + + +// Empty block, but moduleName isn't set to some-lib +// so shouldn't be an error +const Button = something.div` + +` diff --git a/test/fixtures/options/module-name.js b/test/fixtures/options/module-name.js new file mode 100644 index 0000000..d7a2d4c --- /dev/null +++ b/test/fixtures/options/module-name.js @@ -0,0 +1,6 @@ +import emotion from 'emotion' + +// ⚠️ EMPTY BLOCK ⚠️ +const Button = emotion.div` + +` diff --git a/test/fixtures/options/relative-module-name.js b/test/fixtures/options/relative-module-name.js new file mode 100644 index 0000000..64e4179 --- /dev/null +++ b/test/fixtures/options/relative-module-name.js @@ -0,0 +1,6 @@ +import emotion from '../../emotion' + +// ⚠️ EMPTY BLOCK ⚠️ +const Button = emotion.div` + +` diff --git a/test/fixtures/simple/other-library.js b/test/fixtures/simple/other-library.js new file mode 100644 index 0000000..416f600 --- /dev/null +++ b/test/fixtures/simple/other-library.js @@ -0,0 +1,6 @@ +import styled from 'some-other-lib' + +// ⚠️ BAD INDENTATION ⚠️ +const Button2 = styled.button` +color: blue; +` diff --git a/test/options.test.js b/test/options.test.js new file mode 100644 index 0000000..b900ff6 --- /dev/null +++ b/test/options.test.js @@ -0,0 +1,115 @@ +const stylelint = require('stylelint') +const path = require('path') + +const processor = path.join(__dirname, '../src/index.js') +const rules = { + 'block-no-empty': true, + indentation: 2, + 'rule-empty-line-before': [ + 'always-multi-line', + { + except: ['first-nested'], + ignore: ['after-comment'] + } + ], + 'selector-type-no-unknown': true +} + +describe('options', () => { + let fixture + let data + + // NOTE beforeEach() runs _after_ the beforeAll() hooks of the describe() blocks, so `fixture` + // will have the right path + beforeEach(done => { + stylelint + .lint({ + files: [fixture], + syntax: 'scss', + config: { + // Set moduleName option to "emotion" + processors: [[processor, { moduleName: 'emotion' }]], + rules + } + }) + .then(result => { + data = result + done() + }) + .catch(err => { + console.log(err) + data = err + done() + }) + }) + + describe('moduleName', () => { + beforeAll(() => { + fixture = path.join(__dirname, './fixtures/options/module-name.js') + }) + + it('should have one result', () => { + expect(data.results.length).toEqual(1) + }) + + it('should use the right file', () => { + expect(data.results[0].source).toEqual(fixture) + }) + + it('should have errored', () => { + expect(data.results[0].errored).toEqual(true) + }) + + it('should have one warning (i.e. wrong lines of code)', () => { + expect(data.results[0].warnings.length).toEqual(1) + }) + + it('should have a block-no-empty as the first warning', () => { + expect(data.results[0].warnings[0].rule).toEqual('block-no-empty') + }) + }) + + describe('relative moduleName', () => { + beforeAll(() => { + fixture = path.join(__dirname, './fixtures/options/relative-module-name.js') + }) + + it('should have one result', () => { + expect(data.results.length).toEqual(1) + }) + + it('should use the right file', () => { + expect(data.results[0].source).toEqual(fixture) + }) + + it('should have errored', () => { + expect(data.results[0].errored).toEqual(true) + }) + + it('should have one warning (i.e. wrong lines of code)', () => { + expect(data.results[0].warnings.length).toEqual(1) + }) + + it('should have a block-no-empty as the first warning', () => { + expect(data.results[0].warnings[0].rule).toEqual('block-no-empty') + }) + }) + + describe('invalid moduleName', () => { + beforeAll(() => { + fixture = path.join(__dirname, './fixtures/options/invalid-module-name.js') + }) + + it('should have one result', () => { + expect(data.results.length).toEqual(1) + }) + + it('should use the right file', () => { + expect(data.results[0].source).toEqual(fixture) + }) + + it('should not have errored', () => { + expect(data.results[0].errored).toEqual(undefined) + }) + }) +}) diff --git a/test/simple.test.js b/test/simple.test.js index 0136b44..6f038eb 100644 --- a/test/simple.test.js +++ b/test/simple.test.js @@ -198,6 +198,28 @@ describe('simple', () => { }) }) + describe('other library', () => { + beforeAll(() => { + fixture = path.join(__dirname, './fixtures/simple/other-library.js') + }) + + it('should have one result', () => { + expect(data.results.length).toEqual(1) + }) + + it('should use the right file', () => { + expect(data.results[0].source).toEqual(fixture) + }) + + it('should have errored', () => { + expect(data.errored).toEqual(true) + }) + + it('should have 1 warning', () => { + expect(data.results[0].warnings.length).toEqual(1) + }) + }) + describe('identify styled', () => { beforeAll(() => { fixture = path.join(__dirname, './fixtures/simple/identify-styled.js')