diff --git a/extract.js b/extract.js index e3b6948..7d558ef 100644 --- a/extract.js +++ b/extract.js @@ -28,6 +28,8 @@ const supports = { // https://github.com/emotion-js/emotion emotion: true, + "@emotion/core": true, + "@emotion/styled": true, "react-emotion": true, "preact-emotion": true, @@ -56,6 +58,10 @@ const supports = { typestyle: true, }; +const cssPropImpliesStyle = { + "@emotion/core": true +}; + const plugins = [ "jsx", "typescript", @@ -113,6 +119,7 @@ function literalParser (source, opts, styles) { let objLiteral = new Set(); let tplLiteral = new Set(); const jobs = []; + let cssPropIsStyle = false; function addObjectJob (path) { jobs.push(() => { @@ -221,13 +228,16 @@ function literalParser (source, opts, styles) { nameSpace.push(specifier.imported.name); } setSpecifier(specifier.local, nameSpace); + if (cssPropImpliesStyle[moduleId]) { + cssPropIsStyle = true; + } }); }, JSXAttribute: (path) => { const attrName = path.node.name.name; if (attrName === "css") { const elePath = path.findParent(p => p.isJSXOpeningElement()); - if (!isStylePath(elePath)) { + if (!cssPropIsStyle && !isStylePath(elePath)) { return; } } else if (attrName !== "style") { diff --git a/test/emotion.js b/test/emotion.js index 78aa47f..0b6cfe4 100644 --- a/test/emotion.js +++ b/test/emotion.js @@ -35,4 +35,36 @@ describe("javascript tests", () => { }); }); }); + + it("emotion-10", () => { + const filename = require.resolve("./fixtures/emotion-10.jsx"); + let code = fs.readFileSync(filename); + + const document = syntax.parse(code, { + from: filename, + }); + + code = code.toString(); + + expect(document.toString()).to.equal(code); + expect(document.nodes).to.lengthOf(6); + + document.nodes.forEach(root => { + expect(root.last.toString()).to.be.a("string"); + expect(root.source).to.haveOwnProperty("input"); + + expect(code).to.includes(root.source.input.css); + expect(root.source.input.css.length).lessThan(code.length); + expect(root.source).to.haveOwnProperty("start").to.haveOwnProperty("line").to.greaterThan(1); + + root.walk(node => { + expect(node).to.haveOwnProperty("source"); + + expect(node.source).to.haveOwnProperty("input").to.haveOwnProperty("css").equal(root.source.input.css); + + expect(node.source).to.haveOwnProperty("start").to.haveOwnProperty("line"); + expect(node.source).to.haveOwnProperty("end").to.haveOwnProperty("line"); + }); + }); + }); }); diff --git a/test/fixtures/emotion-10.jsx b/test/fixtures/emotion-10.jsx new file mode 100644 index 0000000..4eaa38d --- /dev/null +++ b/test/fixtures/emotion-10.jsx @@ -0,0 +1,44 @@ +/* global render */ +/** @jsx jsx */ + +import { jsx, css } from '@emotion/core'; +import styled from '@emotion/styled'; + +const SomeComponent = styled.div` + display: flex; + background-color: ${props => props.color}; +`; + +const AnotherComponent = styled.h1( + { + color: "hotpink", + }, + props => ({ flex: props.flex }) +); + +render( + + + + Some text. + + + Some other text. + + + +); +const app = document.getElementById("root"); +const myStyle = css` + color: rebeccapurple; +`; +app.classList.add(myStyle); + +export default { + SomeComponent, + AnotherComponent, +}; diff --git a/test/fixtures/non-styled.jsx b/test/fixtures/non-styled.jsx new file mode 100644 index 0000000..93b081f --- /dev/null +++ b/test/fixtures/non-styled.jsx @@ -0,0 +1,24 @@ +import React from "react"; + +const App = props => ( +
+); + +export default { + React, + Div, + App, +}; diff --git a/test/non-style.js b/test/non-style.js index 0b5e254..a378162 100644 --- a/test/non-style.js +++ b/test/non-style.js @@ -1,11 +1,11 @@ "use strict"; const spawnSync = require("child_process").spawnSync; const fs = require("fs"); -const files = spawnSync("git", ["ls-files"], { encoding: "utf8" }).stdout.match(/^.+$/gm).filter(file => file.endsWith(".js")); +const files = spawnSync("git", ["ls-files"], { encoding: "utf8" }).stdout.match(/^.+$/gm).filter(file => file.endsWith(".js")).concat('test/fixtures/non-styled.jsx'); const syntax = require("../"); const expect = require("chai").expect; -describe("non-style js files", () => { +describe("non-styled js|jsx files", () => { files.forEach(file => { it(file, () => { const code = fs.readFileSync(file);