UNPKG

babel-plugin-transform-jsx-stylesheet

Version:

Transform stylesheet selector to style in JSX Elements.

220 lines 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = require("path"); var camelcase = require("camelcase"); var constants_1 = require("./constants"); function default_1(_a, opts) { var t = _a.types, template = _a.template; if (opts === void 0) { opts = {}; } var injectedStyleName = opts.injectedStyleName; if (typeof injectedStyleName === 'string') { (0, constants_1.setStyleSheetName)(injectedStyleName); } var mergeStylesFunctionTemplate = template((0, constants_1.mergeStylesFunctionString)()); var getClassNameFunctionTemplate = template((0, constants_1.getClassNameFunctionString)()); var getStyleFunctionTemplete = template((0, constants_1.getStyleFunctionString)()); var getClassNameFunctionAst = getClassNameFunctionTemplate(); var mergeStylesFunctionAst = mergeStylesFunctionTemplate(); var getStyleFunctionAst = getStyleFunctionTemplete(); function getArrayExpression(value) { var str; if (!value || value.value === '') { // className // className="" return []; } else if (value.type === 'JSXExpressionContainer' && value.expression && typeof value.expression.value !== 'string') { // className={{ container: true }} // className={['container wrapper', { scroll: false }]} if (value.expression.type === 'MemberExpression') { return [value.expression]; } return [t.callExpression(t.identifier(constants_1.GET_STYLE_FUNC_NAME), [value.expression])]; } else { // className="container" // className={'container'} str = (value.expression ? value.expression.value : value.value).trim(); } return str === '' ? [] : str.split(/\s+/).map(function (className) { return template("".concat(constants_1.styleSheetName, "[\"").concat(className, "\"]"))().expression; }); } function findLastImportIndex(body) { var bodyReverse = body.slice(0).reverse(); var _index = 0; bodyReverse.some(function (node, index) { if (node.type === 'ImportDeclaration') { _index = body.length - index - 1; return true; } return false; }); return _index; } return { pre: function (file) { file.set('shouldSkipConvert', false); }, visitor: { Program: { exit: function (_a, _b) { var node = _a.node; var file = _b.file; var cssFileCount = file.get('cssFileCount'); var injectGetStyle = file.get('injectGetStyle'); var lastImportIndex = findLastImportIndex(node.body); var cssParamIdentifiers = file.get('cssParamIdentifiers'); var callExpression; if (cssParamIdentifiers) { // only one css file if (cssParamIdentifiers.length === 1) { callExpression = t.variableDeclaration('var', [t.variableDeclarator(t.identifier(constants_1.styleSheetName), cssParamIdentifiers[0])]); } else if (cssParamIdentifiers.length > 1) { var objectAssignExpression = t.callExpression(t.identifier(constants_1.MERGE_STYLES_FUNC_NAME), cssParamIdentifiers); callExpression = t.variableDeclaration('var', [t.variableDeclarator(t.identifier(constants_1.styleSheetName), objectAssignExpression)]); } node.body.splice(lastImportIndex + 1, 0, callExpression); if (injectGetStyle) { node.body.splice(lastImportIndex + 2, 0, getClassNameFunctionAst); node.body.splice(lastImportIndex + 3, 0, getStyleFunctionAst); } } if (cssFileCount > 1) { node.body.unshift(mergeStylesFunctionAst); } }, }, // eslint-disable-next-line @typescript-eslint/no-shadow JSXOpeningElement: function (_a, _b) { var container = _a.container; var file = _b.file, opts = _b.opts; var _c = opts.retainClassName, retainClassName = _c === void 0 ? false : _c, _d = opts.convertImport, convertImport = _d === void 0 ? true : _d; // skip attribute convert when use css module // `import styles from '*.module.(c|le|sa|sc)ss'` // should not convert attribute `className` to `style` if (file.get('shouldSkipConvert')) return; // Check if has "style" var hasStyleAttribute = false; var styleAttribute; var hasClassName = false; var classNameAttribute; var attributes = container.openingElement.attributes; for (var i = 0; i < attributes.length; i++) { var name_1 = attributes[i].name; if (name_1) { if (!hasStyleAttribute) { hasStyleAttribute = name_1.name === 'style'; styleAttribute = hasStyleAttribute && attributes[i]; } if (!hasClassName) { hasClassName = name_1.name === 'className'; classNameAttribute = hasClassName && attributes[i]; } } } // like className={ x.xxx } var isCssModule = hasClassName && classNameAttribute.value && classNameAttribute.value.type === 'JSXExpressionContainer' && classNameAttribute.value.expression.type === 'MemberExpression'; var cssFileCount = file.get('cssFileCount') || 0; if (!isCssModule && cssFileCount < 1 && convertImport !== false) { return; } if (hasClassName) { // Dont remove className if (!retainClassName) { // development env: change className to __class if (process.env.NODE_ENV === 'development' && classNameAttribute.name) { classNameAttribute.name.name = '__class'; } else { // Remove origin className attributes.splice(attributes.indexOf(classNameAttribute), 1); } } if (classNameAttribute.value && classNameAttribute.value.type === 'JSXExpressionContainer' && typeof classNameAttribute.value.expression.value !== 'string' // not like className={'container'} ) { file.set('injectGetStyle', true); } if (isCssModule) { attributes.splice(attributes.indexOf(classNameAttribute), 1); file.set('injectGetStyle', false); } var arrayExpression = getArrayExpression(classNameAttribute.value); if (arrayExpression.length === 0) { return; } if (hasStyleAttribute && styleAttribute.value) { var expression = styleAttribute.value.expression; var expressionType = expression.type; // style={[styles.a, styles.b]} ArrayExpression if (expressionType === 'ArrayExpression') { expression.elements = arrayExpression.concat(expression.elements); // style={styles.a} MemberExpression // style={{ height: 100 }} ObjectExpression // style={{ ...custom }} ObjectExpression // style={custom} Identifier // style={getStyle()} CallExpression // style={this.props.useCustom ? custom : null} ConditionalExpression // style={custom || other} LogicalExpression } else { var mergeArrayExpression = arrayExpression.concat(expression); mergeArrayExpression.unshift(t.objectExpression([])); styleAttribute.value.expression = t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('assign')), mergeArrayExpression); } } else { if (arrayExpression.length > 1) { // Object.assign({}, ...) arrayExpression.unshift(t.objectExpression([])); } var expression = arrayExpression.length === 1 ? arrayExpression[0] : t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('assign')), arrayExpression); attributes.push(t.jSXAttribute(t.jSXIdentifier('style'), t.jSXExpressionContainer(expression))); } } }, // eslint-disable-next-line @typescript-eslint/no-shadow ImportDeclaration: function (_a, _b) { var node = _a.node; var file = _b.file, opts = _b.opts; // Convert style import is disabled. var _c = opts.convertImport, convertImport = _c === void 0 ? true : _c, _d = opts.forceEnableCSS, forceEnableCSS = _d === void 0 ? false : _d; if (!convertImport) return; var sourceValue = node.source.value; var extname = path.extname(sourceValue); var cssIndex = constants_1.cssSuffixs.indexOf(extname); // Do not convert `import styles from './foo.css'` kind if (node.specifiers.length === 0 && cssIndex > -1) { var cssFileCount = file.get('cssFileCount') || 0; var cssParamIdentifiers = file.get('cssParamIdentifiers') || []; var cssFileBaseName = camelcase(path.basename(sourceValue, extname)); var styleSheetIdentifier = t.identifier("".concat(cssFileBaseName + constants_1.NAME_SUFFIX)); node.specifiers = [t.importDefaultSpecifier(styleSheetIdentifier)]; cssParamIdentifiers.push(styleSheetIdentifier); cssFileCount++; file.set('cssParamIdentifiers', cssParamIdentifiers); file.set('cssFileCount', cssFileCount); } // Set skip flag when `import styles from '*.module.(c|le|sa|sc)ss'` if (node.specifiers.length && cssIndex > -1) { var cssModuleReg = /\.module\.(c|le|sa|sc)ss$/; var shouldSkipConvert = (forceEnableCSS && cssModuleReg.test(sourceValue)) || file.get('shouldSkipConvert'); file.set('shouldSkipConvert', shouldSkipConvert); } }, }, }; } exports.default = default_1; //# sourceMappingURL=index.js.map