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
JavaScript
;
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;
}
}