Skip to content

Commit

Permalink
add: transform css object right
Browse files Browse the repository at this point in the history
  • Loading branch information
futurist committed Dec 22, 2016
1 parent 4dd2079 commit 9ca8737
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 67 deletions.
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"plugins": ["./transform-plugins"],
"plugins": ["./index"],
"ignore": ["node_modules"]
}
77 changes: 48 additions & 29 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,33 @@
// Babel plugin to transform class names into cssobj localized

var util = require('util')
var converter = require('cssobj-converter')
var yaml = require('js-yaml')
var templateDelimiter = '_cssobj_template_delimiter_'

function transformObjecctToFunction(babel, code) {
return babel.transform(code, {
plugins: ['./object-to-function']
}).code
var result = babel.transform('!'+code, {
plugins: ['./transform-plugins']
})
console.log(result.code)
// .cssobjConfig, cssobjImports
return result.ast.program
}

module.exports = function (babel) {
var t = babel.types

var transformClassVisitor = {
JSXAttribute (path) {
var node = path.node
if (!node.name || !node.value || ['className', 'class'].indexOf(node.name.name)<0) return
// get the right mapClass arguments
var exp = t.isJSXExpressionContainer(node.value)
? node.value.expression
: node.value
// transform ExpressionContainer to be result.mapClass(exp)
var callee = t.isMemberExpression(this.callee)
? t.memberExpression(this.callee.object, t.identifier('mapClass'))
: this.callee
node.value = t.jSXExpressionContainer (
t.callExpression(callee, [exp])
)
}
}
return {
inherits: require('babel-plugin-syntax-jsx'),
visitor: {
Program(path){
// console.log(util.inspect(path, {showHidden: false, depth: 5}))
},
TaggedTemplateExpression (path, state) {
var source = path.scope.hub.file.code
var source = path.hub.file.code
var cssobjName = state.cssobjName || (state.opts && state.opts.cssobjName)
var node = path.node
// console.log(path)
var yamlRe = /\n\s*---\s*\n/
if(t.isIdentifier(node.tag, {name: 'CSSOBJ'})) {
var texts = node.quasi.quasis.map(function(v) {
Expand All @@ -49,9 +37,9 @@ module.exports = function (babel) {
return source.substring(v.start, v.end)
})
// it's cssobj template
var i = 0, options
var i = 0, cssobjConfig, cssobjConfigNode
if (texts[0].search(yamlRe)===0) {
// options parser
// config parser
texts[0] = texts[0].replace(yamlRe, '\n')
var yamlArr = [], pos
for (i=0; i<texts.length; i++) {
Expand All @@ -64,20 +52,32 @@ module.exports = function (babel) {
yamlArr.push(texts[i])
}
}
options = yaml.load(yamlArr.join(templateDelimiter))
if(options) {
options = JSON.stringify(options)
.split('"'+templateDelimiter+'"')
cssobjConfig = yaml.load(yamlArr.join(templateDelimiter))
if(cssobjConfig) {
cssobjConfig = util.inspect(cssobjConfig, {depth:null})
.split('\''+templateDelimiter+'\'')
.map(function(v,i,arr) {
if(i==arr.length-1) return v
return v + exps.shift()
})
.join('')
cssobjConfigNode = transformObjecctToFunction(babel, cssobjConfig)
path.hub.file.path.unshiftContainer('body', cssobjConfigNode.cssobjImports)
}
// console.log(yamlArr, options, 111, texts[i])
// console.log(yamlArr, config, 111, texts[i])
texts = texts.slice(i)
}
console.log(options, texts)

// css object transform
var obj = converter(texts.join(templateDelimiter))
var objStr = util.inspect(obj, {depth: null})
.split('\''+templateDelimiter+'\'')
.map(function(v,i,arr) {
if(i==arr.length-1) return v
return v + exps.shift()
})
.join('')
console.log(objStr)
}
},
CallExpression (path, state) {
Expand All @@ -99,4 +99,23 @@ module.exports = function (babel) {
}
}
}

var transformClassVisitor = {
JSXAttribute (path) {
var node = path.node
if (!node.name || !node.value || ['className', 'class'].indexOf(node.name.name)<0) return
// get the right mapClass arguments
var exp = t.isJSXExpressionContainer(node.value)
? node.value.expression
: node.value
// transform ExpressionContainer to be result.mapClass(exp)
var callee = t.isMemberExpression(this.callee)
? t.memberExpression(this.callee.object, t.identifier('mapClass'))
: this.callee
node.value = t.jSXExpressionContainer (
t.callExpression(callee, [exp])
)
}
}

}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"mocha-lcov-reporter": "^1.2.0"
},
"dependencies": {
"babel-plugin-syntax-jsx": "^6.18.0"
"babel-plugin-syntax-jsx": "^6.18.0",
"cssobj-converter": "^2.1.6"
}
}
20 changes: 10 additions & 10 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,23 @@ describe('transform-plugins', () => {
}

it('should transform plugins literal, should not transform non-literal', () => {
let node = `!{plugins: [{'default-unit-234': 'px'}, {selector: abc}]}`
let node = `!{"plugins": [{'default-unit-234': 'px'}, {selector: abc}]}`
expect(lib(node)).to.equal(`import cssobj_plugin_default_unit_234 from 'cssobj-plugin-default-unit-234';
!{ plugins: [cssobj_plugin_default_unit_234('px'), { selector: abc }] };`)
!{ "plugins": [cssobj_plugin_default_unit_234('px'), { selector: abc }] };`)

node = `!{plugins: [{'default-unit-234': 'px'}, {'localize': {space:'_my_'}}]}`
node = `!{"plugins": [{'default-unit-234': 'px'}, {'localize': {space:'_my_'}}]}`
expect(lib(node)).to.equal(`import cssobj_plugin_localize from 'cssobj-plugin-localize';
import cssobj_plugin_default_unit_234 from 'cssobj-plugin-default-unit-234';
!{ plugins: [cssobj_plugin_default_unit_234('px'), cssobj_plugin_localize({ space: '_my_' })] };`)
!{ "plugins": [cssobj_plugin_default_unit_234('px'), cssobj_plugin_localize({ space: '_my_' })] };`)
})

it('should work with empty or non-plugins', () => {
let node = `!{plugins: null}`
expect(lib(node)).to.equal(`!{ plugins: null };`)
node = `!{plugins: []}`
expect(lib(node)).to.equal(`!{ plugins: [] };`)
node = `!{plugins: {abc: 'def'}}`
expect(lib(node)).to.equal(`!{ plugins: { abc: 'def' } };`)
let node = `!{"plugins": null}`
expect(lib(node)).to.equal(`!{ "plugins": null };`)
node = `!{"plugins": []}`
expect(lib(node)).to.equal(`!{ "plugins": [] };`)
node = `!{"plugins": {abc: 'def'}}`
expect(lib(node)).to.equal(`!{ "plugins": { abc: 'def' } };`)
})
})

Expand Down
56 changes: 30 additions & 26 deletions transform-plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,49 @@ module.exports = function (babel) {

return {
visitor: {
Program (path) {
Program (path, state) {
var firstExp = path.node.body[0]

// only transform !{plugins:[]}
if(!t.isExpressionStatement(firstExp)
|| !t.isUnaryExpression(firstExp.expression, {operator: '!'})
|| !t.isObjectExpression(firstExp.expression.argument)) return

// get target expression
var node = firstExp.expression.argument
// get plugins prop
// get "plugins" prop, it's from JSON.stringify
var pluginsNode = node.properties.filter(function(v) {
return t.isIdentifier(v.key, {name: 'plugins'})
return t.isLiteral(v.key, {value: 'plugins'})
&& t.isArrayExpression(v.value)
}).shift()
if(!pluginsNode) return
// only transform literal keys with plugin names
var elements = pluginsNode.value.elements
for (var v, i = 0; i < elements.length; i++) {
v = elements[i]
if (t.isObjectExpression(v)
&& v.properties.length == 1
&& t.isLiteral(v.properties[0].key)
// plugin name cannot be below keywords
&& ['selector', 'value', 'post'].indexOf(v.properties[0].key.value) < 0) {
var prop = v.properties[0].key.value
var pluginIden = 'cssobj_plugin_' + prop.replace(/-/g, '_')
var value = v.properties[0].value
elements[i] = t.callExpression(
t.identifier(pluginIden),
value ? [value] : []
)
path.unshiftContainer(
'body',
t.importDeclaration(

// plugins transform part
if (pluginsNode) {
// only transform literal keys with plugin names
var elements = pluginsNode.value.elements
var cssobjImports = path.node.cssobjImports = []
for (var v, i = 0; i < elements.length; i++) {
v = elements[i]
if (t.isObjectExpression(v)
&& v.properties.length == 1
&& t.isLiteral(v.properties[0].key)
// plugin name cannot be below keywords
&& ['selector', 'value', 'post'].indexOf(v.properties[0].key.value) < 0) {
var prop = v.properties[0].key.value
var pluginIden = 'cssobj_plugin_' + prop.replace(/-/g, '_')
var value = v.properties[0].value
elements[i] = t.callExpression(
t.identifier(pluginIden),
value ? [value] : []
)
cssobjImports.push(t.importDeclaration(
[t.importDefaultSpecifier(t.identifier(pluginIden))],
t.stringLiteral('cssobj-plugin-'+prop)
)
)
))
}
}
path.node.cssobjConfig = node
}

}
}
}
Expand Down

0 comments on commit 9ca8737

Please sign in to comment.