diff --git a/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/__tests__/__snapshots__/index.spec.js.snap b/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/__tests__/__snapshots__/index.spec.js.snap new file mode 100644 index 000000000000..412e66e7fd76 --- /dev/null +++ b/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/__tests__/__snapshots__/index.spec.js.snap @@ -0,0 +1,660 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`jsx style plugin Processing module style assignment When css module enable 1`] = ` +"import { createElement, Component } from 'rax'; +import appScssStyleSheet from \\"./app.scss\\"; +import _styleSheetModuleStyle from './app.module.scss'; + +function _getClassName() { + var className = []; + var args = arguments[0]; + var type = Object.prototype.toString.call(args).slice(8, -1).toLowerCase(); + + if (type === 'string') { + args = args.trim(); + args && className.push(args); + } else if (type === 'array') { + args.forEach(function (cls) { + cls = _getClassName(cls).trim(); + cls && className.push(cls); + }); + } else if (type === 'object') { + for (var k in args) { + k = k.trim(); + + if (k && args.hasOwnProperty(k) && args[k]) { + className.push(k); + } + } + } + + return className.join(' ').trim(); +} + +function _getStyle(classNameExpression) { + var className = _getClassName(classNameExpression); + + var classNameArr = className.split(/\\\\s+/); + var style = {}; + classNameArr.reduce((sty, cls) => Object.assign(sty, _styleSheet[cls.trim()]), style); + return style; +} + +function _getModuleClassName(moduleStyle, styleId) { + return Object.keys(moduleStyle).reduce((pre, cur) => Object.assign(pre, { + [cur]: styleId + '-' + cur + }), {}); +} + +var styleSheet = _getModuleClassName(_styleSheetModuleStyle, 'styleSheet'); + +function _mergeStyles() { + var newTarget = {}; + + for (var index = 0; index < arguments.length; index++) { + var [styleSheet, rawStyleName] = arguments[index]; + + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key; + + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); + } + } + + return newTarget; +} + +var _styleSheet = _mergeStyles([appScssStyleSheet, \\"\\"], [_styleSheetModuleStyle, \\"styleSheet\\"]); + +class App extends Component { + render() { + const a = styleSheet.red; + return
; + } + +}" +`; + +exports[`jsx style plugin Processing module style conditional expression When css module enable 1`] = ` +"import { createElement, Component } from 'rax'; +import appScssStyleSheet from \\"./app.scss\\"; +import _styleSheetModuleStyle from './app.module.scss'; + +function _getClassName() { + var className = []; + var args = arguments[0]; + var type = Object.prototype.toString.call(args).slice(8, -1).toLowerCase(); + + if (type === 'string') { + args = args.trim(); + args && className.push(args); + } else if (type === 'array') { + args.forEach(function (cls) { + cls = _getClassName(cls).trim(); + cls && className.push(cls); + }); + } else if (type === 'object') { + for (var k in args) { + k = k.trim(); + + if (k && args.hasOwnProperty(k) && args[k]) { + className.push(k); + } + } + } + + return className.join(' ').trim(); +} + +function _getStyle(classNameExpression) { + var className = _getClassName(classNameExpression); + + var classNameArr = className.split(/\\\\s+/); + var style = {}; + classNameArr.reduce((sty, cls) => Object.assign(sty, _styleSheet[cls.trim()]), style); + return style; +} + +function _getModuleClassName(moduleStyle, styleId) { + return Object.keys(moduleStyle).reduce((pre, cur) => Object.assign(pre, { + [cur]: styleId + '-' + cur + }), {}); +} + +var styleSheet = _getModuleClassName(_styleSheetModuleStyle, 'styleSheet'); + +function _mergeStyles() { + var newTarget = {}; + + for (var index = 0; index < arguments.length; index++) { + var [styleSheet, rawStyleName] = arguments[index]; + + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key; + + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); + } + } + + return newTarget; +} + +var _styleSheet = _mergeStyles([appScssStyleSheet, \\"\\"], [_styleSheetModuleStyle, \\"styleSheet\\"]); + +class App extends Component { + render() { + const a = 1 ? styleSheet.red : styleSheet.blue; + return
; + } + +}" +`; + +exports[`jsx style plugin Processing module style spread and assign When css module enable 1`] = ` +"import { createElement, Component } from 'rax'; +import appScssStyleSheet from \\"./app.scss\\"; +import _styleSheetModuleStyle from './app.module.scss'; + +function _getClassName() { + var className = []; + var args = arguments[0]; + var type = Object.prototype.toString.call(args).slice(8, -1).toLowerCase(); + + if (type === 'string') { + args = args.trim(); + args && className.push(args); + } else if (type === 'array') { + args.forEach(function (cls) { + cls = _getClassName(cls).trim(); + cls && className.push(cls); + }); + } else if (type === 'object') { + for (var k in args) { + k = k.trim(); + + if (k && args.hasOwnProperty(k) && args[k]) { + className.push(k); + } + } + } + + return className.join(' ').trim(); +} + +function _getStyle(classNameExpression) { + var className = _getClassName(classNameExpression); + + var classNameArr = className.split(/\\\\s+/); + var style = {}; + classNameArr.reduce((sty, cls) => Object.assign(sty, _styleSheet[cls.trim()]), style); + return style; +} + +function _getModuleClassName(moduleStyle, styleId) { + return Object.keys(moduleStyle).reduce((pre, cur) => Object.assign(pre, { + [cur]: styleId + '-' + cur + }), {}); +} + +var styleSheet = _getModuleClassName(_styleSheetModuleStyle, 'styleSheet'); + +function _mergeStyles() { + var newTarget = {}; + + for (var index = 0; index < arguments.length; index++) { + var [styleSheet, rawStyleName] = arguments[index]; + + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key; + + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); + } + } + + return newTarget; +} + +var _styleSheet = _mergeStyles([appScssStyleSheet, \\"\\"], [_styleSheetModuleStyle, \\"styleSheet\\"]); + +class App extends Component { + render() { + const a = { ...styleSheet.red + }; + const b = a; + return
; + } + +}" +`; + +exports[`jsx style plugin Processing module style through call expression When css module enable 1`] = ` +"import { createElement, Component } from 'rax'; +import _styleSheetModuleStyle from './app.module.scss'; + +function _getClassName() { + var className = []; + var args = arguments[0]; + var type = Object.prototype.toString.call(args).slice(8, -1).toLowerCase(); + + if (type === 'string') { + args = args.trim(); + args && className.push(args); + } else if (type === 'array') { + args.forEach(function (cls) { + cls = _getClassName(cls).trim(); + cls && className.push(cls); + }); + } else if (type === 'object') { + for (var k in args) { + k = k.trim(); + + if (k && args.hasOwnProperty(k) && args[k]) { + className.push(k); + } + } + } + + return className.join(' ').trim(); +} + +function _getStyle(classNameExpression) { + var className = _getClassName(classNameExpression); + + var classNameArr = className.split(/\\\\s+/); + var style = {}; + classNameArr.reduce((sty, cls) => Object.assign(sty, _styleSheet[cls.trim()]), style); + return style; +} + +function _getModuleClassName(moduleStyle, styleId) { + return Object.keys(moduleStyle).reduce((pre, cur) => Object.assign(pre, { + [cur]: styleId + '-' + cur + }), {}); +} + +var styleSheet = _getModuleClassName(_styleSheetModuleStyle, 'styleSheet'); + +function _mergeStyles() { + var newTarget = {}; + + for (var index = 0; index < arguments.length; index++) { + var [styleSheet, rawStyleName] = arguments[index]; + + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key; + + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); + } + } + + return newTarget; +} + +var _styleSheet = _mergeStyles([_styleSheetModuleStyle, \\"styleSheet\\"]); + +class App extends Component { + render() { + const a = Object.assign({}, styleSheet.red); + const b = Object.assign({}, a); + return
; + } + +}" +`; + +exports[`jsx style plugin Processing multiple module style When css module enable 1`] = ` +"import { createElement, Component } from 'rax'; +import _styleSheetModuleStyle from './app.module.scss'; +import _styleSheet2ModuleStyle from './app2.module.scss'; + +function _getClassName() { + var className = []; + var args = arguments[0]; + var type = Object.prototype.toString.call(args).slice(8, -1).toLowerCase(); + + if (type === 'string') { + args = args.trim(); + args && className.push(args); + } else if (type === 'array') { + args.forEach(function (cls) { + cls = _getClassName(cls).trim(); + cls && className.push(cls); + }); + } else if (type === 'object') { + for (var k in args) { + k = k.trim(); + + if (k && args.hasOwnProperty(k) && args[k]) { + className.push(k); + } + } + } + + return className.join(' ').trim(); +} + +function _getStyle(classNameExpression) { + var className = _getClassName(classNameExpression); + + var classNameArr = className.split(/\\\\s+/); + var style = {}; + classNameArr.reduce((sty, cls) => Object.assign(sty, _styleSheet[cls.trim()]), style); + return style; +} + +function _getModuleClassName(moduleStyle, styleId) { + return Object.keys(moduleStyle).reduce((pre, cur) => Object.assign(pre, { + [cur]: styleId + '-' + cur + }), {}); +} + +var styleSheet = _getModuleClassName(_styleSheetModuleStyle, 'styleSheet'); + +var styleSheet2 = _getModuleClassName(_styleSheet2ModuleStyle, 'styleSheet2'); + +function _mergeStyles() { + var newTarget = {}; + + for (var index = 0; index < arguments.length; index++) { + var [styleSheet, rawStyleName] = arguments[index]; + + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key; + + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); + } + } + + return newTarget; +} + +var _styleSheet = _mergeStyles([_styleSheetModuleStyle, \\"styleSheet\\"], [_styleSheet2ModuleStyle, \\"styleSheet2\\"]); + +class App extends Component { + render() { + const a = styleSheet.red; + return
; + } + +}" +`; + +exports[`jsx style plugin Provide a default stylesheet object when css module enable and import css module sheet only 1`] = ` +"import { createElement, Component } from 'rax'; +import _styleSheetModuleStyle from './app.module.scss'; + +function _getClassName() { + var className = []; + var args = arguments[0]; + var type = Object.prototype.toString.call(args).slice(8, -1).toLowerCase(); + + if (type === 'string') { + args = args.trim(); + args && className.push(args); + } else if (type === 'array') { + args.forEach(function (cls) { + cls = _getClassName(cls).trim(); + cls && className.push(cls); + }); + } else if (type === 'object') { + for (var k in args) { + k = k.trim(); + + if (k && args.hasOwnProperty(k) && args[k]) { + className.push(k); + } + } + } + + return className.join(' ').trim(); +} + +function _getStyle(classNameExpression) { + var className = _getClassName(classNameExpression); + + var classNameArr = className.split(/\\\\s+/); + var style = {}; + classNameArr.reduce((sty, cls) => Object.assign(sty, _styleSheet[cls.trim()]), style); + return style; +} + +function _getModuleClassName(moduleStyle, styleId) { + return Object.keys(moduleStyle).reduce((pre, cur) => Object.assign(pre, { + [cur]: styleId + '-' + cur + }), {}); +} + +var styleSheet = _getModuleClassName(_styleSheetModuleStyle, 'styleSheet'); + +function _mergeStyles() { + var newTarget = {}; + + for (var index = 0; index < arguments.length; index++) { + var [styleSheet, rawStyleName] = arguments[index]; + + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key; + + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); + } + } + + return newTarget; +} + +var _styleSheet = _mergeStyles([_styleSheetModuleStyle, \\"styleSheet\\"]); + +class App extends Component { + render() { + return
+
+
+
; + } + +}" +`; + +exports[`jsx style plugin combine multiple anonymous css file 1`] = ` +"import { createElement, Component } from 'rax'; +import app1CssStyleSheet from \\"./app1.css\\"; +import app2CssStyleSheet from \\"./app2.css\\"; + +function _mergeEleStyles() { + return [].concat.apply([], arguments).reduce((pre, cur) => Object.assign(pre, cur), {}); +} + +function _mergeStyles() { + var newTarget = {}; + + for (var index = 0; index < arguments.length; index++) { + var [styleSheet, rawStyleName] = arguments[index]; + + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key; + + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); + } + } + + return newTarget; +} + +var _styleSheet = _mergeStyles([app1CssStyleSheet, \\"\\"], [app2CssStyleSheet, \\"\\"]); + +class App extends Component { + render() { + return
; + } + +}" +`; + +exports[`jsx style plugin combine multiple different extension style sources 1`] = ` +"import { createElement, render } from 'rax'; +import indexCssStyleSheet from \\"./index.css\\"; +import indexScssStyleSheet from \\"./index.scss\\"; +import indexLessStyleSheet from \\"../index.less\\"; +import styl from \\"./index.styl\\"; + +function _mergeStyles() { + var newTarget = {}; + + for (var index = 0; index < arguments.length; index++) { + var [styleSheet, rawStyleName] = arguments[index]; + + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key; + + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); + } + } + + return newTarget; +} + +var _styleSheet = _mergeStyles([indexCssStyleSheet, \\"\\"], [indexScssStyleSheet, \\"\\"], [indexLessStyleSheet, \\"\\"], [styl, \\"\\"]); + +render(
);" +`; + +exports[`jsx style plugin combine multiple styles and className 1`] = ` +"import { createElement, Component } from 'rax'; +import appCssStyleSheet from \\"./app.css\\"; +import style from \\"./style.css\\"; + +function _mergeEleStyles() { + return [].concat.apply([], arguments).reduce((pre, cur) => Object.assign(pre, cur), {}); +} + +function _mergeStyles() { + var newTarget = {}; + + for (var index = 0; index < arguments.length; index++) { + var [styleSheet, rawStyleName] = arguments[index]; + + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key; + + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); + } + } + + return newTarget; +} + +var _styleSheet = _mergeStyles([appCssStyleSheet, \\"\\"], [style, \\"\\"]); + +class App extends Component { + render() { + return
; + } + +}" +`; + +exports[`jsx style plugin combine one style and className 1`] = ` +"import { createElement, Component } from 'rax'; +import appCssStyleSheet from \\"./app.css\\"; +import style from \\"./style.css\\"; + +function _mergeEleStyles() { + return [].concat.apply([], arguments).reduce((pre, cur) => Object.assign(pre, cur), {}); +} + +function _mergeStyles() { + var newTarget = {}; + + for (var index = 0; index < arguments.length; index++) { + var [styleSheet, rawStyleName] = arguments[index]; + + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key; + + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); + } + } + + return newTarget; +} + +var _styleSheet = _mergeStyles([appCssStyleSheet, \\"\\"], [style, \\"\\"]); + +class App extends Component { + render() { + return
; + } + +}" +`; + +exports[`jsx style plugin combine the same filename style source 1`] = ` +"import { createElement, Component } from 'rax'; +import appCssStyleSheet from \\"./app.css\\"; +import appCssStyleSheet from \\"../app.css\\"; + +function _mergeEleStyles() { + return [].concat.apply([], arguments).reduce((pre, cur) => Object.assign(pre, cur), {}); +} + +function _mergeStyles() { + var newTarget = {}; + + for (var index = 0; index < arguments.length; index++) { + var [styleSheet, rawStyleName] = arguments[index]; + + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key; + + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); + } + } + + return newTarget; +} + +var _styleSheet = _mergeStyles([appCssStyleSheet, \\"\\"], [appCssStyleSheet, \\"\\"]); + +class App extends Component { + render() { + return
; + } + +}" +`; + +exports[`jsx style plugin merge stylesheet when css module disable 1`] = ` +"import { createElement, Component } from 'rax'; +import appScssStyleSheet from \\"./app.scss\\"; +import styleSheet from \\"./app.module.scss\\"; + +function _mergeEleStyles() { + return [].concat.apply([], arguments).reduce((pre, cur) => Object.assign(pre, cur), {}); +} + +function _mergeStyles() { + var newTarget = {}; + + for (var index = 0; index < arguments.length; index++) { + var [styleSheet, rawStyleName] = arguments[index]; + + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key; + + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); + } + } + + return newTarget; +} + +var _styleSheet = _mergeStyles([appScssStyleSheet, \\"\\"], [styleSheet, \\"\\"]); + +class App extends Component { + render() { + return
; + } + +}" +`; diff --git a/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/__tests__/index.spec.js b/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/__tests__/index.spec.js index 3d0b2c5af08d..09ef61b5d7ec 100644 --- a/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/__tests__/index.spec.js +++ b/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/__tests__/index.spec.js @@ -3,20 +3,6 @@ import syntaxJSX from 'babel-plugin-syntax-jsx' import jSXStylePlugin from '../src/index' -const mergeStylesFunctionTemplate = `function _mergeStyles() { - var newTarget = {}; - - for (var index = 0; index < arguments.length; index++) { - var target = arguments[index]; - - for (var key in target) { - newTarget[key] = Object.assign(newTarget[key] || {}, target[key]); - } - } - - return newTarget; -}` - const getClassNameFunctionTemplate = `function _getClassName() { var className = []; var args = arguments[0]; @@ -183,22 +169,7 @@ class App extends Component { render() { return
; } -}`)).toBe(`import { createElement, Component } from 'rax'; -import app1CssStyleSheet from "./app1.css"; -import app2CssStyleSheet from "./app2.css"; - -${mergeEleStylesFunctionTemplate} - -${mergeStylesFunctionTemplate} - -var _styleSheet = _mergeStyles(app1CssStyleSheet, app2CssStyleSheet); - -class App extends Component { - render() { - return
; - } - -}`) +}`)).toMatchSnapshot() }) it('combine the same filename style source', () => { @@ -210,22 +181,7 @@ class App extends Component { render() { return
; } -}`)).toBe(`import { createElement, Component } from 'rax'; -import appCssStyleSheet from "./app.css"; -import appCssStyleSheet1 from "../app.css"; - -${mergeEleStylesFunctionTemplate} - -${mergeStylesFunctionTemplate} - -var _styleSheet = _mergeStyles(appCssStyleSheet, appCssStyleSheet1); - -class App extends Component { - render() { - return
; - } - -}`) +}`)).toMatchSnapshot() }) it('combine one style and className', () => { @@ -237,22 +193,7 @@ class App extends Component { render() { return
; } -}`)).toBe(`import { createElement, Component } from 'rax'; -import appCssStyleSheet from "./app.css"; -import style from "./style.css"; - -${mergeEleStylesFunctionTemplate} - -${mergeStylesFunctionTemplate} - -var _styleSheet = _mergeStyles(appCssStyleSheet, style); - -class App extends Component { - render() { - return
; - } - -}`) +}`)).toMatchSnapshot() }) it('combine inline style object and className', () => { @@ -292,21 +233,7 @@ class App extends Component { render() { return
; } -}`)).toBe(`import { createElement, Component } from 'rax'; -import appCssStyleSheet from "./app.css"; -import style from "./style.css"; - -${mergeEleStylesFunctionTemplate} - -${mergeStylesFunctionTemplate} - -var _styleSheet = _mergeStyles(appCssStyleSheet, style); - -class App extends Component { - render() { - return
; - }\n -}`) +}`)).toMatchSnapshot() }) it('do not transfrom code when no css file', () => { @@ -406,17 +333,7 @@ import '../index.less' import styl from './index.styl' render(
); -`)).toBe(`import { createElement, render } from 'rax'; -import indexCssStyleSheet from "./index.css"; -import indexScssStyleSheet from "./index.scss"; -import indexLessStyleSheet from "../index.less"; -import styl from "./index.styl"; - -${mergeStylesFunctionTemplate} - -var _styleSheet = _mergeStyles(indexCssStyleSheet, indexScssStyleSheet, indexLessStyleSheet, styl); - -render(
);`) +`)).toMatchSnapshot() }) it('transform styleAttribute expression', () => { expect(getTransfromCode(` @@ -472,31 +389,6 @@ render(
);`) }) - it('ignore merge stylesheet when css module enable', () => { - expect(getTransfromCode(` -import { createElement, Component } from 'rax'; -import './app.scss'; -import styleSheet from './app.module.scss'; - -class App extends Component { - render() { - return
; - } -}`, false, { enableCSSModule: true })).toBe(`import { createElement, Component } from 'rax'; -import appScssStyleSheet from "./app.scss"; -import styleSheet from './app.module.scss'; - -${mergeEleStylesFunctionTemplate} - -var _styleSheet = appScssStyleSheet; - -class App extends Component { - render() { - return
; - }\n -}`) - }) - it('Provide a default stylesheet object when css module enable and import css module sheet only', () => { expect(getTransfromCode(` import { createElement, Component } from 'rax'; @@ -509,18 +401,7 @@ class App extends Component {
; } -}`, false, { enableCSSModule: true })).toBe(`import { createElement, Component } from 'rax'; -import styleSheet from './app.module.scss'; -var _styleSheet = {}; - -class App extends Component { - render() { - return
-
-
-
; - }\n -}`) +}`, false, { enableCSSModule: true })).toMatchSnapshot() }) it('Processing module style assignment When css module enable', () => { @@ -534,17 +415,21 @@ class App extends Component { const a = styleSheet.red return
; } -}`, false, { enableCSSModule: true })).toBe(`import { createElement, Component } from 'rax'; -import appScssStyleSheet from "./app.scss"; +}`, false, { enableCSSModule: true })).toMatchSnapshot() + }) + + it('Processing multiple module style When css module enable', () => { + expect(getTransfromCode(` +import { createElement, Component } from 'rax'; import styleSheet from './app.module.scss'; -var _styleSheet = appScssStyleSheet; +import styleSheet2 from './app2.module.scss'; class App extends Component { render() { - const a = styleSheet.red; - return
; - }\n -}`) + const a = styleSheet.red + return
; + } +}`, false, { enableCSSModule: true })).toMatchSnapshot() }) it('Processing module style spread and assign When css module enable', () => { @@ -559,20 +444,7 @@ class App extends Component { const b = a; return
; } -}`, false, { enableCSSModule: true })).toBe(`import { createElement, Component } from 'rax'; -import appScssStyleSheet from "./app.scss"; -import styleSheet from './app.module.scss'; -var _styleSheet = appScssStyleSheet; - -class App extends Component { - render() { - const a = { ...styleSheet.red - }; - const b = a; - return
; - }\n -}`) +}`, false, { enableCSSModule: true })).toMatchSnapshot() }) it('Processing module style conditional expression When css module enable', () => { @@ -586,17 +458,7 @@ class App extends Component { const a = 1 ? styleSheet.red : styleSheet.blue; return
; } -}`, false, { enableCSSModule: true })).toBe(`import { createElement, Component } from 'rax'; -import appScssStyleSheet from "./app.scss"; -import styleSheet from './app.module.scss'; -var _styleSheet = appScssStyleSheet; - -class App extends Component { - render() { - const a = 1 ? styleSheet.red : styleSheet.blue; - return
; - }\n -}`) +}`, false, { enableCSSModule: true })).toMatchSnapshot() }) it('Processing module style through call expression When css module enable', () => { @@ -610,17 +472,7 @@ class App extends Component { const b = Object.assign({}, a); return
; } -}`, false, { enableCSSModule: true })).toBe(`import { createElement, Component } from 'rax'; -import styleSheet from './app.module.scss'; -var _styleSheet = {}; - -class App extends Component { - render() { - const a = Object.assign({}, styleSheet.red); - const b = Object.assign({}, a); - return
; - }\n -}`) +}`, false, { enableCSSModule: true })).toMatchSnapshot() }) it('merge stylesheet when css module disable', () => { @@ -633,21 +485,7 @@ class App extends Component { render() { return
; } -}`)).toBe(`import { createElement, Component } from 'rax'; -import appScssStyleSheet from "./app.scss"; -import styleSheet from "./app.module.scss"; - -${mergeEleStylesFunctionTemplate} - -${mergeStylesFunctionTemplate} - -var _styleSheet = _mergeStyles(appScssStyleSheet, styleSheet); - -class App extends Component { - render() { - return
; - }\n -}`) +}`)).toMatchSnapshot() }) it('disableMultipleClassName and transform multiple className to multiple style', () => { diff --git a/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/src/index.ts b/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/src/index.ts index 1b4129b38138..a387e69ca141 100644 --- a/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/src/index.ts +++ b/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/src/index.ts @@ -9,6 +9,7 @@ const STYLE_SHEET_NAME = '_styleSheet' const GET_STYLE_FUNC_NAME = '_getStyle' const MERGE_STYLES_FUNC_NAME = '_mergeStyles' const MERGE_ELE_STYLES_FUNC_NAME = '_mergeEleStyles' +const GET_MODULE_CLS_NAME_FUNC_NAME = '_getModuleClassName' const GET_CLS_NAME_FUNC_NAME = '_getClassName' const NAME_SUFFIX = 'styleSheet' @@ -60,14 +61,14 @@ function findLastImportIndex (body) { } const MergeStylesFunction = ` -function _mergeStyles() { +function ${MERGE_STYLES_FUNC_NAME}() { var newTarget = {}; - for (var index = 0; index < arguments.length; index++) { - var target = arguments[index]; + var [styleSheet, rawStyleName] = arguments[index]; - for (var key in target) { - newTarget[key] = Object.assign(newTarget[key] || {}, target[key]); + for (var key in styleSheet) { + const _key = rawStyleName ? rawStyleName + '-' + key : key + newTarget[_key] = Object.assign(newTarget[_key] || {}, styleSheet[key]); } } @@ -115,6 +116,15 @@ function ${GET_STYLE_FUNC_NAME}(classNameExpression) { return style; } ` +const getModuleClassNameFunction = ` +function ${GET_MODULE_CLS_NAME_FUNC_NAME}(moduleStyle, styleId) { + return Object.keys(moduleStyle).reduce((pre, cur) => ( + Object.assign(pre, { + [cur]: styleId + '-' + cur + }) + ), {}) +} +` export default function (babel: { types: typeof Types @@ -128,6 +138,9 @@ export default function (babel: { const getMergeEleStyleFunctionStmt = template(getMergeEleStyleFunction)() + const getModuleClassNameFunctionStmt = template(getModuleClassNameFunction)() + + function getMap (str) { return str.split(/\s+/).map((className) => { // return template(`${STYLE_SHEET_NAME}["${className}"]`)().expression @@ -138,88 +151,7 @@ export default function (babel: { }) } - function isCSSMemberOrBindings (expression, cssModuleStylesheets, astPath) { - if (t.isIdentifier(expression)) { - if (cssModuleStylesheets.includes(expression.name)) { - return true - } else { - const binding = astPath.scope.getBinding(expression.name) - if (binding) { - const { node } = binding.path - if (isCSSMemberOrBindings(node.init, cssModuleStylesheets, astPath)) { - return true - } - } - } - } - - // assign 属性引用 - if (t.isMemberExpression(expression) && t.isIdentifier(expression.object)) { - if (cssModuleStylesheets.includes(expression.object.name)) { - return true - } else { - const binding = astPath.scope.getBinding(expression.object.name) - if (binding) { - const { node } = binding.path - if (isCSSMemberOrBindings(node.init, cssModuleStylesheets, astPath)) { - return true - } - } - } - } - - // Conditional_Operator 条件(三元)运算符 - if (t.isConditionalExpression(expression)) { - const { consequent, alternate } = expression - if ( - isCSSMemberOrBindings(consequent, cssModuleStylesheets, astPath) || - isCSSMemberOrBindings(alternate, cssModuleStylesheets, astPath) - ) { - return true - } - } - - // spread 解构 - if (t.isObjectExpression(expression)) { - for (const prop of expression.properties) { - if (t.isSpreadElement(prop)) { - if (isCSSMemberOrBindings(prop.argument, cssModuleStylesheets, astPath)) { - return true - } - } - } - } - - // 函数调用 - // some call expression args references like Object.assign or @babel/runtime/helpers/extends - if (t.isCallExpression(expression)) { - const { arguments: args } = expression - for (const arg of args) { - if (isCSSMemberOrBindings(arg, cssModuleStylesheets, astPath)) { - return true - } - } - } - } - - function isJSXCSSModuleExpression (value, cssModuleStylesheets, astPath) { - if (t.isJSXExpressionContainer(value)) { - // 1. memberExpression a. 导入. b. 赋值. like `className="{style.red}"` or `const a = style; className="{a.red}"` - // 2. spread like `className="{{ ...style.red }}"` - // 3. memberExpression and spread. like `const a = { ...style }; className="{a.red}" - - if (isCSSMemberOrBindings(value.expression, cssModuleStylesheets, astPath)) { - return true - } - } - } - - function getArrayExpression (value, cssModuleStylesheets, astPath) { - // css module 时 className 处理成 style 属性,所以直接取值跟 style 合并 - if (isJSXCSSModuleExpression(value, cssModuleStylesheets, astPath)) { - return [value.expression] - } - + function getArrayExpression (value) { let str if (!value || value.value === '') { @@ -274,12 +206,14 @@ export default function (babel: { if (existStyleImport) { const { file } = state const styleSheetIdentifiers = file.get('styleSheetIdentifiers') || [] + const cssModuleStylesheets = file.get('cssModuleStylesheets') || [] + const allStyleSheetIdentifiers = [...styleSheetIdentifiers, ...cssModuleStylesheets] let expression // only one css file,由于样式文件合并,永远只有一个 - if (styleSheetIdentifiers.length === 1) { - expression = `var ${STYLE_SHEET_NAME} = ${styleSheetIdentifiers[0].name};\n` - } else if (styleSheetIdentifiers.length > 1) { - const params = styleSheetIdentifiers.reduce((current, next) => `${current},${next.name}`, '').slice(1) + if (allStyleSheetIdentifiers.length === 1 && styleSheetIdentifiers.length === 1) { + expression = `var ${STYLE_SHEET_NAME} = ${allStyleSheetIdentifiers[0].styleSheetName};\n` + } else if (allStyleSheetIdentifiers.length >= 1) { + const params = allStyleSheetIdentifiers.reduce((current, next) => `${current},[${next.styleSheetName}, "${next.rawStyleSheetName || ''}"]`, '').slice(1) expression = `${MergeStylesFunction}\n var ${STYLE_SHEET_NAME} = ${MERGE_STYLES_FUNC_NAME}(${params});\n` } else { @@ -293,6 +227,7 @@ export default function (babel: { const { file } = state const node = astPath.node const injectGetStyle = file.get('injectGetStyle') + const cssModuleStylesheets = file.get('cssModuleStylesheets') || [] // 从最后一个import 开始插入表达式,后续插入的表达式追加在后面 let lastImportIndex = findLastImportIndex(node.body) if (injectGetStyle) { @@ -305,6 +240,16 @@ export default function (babel: { // @ts-ignore node.body.splice(++lastImportIndex, 0, getMergeEleStyleFunctionStmt) } + // 将 styleSheet 转为 {[classname]: classname} + if (cssModuleStylesheets.length) { + // @ts-ignore + node.body.splice(++lastImportIndex, 0, getModuleClassNameFunctionStmt) + cssModuleStylesheets.forEach(({ styleSheetName, rawStyleSheetName }) => { + const functionTempalte = `var ${rawStyleSheetName} = ${GET_MODULE_CLS_NAME_FUNC_NAME}(${styleSheetName}, '${rawStyleSheetName}')` + // @ts-ignore + node.body.splice(++lastImportIndex, 0, template(functionTempalte)()) + }) + } existStyleImport = false } }, @@ -313,7 +258,6 @@ export default function (babel: { const { file, opts = {} } = state const { enableMultipleClassName = false } = opts const { styleMatchRule, classNameMathRule } = getMatchRule(enableMultipleClassName) - const cssModuleStylesheets = file.get('cssModuleStylesheets') || [] const styleNameMapping: any = {} const DEFAULT_STYLE_KEY = 'style' @@ -342,8 +286,16 @@ export default function (babel: { }) } } + for (const key in styleNameMapping) { const { hasClassName, classNameAttribute, hasStyleAttribute, styleAttribute } = styleNameMapping[key] + if (!(hasClassName && existStyleImport) && hasStyleAttribute) { + if (t.isStringLiteral(styleAttribute.value)) { + const cssObject = string2Object(styleAttribute.value.value) + styleAttribute.value = t.jSXExpressionContainer(object2Expression(template, cssObject)) + } + } + if (hasClassName && existStyleImport) { // Remove origin className attributes.splice(attributes.indexOf(classNameAttribute), 1) @@ -351,13 +303,12 @@ export default function (babel: { if ( classNameAttribute.value && classNameAttribute.value.type === 'JSXExpressionContainer' && - typeof classNameAttribute.value.expression.value !== 'string' && // not like className={'container'} - !isJSXCSSModuleExpression(classNameAttribute.value, cssModuleStylesheets, astPath) // 不含有 css module 变量的表达式 + typeof classNameAttribute.value.expression.value !== 'string'// not like className={'container'} ) { file.set('injectGetStyle', true) } - const arrayExpression = getArrayExpression(classNameAttribute.value, cssModuleStylesheets, astPath) + const arrayExpression = getArrayExpression(classNameAttribute.value) if (arrayExpression.length === 0) { return @@ -401,11 +352,6 @@ export default function (babel: { : arrayExpression[0] attributes.push(t.jSXAttribute(t.jSXIdentifier(key === DEFAULT_STYLE_KEY ? key : (key + 'Style')), t.jSXExpressionContainer(expression))) } - } else if (hasStyleAttribute) { - if (t.isStringLiteral(styleAttribute.value)) { - const cssObject = string2Object(styleAttribute.value.value) - styleAttribute.value = t.jSXExpressionContainer(object2Expression(template, cssObject)) - } } } } @@ -435,7 +381,13 @@ function importDeclaration (astPath, state, t) { if (enableCSSModule && isModuleSource(sourceValue)) { if (styleSheetName) { - cssModuleStylesheets.push(styleSheetName) + const moduleStyleSheetName = astPath.scope.generateUid(`${styleSheetName}ModuleStyle`) + specifiers[0].local.name = moduleStyleSheetName + // 保留原始引用的 name + cssModuleStylesheets.push({ + styleSheetName: moduleStyleSheetName, + rawStyleSheetName: styleSheetName + }) } } else { const cssFileName = path.basename(sourceValue) @@ -455,7 +407,9 @@ function importDeclaration (astPath, state, t) { node.specifiers = [t.importDefaultSpecifier(styleSheetIdentifier)] node.source = t.stringLiteral(styleSheetSource) - styleSheetIdentifiers.push(styleSheetIdentifier) + styleSheetIdentifiers.push({ + styleSheetName: styleSheetIdentifier.name + }) } }