Skip to content

Commit

Permalink
Use XO for linting
Browse files Browse the repository at this point in the history
  • Loading branch information
leo committed Dec 5, 2016
1 parent 42adc71 commit 65ff822
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 63 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# styled-jsx

[![Build Status](https://travis-ci.org/zeit/styled-jsx.svg?branch=master)](https://travis-ci.org/zeit/styled-jsx)
[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](/~https://github.com/sindresorhus/xo)
[![Slack Channel](https://zeit-slackin.now.sh/badge.svg)](https://zeit.chat)

Full, scoped and component-friendly CSS support for JSX (SSR + browser).
Expand Down
72 changes: 36 additions & 36 deletions babel.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,30 @@ const STYLE_ATTRIBUTE = 'jsx'
const MARKUP_ATTRIBUTE = 'data-jsx'
const INJECT_METHOD = '_jsxStyleInject'

export default function ({ types: t }) {

const findStyles = (children) => (
children.filter((el) => (
export default function ({types: t}) {
const findStyles = children => (
children.filter(el => (
t.isJSXElement(el) &&
el.openingElement.name.name === 'style' &&
el.openingElement.attributes.some((attr) => (
el.openingElement.attributes.some(attr => (
attr.name.name === STYLE_ATTRIBUTE
))
))
)

const getExpressionText = (expr) => (
t.isTemplateLiteral(expr)
? expr.quasis[0].value.raw
const getExpressionText = expr => (
t.isTemplateLiteral(expr) ?
expr.quasis[0].value.raw :
// assume string literal
: expr.value
expr.value
)

return {
inherits: jsx,
visitor: {
JSXOpeningElement (path, state) {
JSXOpeningElement(path, state) {
if (state.hasJSXStyle) {
if (null == state.ignoreClosing) {
if (state.ignoreClosing === null) {
// this flag has a two-fold purpose:
// - ignore the opening tag of the parent element
// of the style tag, since we don't want to add
Expand All @@ -44,7 +43,7 @@ export default function ({ types: t }) {

const el = path.node

if (el.name && 'style' !== el.name.name) {
if (el.name && el.name.name !== 'style') {
for (const attr of el.attributes) {
if (attr.name === MARKUP_ATTRIBUTE) {
// avoid double attributes
Expand All @@ -64,45 +63,47 @@ export default function ({ types: t }) {
}
},
JSXElement: {
enter (path, state) {
if (null == state.hasJSXStyle) {
enter(path, state) {
if (state.hasJSXStyle === null) {
const styles = findStyles(path.node.children)
if (styles.length) {

if (styles.length > 0) {
state.jsxId = ''
state.styles = []
for (const style of styles) {
if (style.children.length !== 1) {
throw path.buildCodeFrameError(`Expected a child under `
+ `JSX Style tag, but got ${style.children.length} `
+ `(eg: <style jsx>{\`hi\`}</style>)`)
throw path.buildCodeFrameError(`Expected a child under ` +
`JSX Style tag, but got ${style.children.length} ` +
`(eg: <style jsx>{\`hi\`}</style>)`)
}

const child = style.children[0]

if (!t.isJSXExpressionContainer(child)) {
throw path.buildCodeFrameError(`Expected a child of `
+ `type JSXExpressionContainer under JSX Style tag `
+ `(eg: <style jsx>{\`hi\`}</style>), got ${child.type}`)
throw path.buildCodeFrameError(`Expected a child of ` +
`type JSXExpressionContainer under JSX Style tag ` +
`(eg: <style jsx>{\`hi\`}</style>), got ${child.type}`)
}

const expression = child.expression

if (!t.isTemplateLiteral(child.expression) &&
!t.isStringLiteral(child.expression)) {
throw path.buildCodeFrameError(`Expected a template `
+ `literal or String literal as the child of the `
+ `JSX Style tag (eg: <style jsx>{\`some css\`}</style>),`
+ ` but got ${expression.type}`)
throw path.buildCodeFrameError(`Expected a template ` +
`literal or String literal as the child of the ` +
`JSX Style tag (eg: <style jsx>{\`some css\`}</style>),` +
` but got ${expression.type}`)
}

const styleText = getExpressionText(expression)
const styleId = '' + murmurHash(styleText)
const styleId = String(murmurHash(styleText))
state.styles.push([
styleId,
styleText
])
}
state.jsxId += murmurHash(state.styles.map((s) => s[1]).join(''))

state.jsxId += murmurHash(state.styles.map(s => s[1]).join(''))
state.hasJSXStyle = true
state.file.hasJSXStyle = true
// next visit will be: JSXOpeningElement
Expand All @@ -111,7 +112,8 @@ export default function ({ types: t }) {
}
} else if (state.hasJSXStyle) {
const el = path.node.openingElement
if (el.name && 'style' === el.name.name) {

if (el.name && el.name.name === 'style') {
// we replace styles with the function call
const [id, css] = state.styles.shift()
path.replaceWith(
Expand All @@ -128,31 +130,29 @@ export default function ({ types: t }) {
}
}
},

exit (path, state) {
exit(path, state) {
if (state.hasJSXStyle && !--state.ignoreClosing) {
state.hasJSXStyle = null
}
}
},
Program: {
enter (path, state) {
enter(path, state) {
state.file.hasJSXStyle = false
},

exit ({ node, scope }, state) {
exit({node, scope}, state) {
if (!(state.file.hasJSXStyle && !scope.hasBinding(INJECT_METHOD))) {
return
}

const importDeclaration = t.importDeclaration(
[t.importDefaultSpecifier(t.identifier(INJECT_METHOD))],
t.stringLiteral('styled-jsx/inject')
);
)

node.body.unshift(importDeclaration);
node.body.unshift(importDeclaration)
}
},
}
}
}
}
11 changes: 9 additions & 2 deletions flush.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import memory from './memory'
export default function flush () {

export default function flush() {
const ret = {}
for (let i in memory) {

for (const i in memory) {
if (!{}.hasOwnProperty.call(memory, i)) {
continue
}

ret[i] = memory[i]
delete memory[i]
}

return ret
}
9 changes: 4 additions & 5 deletions inject.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import memory from './memory'

const isBrowser = 'undefined' !== typeof window
const isBrowser = typeof window !== 'undefined'
const tags = {}

export default function inject (id, css) {
export default function inject(id, css) {
if (isBrowser) {
// if the tag is already present we ignore it!
if (!tags[id]) {
Expand All @@ -16,11 +16,10 @@ export default function inject (id, css) {
}
}

function makeStyleTag (str) {
function makeStyleTag(str) {
// based on implementation by glamor
const tag = document.createElement('style')
tag.type = 'text/css'
tag.appendChild(document.createTextNode(str))
(document.head || document.getElementsByTagName('head')[0]).appendChild(tag)
tag.appendChild(document.createTextNode(str))(document.head || document.getElementsByTagName('head')[0]).appendChild(tag)
return tag
}
24 changes: 21 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
"devDependencies": {
"ava": "^0.17.0",
"babel-cli": "^6.18.0",
"babel-preset-es2015": "^6.16.0",
"babel-plugin-transform-runtime": "^6.15.0",
"babel-preset-es2015": "^6.16.0",
"babel-preset-react": "^6.16.0",
"babel-preset-stage-3": "^6.16.0",
"babel-register": "^6.18.0",
"fs-promise": "^1.0.0"
"fs-promise": "^1.0.0",
"xo": "^0.17.1"
},
"babel": {
"presets": [
Expand All @@ -29,11 +30,28 @@
]
},
"scripts": {
"test": "ava test/styles.js"
"test": "xo && ava test/styles.js"
},
"ava": {
"require": [
"babel-register"
]
},
"xo": {
"esnext": true,
"space": true,
"semicolon": false,
"ignores": [
"lib/**",
"test/fixtures/**"
],
"envs": [
"node",
"browser"
],
"rules": {
"import/no-unresolved": 0,
"new-cap": 0
}
}
}
6 changes: 3 additions & 3 deletions test/_read.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { resolve } from 'path'
import { readFile } from 'fs-promise'
import {resolve} from 'path'
import {readFile} from 'fs-promise'

export default async (path) => {
export default async path => {
const buffer = await readFile(resolve(__dirname, path))
return buffer.toString()
}
31 changes: 19 additions & 12 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,43 @@
import test from 'ava'
// Native
import path from 'path'
import read from './_read'

// Packages
import test from 'ava'
import {transformFile} from 'babel-core'

// Ours
import plugin from '../babel'
import { transformFile } from 'babel-core'
import read from './_read'

const transform = (file) => (
const transform = file => (
new Promise((resolve, reject) => {
transformFile(path.resolve(__dirname, file), {
plugins: [
plugin
]
}, function (err, data) {
if (err) return reject(err)
}, (err, data) => {
if (err) {
return reject(err)
}
resolve(data)
})
})
)

test('works with stateless', async (t) => {
const { code } = await transform('./fixtures/stateless.js')
test('works with stateless', async t => {
const {code} = await transform('./fixtures/stateless.js')
const out = await read('./fixtures/stateless.out.js')
t.is(code, out.trim())
})

test('works with class', async (t) => {
const { code } = await transform('./fixtures/class.js')
test('works with class', async t => {
const {code} = await transform('./fixtures/class.js')
const out = await read('./fixtures/class.out.js')
t.is(code, out.trim())
})

test('ignores when attribute is absent', async (t) => {
const { code } = await transform('./fixtures/absent.js')
test('ignores when attribute is absent', async t => {
const {code} = await transform('./fixtures/absent.js')
const out = await read('./fixtures/absent.out.js')
t.is(code, out.trim())
})
8 changes: 6 additions & 2 deletions test/styles.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// Packages
import test from 'ava'
import read from './_read'

// Ours
import transform from '../lib/style-transform'
import read from './_read'

test('transpile styles with attributes', async (t) => {
test('transpile styles with attributes', async t => {
const src = await read('./fixtures/transform.css')
const out = await read('./fixtures/transform.out.css')

t.is(transform('woot', src), out.trim())
})

0 comments on commit 65ff822

Please sign in to comment.