Skip to content

Commit

Permalink
add: transform template work right
Browse files Browse the repository at this point in the history
  • Loading branch information
futurist committed Dec 22, 2016
1 parent 9ca8737 commit 1020d48
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 64 deletions.
111 changes: 60 additions & 51 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,46 @@ var converter = require('cssobj-converter')
var yaml = require('js-yaml')
var templateDelimiter = '_cssobj_template_delimiter_'

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

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

return {
inherits: require('babel-plugin-syntax-jsx'),
visitor: {
Program(path){
Program (path) {
// console.log(util.inspect(path, {showHidden: false, depth: 5}))
},
TaggedTemplateExpression (path, state) {
var source = path.hub.file.code
var root = path.hub.file
var source = root.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) {
if (t.isIdentifier(node.tag, {name: 'CSSOBJ'})) {
var texts = node.quasi.quasis.map(function (v) {
return v.value.raw
})
var exps = node.quasi.expressions.map(function(v) {
var exps = node.quasi.expressions.map(function (v) {
return source.substring(v.start, v.end)
})
// it's cssobj template
var i = 0, cssobjConfig, cssobjConfigNode
if (texts[0].search(yamlRe)===0) {
var i = 0, cssobjConfig, cssobjConfigNode, config = '{}'
if (texts[0].search(yamlRe) === 0) {
// config parser
texts[0] = texts[0].replace(yamlRe, '\n')
var yamlArr = [], pos
for (i=0; i<texts.length; i++) {
for (i = 0; i < texts.length; i++) {
pos = texts[i].search(yamlRe)
if(pos>-1) {
if (pos > -1) {
yamlArr.push(texts[i].substr(0, pos))
texts[i] = texts[i].substr(pos).replace(yamlRe, '')
break
Expand All @@ -53,16 +53,17 @@ module.exports = function (babel) {
}
}
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
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)
root.path.unshiftContainer('body', cssobjConfigNode.ast.program.cssobjImports)
config = cssobjConfigNode.code.substr(1).replace(/;+$/, '')
}
// console.log(yamlArr, config, 111, texts[i])
texts = texts.slice(i)
Expand All @@ -71,13 +72,20 @@ module.exports = function (babel) {
// 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)
.split('\'' + templateDelimiter + '\'')
.map(function (v, i, arr) {
if (i == arr.length - 1) return v
return v + exps.shift()
})
.join('')
// got css object
// console.log(objStr)
root.path.unshiftContainer('body', t.importDeclaration(
[t.importDefaultSpecifier(t.identifier('cssobj'))],
t.stringLiteral('cssobj')
))

path.replaceWithSourceString(`cssobj(${config}, ${objStr})`)
}
},
CallExpression (path, state) {
Expand All @@ -87,35 +95,36 @@ module.exports = function (babel) {
var args = path.node.arguments
// this form: result.mapClass(JSX)
// or this form: customName(JSX)
if((t.isMemberExpression(callee)
&& !callee.computed
&& t.isIdentifier(callee.property, {name: mapName || 'mapClass'})
||
mapName && t.isIdentifier(callee, {name: mapName}))
&& t.isJSXElement(args[0])) {
path.traverse(transformClassVisitor, { callee: callee, mapName: mapName })
if ((t.isMemberExpression(callee)
&& !callee.computed
&& t.isIdentifier(callee.property, {name: mapName || 'mapClass'})
||
mapName && t.isIdentifier(callee, {name: mapName}))
&& t.isJSXElement(args[0])) {
path.traverse(transformClassVisitor(), { callee: callee, mapName: mapName })
path.replaceWith(args[0])
}
}
}
}

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])
)
function transformClassVisitor () {
return {
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])
)
}
}
}

}
14 changes: 8 additions & 6 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ describe('transform-plugins', () => {
}).code
}

it('should transform plugins literal, should not transform non-literal', () => {
it('should transform plugins literal, should not transform keywords', () => {
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 }] };`)
expect(lib(node)).to.equal(`!{ "plugins": [cssobj_plugin_default_unit_234('px'), { selector: abc }] };`)

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_' })] };`)
expect(lib(node)).to.equal(`!{ "plugins": [cssobj_plugin_default_unit_234('px'), cssobj_plugin_localize({ space: '_my_' })] };`)
})

it('should transform plugins literal without options', () => {
let node = `!{"plugins": [{'default-unit-234': 'px'}, 'flexbox']}`
expect(lib(node)).to.equal(`!{ "plugins": [cssobj_plugin_default_unit_234('px'), cssobj_plugin_flexbox()] };`)
})

it('should work with empty or non-plugins', () => {
Expand Down
23 changes: 16 additions & 7 deletions transform-plugins.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// transform from object into cssobj config, with plugins transformed

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

Expand All @@ -14,8 +16,9 @@ module.exports = function (babel) {
// get target expression
var node = firstExp.expression.argument
// get "plugins" prop, it's from JSON.stringify

var pluginsNode = node.properties.filter(function(v) {
return t.isLiteral(v.key, {value: 'plugins'})
return getKeyValue(v, 'plugins')
&& t.isArrayExpression(v.value)
}).shift()

Expand All @@ -24,16 +27,16 @@ module.exports = function (babel) {
// 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++) {
for (var v, prop, value, i = 0; i < elements.length; i++) {
v = elements[i]
if (t.isObjectExpression(v)
if (t.isLiteral(v) && (value='', prop = v.value)
|| t.isObjectExpression(v)
&& v.properties.length == 1
&& t.isLiteral(v.properties[0].key)
&& (prop = getKeyValue(v.properties[0]))
// plugin name cannot be below keywords
&& ['selector', 'value', 'post'].indexOf(v.properties[0].key.value) < 0) {
var prop = v.properties[0].key.value
&& ['selector', 'value', 'post'].indexOf(prop) < 0
&& (value = v.properties[0].value)) {
var pluginIden = 'cssobj_plugin_' + prop.replace(/-/g, '_')
var value = v.properties[0].value
elements[i] = t.callExpression(
t.identifier(pluginIden),
value ? [value] : []
Expand All @@ -49,4 +52,10 @@ module.exports = function (babel) {
}
}
}

function getKeyValue (v, name) {
if (t.isLiteral(v.key, name ? {value: name}: {})) return v.key.value
if (t.isIdentifier(v.key, name ? {name: name}: {})) return v.key.name
}

}

0 comments on commit 1020d48

Please sign in to comment.