UNPKG

babel-plugin-transform-react-jsx-img-import

Version:

Generate imports for jsx img elements. A handy transform for use in webpack workflows.

222 lines (148 loc) 6.58 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); exports.default = function (_ref) { let t = _ref.types; return { visitor: { CallExpression: function CallExpression(path, state) { // is a React.createElement("img" .... ) if (isReactCreateElement(path) && hasImgArgument(path)) { // process src let imgSrcValueNodePath = getPropertyValue(path, 'src'); if (imgSrcValueNodePath) { let newSrcValueNodePath = transformImgSrcNodePath(imgSrcValueNodePath, t); imgSrcValueNodePath.replaceWith(newSrcValueNodePath); } // process srcSet let imgSrcSetValueNodePath = getPropertyValue(path, 'srcSet'); if (imgSrcSetValueNodePath) { let newSrcSetValueNodePath = transformImgSrcSetNodePath(imgSrcSetValueNodePath, t); imgSrcSetValueNodePath.replaceWith(newSrcSetValueNodePath); } } else if (isReactCreateElement(path) && hasSvgImageArgument(path)) { // process href let svgImageHrefValueNodePath = getPropertyValue(path, 'href'); if (svgImageHrefValueNodePath) { let newSvgImageHrefValueNodePath = transformSvgImageHrefNodePath(svgImageHrefValueNodePath, t); svgImageHrefValueNodePath.replaceWith(newSvgImageHrefValueNodePath); } } }, Program: { exit: function exit(path, state) { const importDeclarations = _lodash2.default.map(imgImportIdentifiers, (imgImportIdentifier, imgSrcLiteral) => { return t.importDeclaration([t.importNamespaceSpecifier(imgImportIdentifier)], t.stringLiteral(imgSrcLiteral)); }); path.unshiftContainer('body', importDeclarations); }, enter: function enter(path, state) { imgImportIdentifiers = {}; rootScope = path.scope; } } } }; }; var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } let imgImportIdentifiers = {}; let rootScope; function isReactCreateElement(path) { return path.get('callee').matchesPattern('React.createElement'); } function hasImgArgument(path) { return path.get('arguments').length > 1 && path.get('arguments')[0].isStringLiteral({ value: 'img' }); } function hasSvgImageArgument(path) { return path.get('arguments').length > 1 && path.get('arguments')[0].isStringLiteral({ value: 'image' }); } function getPropertyValue(path, propertyName) { if (path.get('arguments')[1].isObjectExpression()) { let props = path.get('arguments')[1].get("properties"); for (let prop of props) { if (!prop.isProperty()) continue; let key = prop.get("key"); if (key.isIdentifier({ name: propertyName })) { return prop.get("value"); } } } } function isURL(url) { let lowerURL = url.toLowerCase(); return lowerURL.startsWith('http://') || lowerURL.startsWith('https://') || lowerURL.startsWith('data:'); } function transformImgSrcNodePath(imgSrcNodePath, t) { if (imgSrcNodePath.isStringLiteral() && !imgSrcNodePath._img_import_processed) { imgSrcNodePath._img_import_processed = true; return createImport(imgSrcNodePath.node.value, t); } else { return imgSrcNodePath; } } function transformSvgImageHrefNodePath(svgImageHrefNodePath, t) { if (svgImageHrefNodePath.isStringLiteral() && !svgImageHrefNodePath._img_import_processed) { svgImageHrefNodePath._img_import_processed = true; return createImport(svgImageHrefNodePath.node.value, t); } else { return svgImageHrefNodePath; } } function parseSrcSetValue(srcSetValue) { const imgList = srcSetValue.split(',').map(function (img) { var _img$trim$split = img.trim().split(' '); var _img$trim$split2 = _slicedToArray(_img$trim$split, 2); const imgSrc = _img$trim$split2[0]; const descriptor = _img$trim$split2[1]; return { imgSrc: imgSrc, descriptor: descriptor }; }); return imgList; } function createImport(imgSrc, t) { // Override transformation if (imgSrc.startsWith('!')) { return t.stringLiteral(imgSrc.substring(1)); } // Ignore if src is an absolute URL if (isURL(imgSrc)) { return t.stringLiteral(imgSrc); } // cache import identifiers. let imgImportIdentifier = imgImportIdentifiers[imgSrc]; if (!imgImportIdentifier) { imgImportIdentifier = rootScope.generateUidIdentifier('image'); imgImportIdentifiers[imgSrc] = imgImportIdentifier; } // We need to access the default import since Babel shim non // CommonJS modules. let imgImportDefaultIdentifier = t.memberExpression(imgImportIdentifier, t.identifier("default")); return imgImportDefaultIdentifier; } function transformImgSrcSetNodePath(imgSrcSetValueNodePath, t) { if (imgSrcSetValueNodePath.isStringLiteral()) { let srcSetValue = imgSrcSetValueNodePath.node.value; let srcSetList = parseSrcSetValue(srcSetValue); const srcSetValues = srcSetList.map(function (srcSetElement) { const imgSrc = createImport(srcSetElement.imgSrc, t); const descriptor = srcSetElement.descriptor ? t.stringLiteral(srcSetElement.descriptor) : t.stringLiteral(''); return { imgSrc: imgSrc, descriptor: descriptor }; }); const srcSetExpression = srcSetValues.reduce(function (prev, current, i) { let exp = t.binaryExpression('+', t.binaryExpression('+', current.imgSrc, t.stringLiteral(' ')), current.descriptor); if (i < srcSetValues.length - 1) { exp = t.binaryExpression('+', exp, t.stringLiteral(', ')); } if (prev) { exp = t.binaryExpression('+', prev, exp); } return exp; }, null); return srcSetExpression; } else { return imgSrcSetValueNodePath; } }