From 82c05aa4b38e6ef14e0afac3b50f660529c8ac05 Mon Sep 17 00:00:00 2001 From: Mathieu Dutour Date: Wed, 22 Apr 2020 08:39:09 +0200 Subject: [PATCH] feat(gatsby-remark-images): support markdownCaptions in mdx + fix for remark (#21188) * pass compiler to gatsby-remark-* plugins in the mdx plugin * make getImageCaption async * use async mdx compiler * fix for using compiler * don't mutate the node multiple times * convert markdown ast to html ast Co-authored-by: vladar --- packages/gatsby-plugin-mdx/utils/gen-mdx.js | 4 + packages/gatsby-remark-images/src/index.js | 6 +- .../src/extend-node-type.js | 101 ++++++++++-------- 3 files changed, 65 insertions(+), 46 deletions(-) diff --git a/packages/gatsby-plugin-mdx/utils/gen-mdx.js b/packages/gatsby-plugin-mdx/utils/gen-mdx.js index 3c6ede688ddd7..15acbc6911bc3 100644 --- a/packages/gatsby-plugin-mdx/utils/gen-mdx.js +++ b/packages/gatsby-plugin-mdx/utils/gen-mdx.js @@ -116,6 +116,10 @@ export const _frontmatter = ${JSON.stringify(data)}` reporter, cache, pathPrefix, + compiler: { + parseString: compiler.parse.bind(compiler), + generateHTML: ast => mdx(ast, options), + }, ...helpers, } ) diff --git a/packages/gatsby-remark-images/src/index.js b/packages/gatsby-remark-images/src/index.js index e0895a1ea3927..427c499a28c96 100644 --- a/packages/gatsby-remark-images/src/index.js +++ b/packages/gatsby-remark-images/src/index.js @@ -78,7 +78,7 @@ module.exports = ( } } - const getImageCaption = (node, overWrites) => { + const getImageCaption = async (node, overWrites) => { const getCaptionString = () => { const captionOptions = Array.isArray(options.showCaptions) ? options.showCaptions @@ -115,7 +115,7 @@ module.exports = ( return _.escape(captionString) } - return compiler.generateHTML(compiler.parseString(captionString)) + return compiler.generateHTML(await compiler.parseString(captionString)) } // Takes a node and generates the needed images and then returns @@ -288,7 +288,7 @@ module.exports = ( // Construct new image node w/ aspect ratio placeholder const imageCaption = - options.showCaptions && getImageCaption(node, overWrites) + options.showCaptions && (await getImageCaption(node, overWrites)) let removeBgImage = false if (options.disableBgImageOnAlpha) { diff --git a/packages/gatsby-transformer-remark/src/extend-node-type.js b/packages/gatsby-transformer-remark/src/extend-node-type.js index 3d6cdeb3b92c1..b7653e9d80b2c 100644 --- a/packages/gatsby-transformer-remark/src/extend-node-type.js +++ b/packages/gatsby-transformer-remark/src/extend-node-type.js @@ -165,35 +165,21 @@ module.exports = ( } } - async function getMarkdownAST(markdownNode) { - if (process.env.NODE_ENV !== `production` || !fileNodes) { - fileNodes = getNodesByType(`File`) + // Parse a markdown string and its AST representation, + // applying the remark plugins if necesserary + async function parseString(string, markdownNode) { + // compiler to inject in the remark plugins + // so that they can use our parser/generator + // with all the options and plugins from the user + const compiler = { + parseString: string => parseString(string, markdownNode), + generateHTML: ast => + hastToHTML(markdownASTToHTMLAst(ast), { + allowDangerousHTML: true, + }), } - // Use Bluebird's Promise function "each" to run remark plugins serially. - await Promise.each(pluginOptions.plugins, plugin => { - const requiredPlugin = require(plugin.resolve) - if (_.isFunction(requiredPlugin.mutateSource)) { - return requiredPlugin.mutateSource( - { - markdownNode, - files: fileNodes, - getNode, - reporter, - cache: getCache(plugin.name), - getCache, - compiler: { - parseString: remark.parse.bind(remark), - generateHTML: getHTML, - }, - ...rest, - }, - plugin.pluginOptions - ) - } else { - return Promise.resolve() - } - }) - const markdownAST = remark.parse(markdownNode.internal.content) + + const markdownAST = remark.parse(string) if (basePath) { // Ensure relative links include `pathPrefix` @@ -232,10 +218,7 @@ module.exports = ( reporter, cache: getCache(plugin.name), getCache, - compiler: { - parseString: remark.parse.bind(remark), - generateHTML: getHTML, - }, + compiler, ...rest, }, plugin.pluginOptions @@ -248,6 +231,38 @@ module.exports = ( return markdownAST } + async function getMarkdownAST(markdownNode) { + if (process.env.NODE_ENV !== `production` || !fileNodes) { + fileNodes = getNodesByType(`File`) + } + + // Execute the remark plugins that can mutate the node + // before parsing its content + // + // Use Bluebird's Promise function "each" to run remark plugins serially. + await Promise.each(pluginOptions.plugins, plugin => { + const requiredPlugin = require(plugin.resolve) + if (_.isFunction(requiredPlugin.mutateSource)) { + return requiredPlugin.mutateSource( + { + markdownNode, + files: fileNodes, + getNode, + reporter, + cache: getCache(plugin.name), + getCache, + ...rest, + }, + plugin.pluginOptions + ) + } else { + return Promise.resolve() + } + }) + + return parseString(markdownNode.internal.content, markdownNode) + } + async function getHeadings(markdownNode) { const cachedHeadings = await cache.get(headingsCacheKey(markdownNode)) if (cachedHeadings) { @@ -323,16 +338,20 @@ module.exports = ( } } + async function markdownASTToHTMLAst(ast) { + return toHAST(ast, { + allowDangerousHTML: true, + handlers: { code: codeHandler }, + }) + } + async function getHTMLAst(markdownNode) { const cachedAst = await cache.get(htmlAstCacheKey(markdownNode)) if (cachedAst) { return cachedAst } else { const ast = await getAST(markdownNode) - const htmlAst = toHAST(ast, { - allowDangerousHTML: true, - handlers: { code: codeHandler }, - }) + const htmlAst = markdownASTToHTMLAst(ast) // Save new HTML AST to cache and return cache.set(htmlAstCacheKey(markdownNode), htmlAst) @@ -341,9 +360,7 @@ module.exports = ( } async function getHTML(markdownNode) { - const shouldCache = markdownNode && markdownNode.internal - const cachedHTML = - shouldCache && (await cache.get(htmlCacheKey(markdownNode))) + const cachedHTML = await cache.get(htmlCacheKey(markdownNode)) if (cachedHTML) { return cachedHTML } else { @@ -353,10 +370,8 @@ module.exports = ( allowDangerousHTML: true, }) - if (shouldCache) { - // Save new HTML to cache - cache.set(htmlCacheKey(markdownNode), html) - } + // Save new HTML to cache + cache.set(htmlCacheKey(markdownNode), html) return html }