Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix support for styled options #47

Merged
merged 1 commit into from
Dec 29, 2018
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
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,23 @@ PostCSS JSX Syntax

- [aphrodite](https://github.com/Khan/aphrodite)
- [astroturf](https://github.com/4Catalyzer/astroturf)
- [csjs](https://github.com/rtsao/csjs)
- [css-light](https://github.com/streamich/css-light)
- [cssobj](https://github.com/cssobj/cssobj)
- [electron-css](https://github.com/azukaar/electron-css)
- [emotion](https://github.com/emotion-js/emotion)
- [freestyler](https://github.com/streamich/freestyler)
- [glamor](https://github.com/threepointone/glamor)
- [glamorous](https://github.com/paypal/glamorous)
- [j2c](https://github.com/j2css/j2c)
- [linaria](https://github.com/callstack/linaria)
- [lit-css](https://github.com/bashmish/lit-css)
- [react-native](https://github.com/necolas/react-native-web)
- [react-style](https://github.com/js-next/react-style)
- [reactcss](https://github.com/casesandberg/reactcss)
- [styled-components](https://github.com/styled-components/styled-components)
- [styletron-react](https://github.com/rtsao/styletron)
- [styling](https://github.com/andreypopp/styling)
- [typestyle](https://github.com/typestyle/typestyle)

## Getting Started
Expand All @@ -39,7 +47,7 @@ npm install postcss-syntax postcss-jsx --save-dev
```js
const postcss = require('postcss');
const stylelint = require('stylelint');
const syntax = require('postcss-jsx');
const syntax = require('postcss-syntax');
postcss([stylelint({ fix: true })]).process(source, { syntax: syntax }).then(function (result) {
// An alias for the result.css property. Use it with syntaxes that generate non-CSS output.
result.content
Expand Down Expand Up @@ -68,6 +76,14 @@ const Component1 = glm.a({

## Advanced Use Cases

Add support for more `css-in-js` package:
```js
const syntax = require('postcss-syntax')({
"i-css": (index, namespace) => namespace[index + 1] === "addStyles",
"styled-components": true,
});
```

See: [postcss-syntax](https://github.com/gucong3000/postcss-syntax)

## Style Transformations
Expand Down
128 changes: 88 additions & 40 deletions extract.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,79 @@ const {
const getTemplate = require("./get-template");
const loadSyntax = require("postcss-syntax/load-syntax");

const isStyleSheetCreate = expectAdjacentSibling(["create"]);
const supports = {
// https://github.com/Khan/aphrodite
// https://github.com/necolas/react-native-web
StyleSheet: true,

// https://github.com/emotion-js/emotion
// import styled from '@emotion/styled'
// https://github.com/threepointone/glamor
// import { styled } from 'glamor/styled'
// https://github.com/rtsao/styletron
// import { styled } from "styletron-react";
// import { styled } from 'linaria/react';
styled: true,

// https://github.com/typestyle/typestyle
// import { style } from "typestyle";
style: true,

// https://github.com/4Catalyzer/astroturf
// import { css } from 'astroturf';
// https://github.com/bashmish/lit-css
// import { StyleSheet, css } from 'aphrodite';
// import styled, { css } from 'astroturf';
// import { css } from 'lit-css';
// https://github.com/threepointone/glamor
// import { css } from 'glamor'
// require('css-light').css({color: 'red'});
// import { css } from 'linaria';
css: true,

// https://github.com/emotion-js/emotion
// import { StyleSheet, css } from 'aphrodite';
// import { AppRegistry, StyleSheet, Text, View } from 'react-native';
StyleSheet: isStyleSheetCreate,

// import styled, { css } from 'astroturf';
astroturf: true,

// require('csjs')`css`;
csjs: true,

// require('cssobj')({color: 'red'})
cssobj: true,

// require('electron-css')({color: 'red'})
"electron-css": true,

// import styled from "react-emotion";
emotion: true,
"react-emotion": true,

// import styled from 'preact-emotion'
"preact-emotion": true,

// https://github.com/streamich/freestyler
freestyler: true,

// https://github.com/paypal/glamorous
glamorous: true,

// https://github.com/js-next/react-style
"react-style": true,
// https://github.com/irom-io/i-css
// "i-css": (i, nameSpace) => nameSpace[i + 1] === "addStyles" && nameSpace[i + 2] === "wrapper",

// https://github.com/j2css/j2c
j2c: expectAdjacentSibling(["inline", "sheet"]),

// https://github.com/casesandberg/reactcss
// var styles = StyleSheet.create({color: 'red'})
"react-inline": isStyleSheetCreate,
"react-style": isStyleSheetCreate,

// import reactCSS from 'reactcss'
reactcss: true,

// https://github.com/styled-components/styled-components
// const StyledButton = injectSheet(styles)(Button)
"react-jss": true,

// import styled from 'styled-components';
"styled-components": true,

// https://github.com/rtsao/styletron
// import {styled} from "styletron-react";
// import {withStyle} from "styletron-react";
"styletron-react": true,
"styletron-react": expectAdjacentSibling(["withStyle"]),

"styling": true,

// const rule = superstyle({ color: 'blue' })
"superstyle": true,
};

const plugins = [
Expand All @@ -71,38 +97,45 @@ const plugins = [
"optionalCatchBinding",
];

function getSourceType (filename) {
if (filename && /\.m[tj]sx?$/.test(filename)) {
return "module";
}
try {
return loadOptions({
filename,
}).sourceType;
} catch (ex) {
//
}
function expectAdjacentSibling (names) {
return (i, nameSpace) => (
names.some(name => nameSpace[i + 1] === name)
);
}

function getOptions (opts) {
function loadBabelOpts (opts) {
const filename = opts.from && opts.from.replace(/\?.*$/, "");

return {
opts = {
sourceFilename: filename,
sourceType: getSourceType(filename) || "unambiguous",
sourceType: filename && /\.m[tj]sx?$/.test(filename) ? "module" : "unambiguous",
plugins,
allowImportExportEverywhere: true,
allowAwaitOutsideFunction: true,
allowReturnOutsideFunction: true,
allowSuperOutsideMethod: true,
};
let fileOpts;
try {
fileOpts = filename && loadOptions({
filename,
});
} catch (ex) {
//
}
for (const key in fileOpts) {
if (Array.isArray(fileOpts[key]) && !fileOpts[key].length) {
continue;
}
opts[key] = fileOpts[key];
}
return opts;
}

function literalParser (source, opts, styles) {
let ast;
try {
ast = parse(source, {
parserOpts: getOptions(opts),
parserOpts: loadBabelOpts(opts),
});
} catch (ex) {
// console.error(ex);
Expand All @@ -113,6 +146,7 @@ function literalParser (source, opts, styles) {
const variableDeclarator = new Map();
let objLiteral = new Set();
let tplLiteral = new Set();
const tplCallee = new Set();
const jobs = [];

function addObjectJob (path) {
Expand Down Expand Up @@ -200,7 +234,18 @@ function literalParser (source, opts, styles) {
}

function isStylePath (path) {
return getNameSpace(path, []).some(name => name && supports[name]);
return getNameSpace(path, []).some(function (name) {
let result = name && ((supports.hasOwnProperty(name) && supports[name]) || (opts.syntax.config.hasOwnProperty(name) && opts.syntax.config[name]));
switch (typeof result) {
case "function": {
result = result.apply(this, Array.prototype.slice.call(arguments, 1));
}
// eslint-disable-next-line no-fallthrough
case "boolean": {
return result;
}
}
});
}

const visitor = {
Expand All @@ -215,7 +260,7 @@ function literalParser (source, opts, styles) {
});
},
JSXAttribute: (path) => {
if (supports[path.node.name.name]) {
if (/^(?:css|style)$/.test(path.node.name.name)) {
addObjectJob(path.get("value.expression"));
}
},
Expand Down Expand Up @@ -259,7 +304,7 @@ function literalParser (source, opts, styles) {
break;
} while (currPath);
});
} else if (isStylePath(path.get("callee"))) {
} else if (!tplCallee.has(callee) && isStylePath(path.get("callee"))) {
path.get("arguments").forEach((arg) => {
addObjectJob(arg.isFunction() ? arg.get("body") : arg);
});
Expand All @@ -268,6 +313,9 @@ function literalParser (source, opts, styles) {
TaggedTemplateExpression: (path) => {
if (isStylePath(path.get("tag"))) {
tplLiteral.add(path.node.quasi);
if (path.node.tag.callee) {
tplCallee.add(path.node.tag.callee);
}
}
},
};
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"debug": "npm run mocha -- --inspect-brk"
},
"dependencies": {
"@babel/core": "^7.1.2"
"@babel/core": ">=7.1.0"
},
"peerDependencies": {
"postcss": ">=5.0.0",
Expand Down
9 changes: 9 additions & 0 deletions test/fixtures/styled-opts.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import styled from "astroturf";
import Footer from "footer";

const Button = styled(Footer, { allowAs: true })`
position: relative;
display: flex;
`;

export default Button;
81 changes: 81 additions & 0 deletions test/fixtures/styled-opts.mjs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"raws": {},
"type": "root",
"nodes": [
{
"raws": {
"semicolon": true,
"after": "\n"
},
"type": "root",
"nodes": [
{
"raws": {
"before": "\n\t",
"between": ": "
},
"type": "decl",
"source": {
"start": {
"line": 5,
"column": 2
},
"input": {
"file": "styled-opts.mjs"
},
"end": {
"line": 5,
"column": 20
}
},
"prop": "position",
"value": "relative"
},
{
"raws": {
"before": "\n\t",
"between": ": "
},
"type": "decl",
"source": {
"start": {
"line": 6,
"column": 2
},
"input": {
"file": "styled-opts.mjs"
},
"end": {
"line": 6,
"column": 15
}
},
"prop": "display",
"value": "flex"
}
],
"source": {
"input": {
"file": "styled-opts.mjs"
},
"start": {
"line": 4,
"column": 50
},
"inline": false,
"lang": "css",
"syntax": {}
}
}
],
"source": {
"input": {
"file": "styled-opts.mjs"
},
"start": {
"line": 1,
"column": 1
},
"lang": "jsx"
}
}
2 changes: 2 additions & 0 deletions test/fixtures/toLocaleString.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line
(positionsChecked / scansCount).toLocaleString("de-DE", { style: "percent" });
9 changes: 5 additions & 4 deletions test/supports.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,18 @@ function clean (node) {

describe("should support for each CSS in JS package", () => {
[
"emotion-10.jsx",
"glamorous.jsx",
"interpolation-content.mjs",
"jsx.jsx",
"emotion-10.jsx",
"lit-css.mjs",
"react-emotion.jsx",
"react-native.mjs",
"glamorous.jsx",
"lit-css.mjs",
"styled-components.js",
"styled-opts.mjs",
"tpl-decl.mjs",
"tpl-in-tpl.mjs",
"tpl-selector.mjs",
"tpl-decl.mjs",
"tpl-special.mjs",
].forEach(file => {
it(file, () => {
Expand Down