diff --git a/lib/helpers.js b/lib/helpers.js index bc0ef9e9..d0a6d512 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -22,12 +22,26 @@ function propToStr (key, val) { function objToStr(obj) { const keys = Object.keys(obj); - if (!keys.length) { return ''; } + if (!keys.length) { return '{}'; } return `{ ${keys.map(k => propToStr(k, obj[k])).join(', ')} }`; } +function styleToObj(style) { + if (typeof style === 'string') { + return style.split(';').reduce((acc, st) => { + if (st.length) { + var prop = st.split(':'); + acc[prop[0]] = prop[1]; + } + return acc; + }, {}); + } + return style; +} + module.exports = { objToStr, arrToStr, + styleToObj, valToStr }; diff --git a/lib/index.js b/lib/index.js index e8dc9893..56750851 100644 --- a/lib/index.js +++ b/lib/index.js @@ -4,6 +4,7 @@ var pascalCase = require('pascal-case'); var reactMappings = require('./reactMappings'); var valToStr = require('./helpers').valToStr; +var styleToObj = require('./helpers').styleToObj; var plugins = require('./plugins'); @@ -17,12 +18,12 @@ function JSXNode(tag, props, children) { } var propsToStr = props => Object.keys(props).reduce((acc, k) => { - if (typeof props[k] === 'string') { - return acc + ` ${k}=${valToStr(props[k])}` - } else { - return acc + ` ${k}={${valToStr(props[k])}}` - } - }, ''); + if (typeof props[k] === 'string') { + return acc + ` ${k}=${valToStr(props[k])}` + } else { + return acc + ` ${k}={${valToStr(props[k])}}` + } +}, ''); var tagToClass = tag => reactMappings[tag] ? tag : pascalCase(tag); JSXNode.prototype.toString = function() { @@ -43,7 +44,8 @@ JSXNode.prototype.toString = function() { }; function Transformer(options) { - this.plugins = plugins.defaultPlugins; + this.plugins = []; + this.use(plugins.defaultPlugins); this.bemNaming = bn(options.naming || 'react'); } @@ -51,6 +53,7 @@ Transformer.prototype.process = function(bemjson) { var nodes = [{ json: bemjson, id: 0, + blockName: '', tree: [] }]; var root = nodes[0]; @@ -61,11 +64,12 @@ Transformer.prototype.process = function(bemjson) { if (Array.isArray(json)) { for (i = 0; i < json.length; i++) { - nodes.push({ json: json[i], id: i, tree: node.tree }); + nodes.push({ json: json[i], id: i, tree: node.tree, blockName: node.blockName}); } } else { var res = undefined; var jsx = new JSXNode(); + var blockName = json.block || node.blockName; if (typeof json === 'string') { jsx.isText = true; @@ -74,17 +78,18 @@ Transformer.prototype.process = function(bemjson) { if (json.tag) { jsx.tag = json.tag; - } else if (json.block) { - jsx.bemEntity = new BemEntity({block: json.block, elem: json.elem}); + } else if (json.block || json.elem) { + jsx.bemEntity = new BemEntity({ block: blockName, elem: json.elem }); jsx.tag = this.bemNaming.stringify(jsx.bemEntity); } for (i = 0; i < this.plugins.length; i++) { var plugin = this.plugins[i]; - res = plugin(jsx, json); + res = plugin(jsx, Object.assign({ block: blockName }, json)); if (res !== undefined) { json = res; node.json = json; + node.blockName = blockName; nodes.push(node); break; } @@ -94,11 +99,13 @@ Transformer.prototype.process = function(bemjson) { var content = json.content; if (content) { if (Array.isArray(content)) { + // flatten + json.content = content = content.concat.apply([], content); for (i = 0; i < content.length; i++) { - nodes.push({ json: content[i], id: i, tree: jsx.children }); + nodes.push({ json: content[i], id: i, tree: jsx.children, blockName: blockName }); } } else { - nodes.push({ json: content, id: 'children', tree: jsx}); + nodes.push({ json: content, id: 'children', tree: jsx, blockName: blockName }); } } else { jsx.children = undefined; @@ -119,7 +126,7 @@ Transformer.prototype.process = function(bemjson) { }; Transformer.prototype.use = function() { - [].push.apply(this.plugins, arguments) + this.plugins = [].concat.apply(this.plugins, arguments) return this; }; @@ -134,5 +141,7 @@ Transformer.prototype.Transformer = Transformer; module.exports = function(opts) { return new Transformer(opts || {}); }; + module.exports.tagToClass = tagToClass; module.exports.plugins = plugins; +module.exports.styleToObj = styleToObj; diff --git a/lib/plugins.js b/lib/plugins.js index fd108038..04bae475 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -1,3 +1,4 @@ +var styleToObj = require('./helpers').styleToObj; module.exports.defaultPlugins = [ function copyMods(jsx, bemjson) { @@ -8,9 +9,19 @@ module.exports.defaultPlugins = [ Object.keys(bemjson).forEach(k => { if(~blackList.indexOf(k)) { return; } + if(k === 'attrs') { + bemjson[k]['style'] && (jsx.props['style'] = bemjson[k]['style']); + } jsx.props[k] = bemjson[k]; }); + }, + function stylePropToObj(jsx) { + if (jsx.props['style']) { + jsx.props['style'] = styleToObj(jsx.props['style']) + jsx.props['attrs'] && + (jsx.props['attrs']['style'] = jsx.props['style']); + } } ]; @@ -24,3 +35,4 @@ module.exports.whiteList = function(options) { } } }; + diff --git a/package.json b/package.json index 306a961a..ac6f6dde 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ }, "homepage": "https://github.com/bem-sdk/bemjson-to-jsx#readme", "dependencies": { - "@bem/entity-name": "^1.4.0", + "@bem/entity-name": "github:bem-sdk/bem-entity-name", "@bem/naming": "^2.0.0-6", "pascal-case": "^2.0.1" } diff --git a/test/helpers.js b/test/helpers.js index 1db9c0a4..539138d9 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -1,6 +1,8 @@ const expect = require('chai').expect; -const objToStr = require('../lib/helpers').objToStr; +const helpers = require('../lib/helpers'); +const objToStr = helpers.objToStr; +const styleToObj = helpers.styleToObj; describe('helpers: objToStr', () => { @@ -8,8 +10,8 @@ describe('helpers: objToStr', () => { expect(objToStr({ hello: 'world' })).to.equal('{ \'hello\': \'world\' }'); }); - it('should return empty string for empty obj', () => { - expect(objToStr({})).to.equal(''); + it('should return empty obj for empty obj', () => { + expect(objToStr({})).to.equal('{}'); }); it('should process many keys', () => { @@ -58,3 +60,15 @@ describe('helpers: objToStr', () => { }); }); }); + +describe('helpers: styleToObj', () => { + it('should transform style string to style obj', () => { + var obj = styleToObj('width:200px;height:100px;'); + expect(obj).to.eql({ width: '200px', height: '100px' }); + }); + + it('should not transform style obj to smth else', () => { + var obj = styleToObj({ width: '200px', height: '100px' }); + expect(obj).to.eql({ width: '200px', height: '100px' }); + }); +}); diff --git a/test/index.js b/test/index.js index 456e34c9..bccf2262 100644 --- a/test/index.js +++ b/test/index.js @@ -99,6 +99,12 @@ describe('transform', () => { ).to.equal(`\n\n\n`); }); + it('should transform elem in context of block', () => { + expect( + transform({ block: 'button2', content: { elem: 'text', content: 'Hello' } }).JSX + ).to.equal(`\n\nHello\n\n`); + }); + it('should treat mods as props', () => { expect( transform({ block: 'button2', mods: {theme: 'normal', size: 's'} }).JSX diff --git a/test/plugins.js b/test/plugins.js index 9c707112..ff7465bd 100644 --- a/test/plugins.js +++ b/test/plugins.js @@ -1,16 +1,14 @@ const expect = require('chai').expect; var T = require('../lib'); -var transformer = T(); var BemEntity = require('@bem/entity-name'); -// var transform = transformer.process.bind(transformer); describe('pluginis', () => { describe('whiteList', () => { it('without opts', () => { - var res = transformer + var res = T() .use(T.plugins.whiteList()) .process({ block: 'button2' }); @@ -20,7 +18,7 @@ describe('pluginis', () => { }); it('whiteList', () => { - var res = transformer + var res = T() .use(T.plugins.whiteList({ entities: [{ block: 'button2' }].map(BemEntity.create) })) .process({ block: 'button2', content: [{ block: 'menu' }, { block: 'selec' }] }); @@ -30,4 +28,22 @@ describe('pluginis', () => { }); }); + describe('stylePropToObj', () => { + it('styleProp to obj', () => { + var res = T().process({ block: 'button2', style: 'width:200px' }); + + expect(res.JSX).to.equal( + `` + ); + }); + + it('attrs style to obj', () => { + var res = T().process({ block: 'button2', attrs: { style: 'width:200px' } }); + + expect(res.JSX).to.equal( + `` + ); + }); + }); + });