From 1020d48f2eee560af927b6cb0149a1af621ecce4 Mon Sep 17 00:00:00 2001 From: 1111hui <26634873@qq.com> Date: Thu, 22 Dec 2016 15:06:19 +0800 Subject: [PATCH] add: transform template work right --- index.js | 111 +++++++++++++++++++++++-------------------- test/test.js | 14 +++--- transform-plugins.js | 23 ++++++--- 3 files changed, 84 insertions(+), 64 deletions(-) diff --git a/index.js b/index.js index 4c4c7d7..0b119b8 100644 --- a/index.js +++ b/index.js @@ -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-1) { + if (pos > -1) { yamlArr.push(texts[i].substr(0, pos)) texts[i] = texts[i].substr(pos).replace(yamlRe, '') break @@ -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) @@ -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) { @@ -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]) + ) + } } } - } diff --git a/test/test.js b/test/test.js index ca82b28..f8e58be 100644 --- a/test/test.js +++ b/test/test.js @@ -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', () => { diff --git a/transform-plugins.js b/transform-plugins.js index 319d80c..7774d2b 100644 --- a/transform-plugins.js +++ b/transform-plugins.js @@ -1,3 +1,5 @@ +// transform from object into cssobj config, with plugins transformed + module.exports = function (babel) { var t = babel.types @@ -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() @@ -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] : [] @@ -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 + } + }