Files
30-seconds-of-code/node_modules/gatsby-remark-images/index.js
2019-08-20 15:52:05 +02:00

532 lines
19 KiB
JavaScript

"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _require = require("./constants"),
DEFAULT_OPTIONS = _require.DEFAULT_OPTIONS,
imageClass = _require.imageClass,
imageBackgroundClass = _require.imageBackgroundClass,
imageWrapperClass = _require.imageWrapperClass;
var visitWithParents = require("unist-util-visit-parents");
var getDefinitions = require("mdast-util-definitions");
var path = require("path");
var queryString = require("query-string");
var isRelativeUrl = require("is-relative-url");
var _ = require("lodash");
var _require2 = require("gatsby-plugin-sharp"),
fluid = _require2.fluid,
traceSVG = _require2.traceSVG;
var Promise = require("bluebird");
var cheerio = require("cheerio");
var slash = require("slash");
var chalk = require("chalk"); // If the image is relative (not hosted elsewhere)
// 1. Find the image file
// 2. Find the image's size
// 3. Filter out any responsive image fluid sizes that are greater than the image's width
// 4. Create the responsive images.
// 5. Set the html w/ aspect ratio helper.
module.exports = function (_ref, pluginOptions) {
var files = _ref.files,
markdownNode = _ref.markdownNode,
markdownAST = _ref.markdownAST,
pathPrefix = _ref.pathPrefix,
getNode = _ref.getNode,
reporter = _ref.reporter,
cache = _ref.cache,
compiler = _ref.compiler;
var options = _.defaults(pluginOptions, {
pathPrefix: pathPrefix
}, DEFAULT_OPTIONS);
var findParentLinks = function findParentLinks(_ref2) {
var children = _ref2.children;
return children.some(function (node) {
return node.type === "html" && !!node.value.match(/<a /) || node.type === "link";
});
}; // Get all the available definitions in the markdown tree
var definitions = getDefinitions(markdownAST); // This will allow the use of html image tags
// const rawHtmlNodes = select(markdownAST, `html`)
var rawHtmlNodes = [];
visitWithParents(markdownAST, ["html", "jsx"], function (node, ancestors) {
var inLink = ancestors.some(findParentLinks);
rawHtmlNodes.push({
node: node,
inLink: inLink
});
}); // This will only work for markdown syntax image tags
var markdownImageNodes = [];
visitWithParents(markdownAST, ["image", "imageReference"], function (node, ancestors) {
var inLink = ancestors.some(findParentLinks);
markdownImageNodes.push({
node: node,
inLink: inLink
});
});
var getImageInfo = function getImageInfo(uri) {
var _queryString$parseUrl = queryString.parseUrl(uri),
url = _queryString$parseUrl.url,
query = _queryString$parseUrl.query;
return {
ext: path.extname(url).split(".").pop(),
url: url,
query: query
};
};
var getImageCaption = function getImageCaption(node, overWrites) {
var getCaptionString = function getCaptionString() {
var captionOptions = Array.isArray(options.showCaptions) ? options.showCaptions : options.showCaptions === true ? ["title", "alt"] : false;
if (captionOptions) {
for (var _iterator = captionOptions, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
var _ref3;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref3 = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref3 = _i.value;
}
var option = _ref3;
switch (option) {
case "title":
if (node.title) {
return node.title;
}
break;
case "alt":
if (overWrites.alt) {
return overWrites.alt;
}
if (node.alt) {
return node.alt;
}
break;
}
}
}
return "";
};
var captionString = getCaptionString();
if (!options.markdownCaptions || !compiler) {
return _.escape(captionString);
}
return compiler.generateHTML(compiler.parseString(captionString));
}; // Takes a node and generates the needed images and then returns
// the needed HTML replacement for the image
var generateImagesAndUpdateNode =
/*#__PURE__*/
function () {
var _ref4 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee(node, resolve, inLink, overWrites) {
var parentNode, imagePath, imageNode, fluidResult, originalImg, fallbackSrc, srcSet, presentationWidth, srcSplit, fileName, fileNameNoExt, defaultAlt, alt, title, loading, imageTag, webpFluidResult, placeholderImageData, args, _require3, Potrace, argsKeys, tracedSVG, ratio, wrapperStyle, imageCaption, rawHTML;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
if (overWrites === void 0) {
overWrites = {};
}
// Check if this markdownNode has a File parent. This plugin
// won't work if the image isn't hosted locally.
parentNode = getNode(markdownNode.parent);
if (!(parentNode && parentNode.dir)) {
_context.next = 6;
break;
}
imagePath = slash(path.join(parentNode.dir, getImageInfo(node.url).url));
_context.next = 7;
break;
case 6:
return _context.abrupt("return", null);
case 7:
imageNode = _.find(files, function (file) {
if (file && file.absolutePath) {
return file.absolutePath === imagePath;
}
return null;
});
if (!(!imageNode || !imageNode.absolutePath)) {
_context.next = 10;
break;
}
return _context.abrupt("return", resolve());
case 10:
_context.next = 12;
return fluid({
file: imageNode,
args: options,
reporter: reporter,
cache: cache
});
case 12:
fluidResult = _context.sent;
if (fluidResult) {
_context.next = 15;
break;
}
return _context.abrupt("return", resolve());
case 15:
originalImg = fluidResult.originalImg;
fallbackSrc = fluidResult.src;
srcSet = fluidResult.srcSet;
presentationWidth = fluidResult.presentationWidth; // Generate default alt tag
srcSplit = getImageInfo(node.url).url.split("/");
fileName = srcSplit[srcSplit.length - 1];
fileNameNoExt = fileName.replace(/\.[^/.]+$/, "");
defaultAlt = fileNameNoExt.replace(/[^A-Z0-9]/gi, " ");
alt = _.escape(overWrites.alt ? overWrites.alt : node.alt ? node.alt : defaultAlt);
title = node.title ? _.escape(node.title) : alt;
loading = options.loading;
if (!["lazy", "eager", "auto"].includes(loading)) {
reporter.warn(reporter.stripIndent("\n " + chalk.bold(loading) + " is an invalid value for the " + chalk.bold("loading") + " option. Please pass one of \"lazy\", \"eager\" or \"auto\".\n "));
} // Create our base image tag
imageTag = ("\n <img\n class=\"" + imageClass + "\"\n alt=\"" + alt + "\"\n title=\"" + title + "\"\n src=\"" + fallbackSrc + "\"\n srcset=\"" + srcSet + "\"\n sizes=\"" + fluidResult.sizes + "\"\n loading=\"" + loading + "\"\n />\n ").trim(); // if options.withWebp is enabled, generate a webp version and change the image tag to a picture tag
if (!options.withWebp) {
_context.next = 35;
break;
}
_context.next = 31;
return fluid({
file: imageNode,
args: _.defaults({
toFormat: "WEBP"
}, // override options if it's an object, otherwise just pass through defaults
options.withWebp === true ? {} : options.withWebp, pluginOptions, DEFAULT_OPTIONS),
reporter: reporter
});
case 31:
webpFluidResult = _context.sent;
if (webpFluidResult) {
_context.next = 34;
break;
}
return _context.abrupt("return", resolve());
case 34:
imageTag = ("\n <picture>\n <source\n srcset=\"" + webpFluidResult.srcSet + "\"\n sizes=\"" + webpFluidResult.sizes + "\"\n type=\"" + webpFluidResult.srcSetType + "\"\n />\n <source\n srcset=\"" + srcSet + "\"\n sizes=\"" + fluidResult.sizes + "\"\n type=\"" + fluidResult.srcSetType + "\"\n />\n <img\n class=\"" + imageClass + "\"\n src=\"" + fallbackSrc + "\"\n alt=\"" + alt + "\"\n title=\"" + title + "\"\n loading=\"" + loading + "\"\n />\n </picture>\n ").trim();
case 35:
placeholderImageData = fluidResult.base64; // if options.tracedSVG is enabled generate the traced SVG and use that as the placeholder image
if (!options.tracedSVG) {
_context.next = 45;
break;
}
args = typeof options.tracedSVG === "object" ? options.tracedSVG : {}; // Translate Potrace constants (e.g. TURNPOLICY_LEFT, COLOR_AUTO) to the values Potrace expects
_require3 = require("potrace"), Potrace = _require3.Potrace;
argsKeys = Object.keys(args);
args = argsKeys.reduce(function (result, key) {
var value = args[key];
result[key] = Potrace.hasOwnProperty(value) ? Potrace[value] : value;
return result;
}, {});
_context.next = 43;
return traceSVG({
file: imageNode,
args: args,
fileArgs: args,
cache: cache,
reporter: reporter
});
case 43:
tracedSVG = _context.sent;
// Escape single quotes so the SVG data can be used in inline style attribute with single quotes
placeholderImageData = tracedSVG.replace(/'/g, "\\'");
case 45:
ratio = 1 / fluidResult.aspectRatio * 100 + "%";
wrapperStyle = typeof options.wrapperStyle === "function" ? options.wrapperStyle(fluidResult) : options.wrapperStyle; // Construct new image node w/ aspect ratio placeholder
imageCaption = options.showCaptions && getImageCaption(node, overWrites);
rawHTML = ("\n <span\n class=\"" + imageBackgroundClass + "\"\n style=\"padding-bottom: " + ratio + "; position: relative; bottom: 0; left: 0; background-image: url('" + placeholderImageData + "'); background-size: cover; display: block;\"\n ></span>\n " + imageTag + "\n ").trim(); // Make linking to original image optional.
if (!inLink && options.linkImagesToOriginal) {
rawHTML = ("\n <a\n class=\"gatsby-resp-image-link\"\n href=\"" + originalImg + "\"\n style=\"display: block\"\n target=\"_blank\"\n rel=\"noopener\"\n >\n " + rawHTML + "\n </a>\n ").trim();
}
rawHTML = ("\n <span\n class=\"" + imageWrapperClass + "\"\n style=\"position: relative; display: block; margin-left: auto; margin-right: auto; " + (imageCaption ? "" : wrapperStyle) + " max-width: " + presentationWidth + "px;\"\n >\n " + rawHTML + "\n </span>\n ").trim(); // Wrap in figure and use title as caption
if (imageCaption) {
rawHTML = ("\n <figure class=\"gatsby-resp-image-figure\" style=\"" + wrapperStyle + "\">\n " + rawHTML + "\n <figcaption class=\"gatsby-resp-image-figcaption\">" + imageCaption + "</figcaption>\n </figure>\n ").trim();
}
return _context.abrupt("return", rawHTML);
case 53:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return function generateImagesAndUpdateNode(_x, _x2, _x3, _x4) {
return _ref4.apply(this, arguments);
};
}();
return Promise.all( // Simple because there is no nesting in markdown
markdownImageNodes.map(function (_ref5) {
var node = _ref5.node,
inLink = _ref5.inLink;
return new Promise(
/*#__PURE__*/
function () {
var _ref6 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee2(resolve, reject) {
var overWrites, refNode, fileType, rawHTML;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
overWrites = {};
if (!(!node.hasOwnProperty("url") && node.hasOwnProperty("identifier"))) {
_context2.next = 7;
break;
}
//consider as imageReference node
refNode = node;
node = definitions(refNode.identifier); // pass original alt from referencing node
overWrites.alt = refNode.alt;
if (node) {
_context2.next = 7;
break;
}
return _context2.abrupt("return", resolve());
case 7:
fileType = getImageInfo(node.url).ext; // Ignore gifs as we can't process them,
// svgs as they are already responsive by definition
if (!(isRelativeUrl(node.url) && fileType !== "gif" && fileType !== "svg")) {
_context2.next = 16;
break;
}
_context2.next = 11;
return generateImagesAndUpdateNode(node, resolve, inLink, overWrites);
case 11:
rawHTML = _context2.sent;
if (rawHTML) {
// Replace the image or ref node with an inline HTML node.
if (refNode) {
node = refNode;
}
node.type = "html";
node.value = rawHTML;
}
return _context2.abrupt("return", resolve(node));
case 16:
return _context2.abrupt("return", resolve());
case 17:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
return function (_x5, _x6) {
return _ref6.apply(this, arguments);
};
}());
})).then(function (markdownImageNodes) {
return (// HTML image node stuff
Promise.all( // Complex because HTML nodes can contain multiple images
rawHtmlNodes.map(function (_ref7) {
var node = _ref7.node,
inLink = _ref7.inLink;
return new Promise(
/*#__PURE__*/
function () {
var _ref8 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee3(resolve, reject) {
var $, imageRefs, _i2, thisImg, formattedImgTag, fileType, rawHTML;
return _regenerator.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
if (node.value) {
_context3.next = 2;
break;
}
return _context3.abrupt("return", resolve());
case 2:
$ = cheerio.load(node.value);
if (!($("img").length === 0)) {
_context3.next = 5;
break;
}
return _context3.abrupt("return", resolve());
case 5:
imageRefs = [];
$("img").each(function () {
imageRefs.push($(this));
});
_i2 = 0;
case 8:
if (!(_i2 < imageRefs.length)) {
_context3.next = 29;
break;
}
thisImg = imageRefs[_i2];
// Get the details we need.
formattedImgTag = {};
formattedImgTag.url = thisImg.attr("src");
formattedImgTag.title = thisImg.attr("title");
formattedImgTag.alt = thisImg.attr("alt");
if (formattedImgTag.url) {
_context3.next = 16;
break;
}
return _context3.abrupt("return", resolve());
case 16:
fileType = getImageInfo(formattedImgTag.url).ext; // Ignore gifs as we can't process them,
// svgs as they are already responsive by definition
if (!(isRelativeUrl(formattedImgTag.url) && fileType !== "gif" && fileType !== "svg")) {
_context3.next = 26;
break;
}
_context3.next = 20;
return generateImagesAndUpdateNode(formattedImgTag, resolve, inLink);
case 20:
rawHTML = _context3.sent;
if (!rawHTML) {
_context3.next = 25;
break;
}
// Replace the image string
thisImg.replaceWith(rawHTML);
_context3.next = 26;
break;
case 25:
return _context3.abrupt("return", resolve());
case 26:
_i2++;
_context3.next = 8;
break;
case 29:
// Replace the image node with an inline HTML node.
node.type = "html";
node.value = $("body").html(); // fix for cheerio v1
return _context3.abrupt("return", resolve(node));
case 32:
case "end":
return _context3.stop();
}
}
}, _callee3, this);
}));
return function (_x7, _x8) {
return _ref8.apply(this, arguments);
};
}());
})).then(function (htmlImageNodes) {
return markdownImageNodes.concat(htmlImageNodes).filter(function (node) {
return !!node;
});
})
);
});
};