Skip to content

Commit

Permalink
Fix support for styled options (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
gucong3000 committed Dec 29, 2018
1 parent 9224e76 commit db6975a
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 46 deletions.
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

0 comments on commit db6975a

Please sign in to comment.