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

Allow random expressions as long as they result in a className that begins with css #213

Merged
merged 9 commits into from
Aug 2, 2017
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
5 changes: 3 additions & 2 deletions example/.babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
}
}
],
"stage-2",
"stage-0",
"react"
],
"plugins": [
['emotion/babel']
['emotion/babel'],
"transform-class-properties"
]
}
1 change: 1 addition & 0 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"babel-core": "^6.23.1",
"babel-eslint": "^7.2.3",
"babel-loader": "^7.1.1",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-preset-env": "^1.6.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
Expand Down
11 changes: 10 additions & 1 deletion example/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,23 @@ const theme = {
gold: '#ffd43b'
}

const margin = (t, r, b, l) => {
return () => css`
margin-top: ${t}
margin-right: ${r}
margin-bottom: ${b}
margin-left: ${l}
`
}

const PlaygroundWrapper = styled('div')`
font-family: 'Oxygen', sans-serif;
flex:1;
color: #343a40;
background: #f8f9fa;

& .inner {
margin: 0 auto;
${margin(0, 'auto', 0, 'auto')};
width: calc(100% - 32px);
max-width: 960px;

Expand Down
5 changes: 3 additions & 2 deletions example/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module.exports = env => {
var loaders = [
{
test: /\.jsx?$/,
include: [/src/, /autoprefixer/, /chalk/, /ansi-styles/, /postcss-nested/],
include: [/src/, /autoprefixer/, /chalk/, /ansi-styles/, /postcss-nested/, /caniuse-lite/],
loader: 'babel-loader'
},
{
Expand Down Expand Up @@ -63,7 +63,8 @@ module.exports = env => {
publicPath: '/'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
extensions: ['.ts', '.tsx', '.js', '.jsx'],
symlinks: false
},
plugins: [
new HtmlWebpackPlugin({
Expand Down
32 changes: 28 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,18 +234,25 @@ function deconstruct (style) {
let selects
let medias
let supports

forEach(keys(style), key => {
if (key.indexOf('&') >= 0) {
selects = selects || {}
selects[key] = style[key]
selects[key] = deconstruct(style[key]).plain
} else if (key.indexOf('@media') === 0) {
medias = medias || {}
medias[key] = deconstruct(style[key])
} else if (key.indexOf('@supports') === 0) {
supports = supports || {}
supports[key] = deconstruct(style[key])
} else if (key.indexOf('css-') === 0) {
// replace fragments
plain = plain || {}
const registeredStyles = registered[key.split('css-')[1]].style
assign(plain, registeredStyles)
} else {
plain = plain || {}

plain[key] = style[key]
}
})
Expand Down Expand Up @@ -361,12 +368,24 @@ function flatten (inArr) {
}

// mutable! modifies dest.
function build (dest, { selector = '', mq = '', supp = '', src = {} }) {
function build (
dest,
{
selector = '',
mq = '',
supp = '',
src = [{}]
}: {
selector?: string,
mq?: string,
supp?: string,
src: Array<{ [string]: any }>
}
) {
if (!Array.isArray(src)) {
src = [src]
}
src = flatten(src)

forEach(src, _src => {
if (isLikeRule(_src)) {
let reg = _getRegistered(_src)
Expand All @@ -379,7 +398,12 @@ function build (dest, { selector = '', mq = '', supp = '', src = {} }) {
if (_src && _src.composes) {
build(dest, { selector, mq, supp, src: _src.composes })
}

forEach(keys(_src || {}), key => {
if (key === 'undefined') {
// drop undefined fragment results
return
}
if (isSelector(key)) {
build(dest, {
selector: joinSelectors(selector, key),
Expand Down Expand Up @@ -424,7 +448,7 @@ function build (dest, { selector = '', mq = '', supp = '', src = {} }) {
})
}

let nullrule: EmotionClassName = {
let nullrule: EmotionRule = {
// 'data-css-nil': ''
}

Expand Down
40 changes: 32 additions & 8 deletions src/parser.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// @flow
import parse from 'postcss-safe-parser'
import Input from 'postcss/lib/input'
import Declaration from 'postcss/lib/declaration'
import SafeParser from 'postcss-safe-parser/lib/safe-parser'
import postcssNested from 'postcss-nested'
import postcssJs from 'postcss-js'
import objParse from 'postcss-js/parser'
Expand All @@ -8,12 +10,6 @@ import { processStyleName } from './glamor/CSSPropertyOperations'

export const prefixer = postcssJs.sync([autoprefixer, postcssNested])

type Rule = {
parent: { selector: string, nodes: Array<mixed> },
selector: string,
remove: () => {}
}

type Decl = {
parent: { selector: string, nodes: Array<mixed> },
prop: string,
Expand All @@ -35,7 +31,7 @@ export function parseCSS (
if (typeof css === 'object') {
root = objParse(css, { from: filename })
} else {
root = parse(css, { from: filename })
root = safeParse(css, { from: filename })
}
let vars = 0
let composes: number = 0
Expand Down Expand Up @@ -89,3 +85,31 @@ export function expandCSSFallbacks (style: { [string]: any }) {
// flatten arrays which haven't been flattened yet
return flattened
}

// Parser
export function safeParse (css, opts) {
let input = new Input(css, opts)

let parser = new EmotionSafeParser(input)
parser.parse()

return parser.root
}

export class EmotionSafeParser extends SafeParser {
unknownWord (tokens: Array<Array<any>>) {
if (tokens[0][0] === 'word') {
if (/xxx(\d+)xxx/gm.exec(tokens[0][1])) {
this.init(
new Declaration(
{ prop: tokens[0][1], value: 'fragment' },
tokens[0][2],
tokens[0][3]
)
)
return
}
}
this.spaces += tokens.map(i => i[1]).join('')
}
}
20 changes: 20 additions & 0 deletions test/__snapshots__/css.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,23 @@ exports[`css null rule 1`] = `
className="css-nil"
/>
`;

exports[`css random expression 1`] = `
.glamor-0 {
font-size: 20px;
background: green;
}

@media (min-width: 420px) {
.glamor-0 {
color: blue;
width: 96px;
height: 96px;
line-height: 40px;
}
}

<div
className="glamor-0"
/>
`;
30 changes: 30 additions & 0 deletions test/__snapshots__/react.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,36 @@ exports[`styled objects with spread properties 1`] = `
</figure>
`;

exports[`styled random expressions 1`] = `
.glamor-1 {
font-size: 1rem;
margin-top: 0px;
margin-right: auto;
margin-bottom: 0px;
margin-left: auto;
color: green;
}

<h1
className="glamor-0 legacy__class glamor-1"
prop={true}
>
hello world
</h1>
`;

exports[`styled random expressions undefined return 1`] = `
.glamor-1 {
color: green;
}

<h1
className="glamor-0 legacy__class glamor-1"
>
hello world
</h1>
`;

exports[`styled themes 1`] = `
.glamor-1 {
background-color: #ffd43b;
Expand Down
40 changes: 31 additions & 9 deletions test/babel/__snapshots__/css.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -246,15 +246,37 @@ const cls2 = /*#__PURE__*/css(['one-class', 'another-class', cls1], ['center'],
exports[`babel css inline css basic 1`] = `
"
/*#__PURE__*/css([], [widthVar], function createEmotionStyledRules(x0) {
return [{
\\"margin\\": \\"12px 48px\\",
\\"color\\": \\"#ffffff; color: blue\\",
\\"display\\": \\"-webkit-box; display: -ms-flexbox; display: flex\\",
\\"WebkitBoxFlex\\": \\"1\\",
\\"msFlex\\": \\"1 0 auto\\",
\\"flex\\": \\"1 0 auto\\",
\\"width\\": \`\${x0}\`
}];
return [{
\\"margin\\": \\"12px 48px\\",
\\"color\\": \\"#ffffff; color: blue\\",
\\"display\\": \\"-webkit-box; display: -ms-flexbox; display: flex\\",
\\"WebkitBoxFlex\\": \\"1\\",
\\"msFlex\\": \\"1 0 auto\\",
\\"flex\\": \\"1 0 auto\\",
\\"@media (min-width: 420px)\\": {
\\"lineHeight\\": \\"40px\\"
},
\\"width\\": \`\${x0}\`
}];
});"
`;

exports[`babel css inline css random expression 1`] = `
"/*#__PURE__*/css([], [/*#__PURE__*/css([], [], function createEmotionStyledRules() {
return [{
\\"width\\": \\"96px\\",
\\"height\\": \\"96px\\"
}];
})], function createEmotionStyledRules(x0) {
return [{
\\"fontSize\\": \\"20px\\",
\\"@media (min-width: 420px)\\": {
\\"color\\": \\"blue\\",
[\`\${x0}\`]: \\"fragment\\",
\\"lineHeight\\": \\"26px\\"
},
\\"background\\": \\"green\\"
}];
});"
`;

Expand Down
23 changes: 23 additions & 0 deletions test/babel/__snapshots__/styled.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,29 @@ const H1 = styled('h1', 'css-13vphhj0', [{
}]);"
`;

exports[`babel styled component inline random expressions 1`] = `
"
const a = () => /*#__PURE__*/css([], [], function createEmotionStyledRules() {
return [{
\\"fontSize\\": \\"1rem\\"
}];
});
/*#__PURE__*/styled(\\"h1\\", \\"css-1ep7oc10\\", [], [/*#__PURE__*/css([], [], function createEmotionStyledRules() {
return [{
\\"fontSize\\": \\"32px\\"
}];
}), props => props.prop && a()], function createEmotionStyledRules(x0, x1) {
return [{
\\"margin\\": \\"12px 48px\\",
[\`\${x0}\`]: \\"fragment\\",
\\"color\\": \\"#ffffff\\",
\\"& .profile\\": {
[\`\${x1}\`]: \\"fragment\\"
}
}];
});"
`;

exports[`babel styled component inline shorthand property 1`] = `
"const H1 = styled(\\"h1\\", \\"css-1o8pmqr0\\", [{
\\"fontSize\\": \`\${fontSize}\`
Expand Down
20 changes: 20 additions & 0 deletions test/babel/css.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ describe('babel css', () => {
display: flex;
flex: 1 0 auto;
color: blue;
@media(min-width: 420px) {
line-height: 40px;
}
width: \${widthVar};
\``
const { code } = babel.transform(basic, {
Expand All @@ -24,6 +27,23 @@ describe('babel css', () => {
expect(code).toMatchSnapshot()
})

test('css random expression', () => {
const basic = `css\`
font-size: 20px;
@media(min-width: 420px) {
color: blue;
\${css\`width: 96px; height: 96px;\`};
line-height: 26px;
}
background: green;
\`
`
const { code } = babel.transform(basic, {
plugins: [[plugin]]
})
expect(code).toMatchSnapshot()
})

test('nested expanded properties', () => {
const basic = `
css\`
Expand Down
Loading