Repository: zestedesavoir/zmarkdown
Pull request #356 (2019-08-14 19:27:21)

Transform images to inline in heading, table and gridTable
This PR fixes bug #354 with added **new tests**.

# How it works

The first thing that was done was to write tests for failing cases and correct erroneous snapshot for one of the previous tests. I may have added a lot of tests compared to the problem, but a wise old man once told me there was never too much tests 🧙‍♂️.

Then, on the problem itself, I added a new option for the image serializer of `rebber`, which allow to inject a matcher for when the image should be renderer inline. The default matcher keeps the old `paragraph` exception and add a new one for `heading`; also, this matcher is enforced in `gridTable` of rebber-plugins and `table`of rebber.

Well, well, well, anyway, the bug is now solved and tests are now good! Be careful before merging; we may need a rebase because PR #355 deals with the same block of code.


Patch:
diff --git a/packages/rebber-plugins/dist/type/gridTable.js b/packages/rebber-plugins/dist/type/gridTable.js
index c518a3ee..e981969a 100644
--- a/packages/rebber-plugins/dist/type/gridTable.js
+++ b/packages/rebber-plugins/dist/type/gridTable.js
@@ -194,5 +194,11 @@ function gridTable(ctx, node) {
   overriddenCtx.tableCell = stringifier.gridTableCell.bind(stringifier);
   overriddenCtx.tableRow = stringifier.gridTableRow.bind(stringifier);
   overriddenCtx.headerParse = stringifier.gridTableHeaderParse.bind(stringifier);
+  overriddenCtx.image = overriddenCtx.image ? overriddenCtx.image : {};
+
+  overriddenCtx.image.inlineMatcher = function () {
+    return true;
+  };
+
   return table(overriddenCtx, node).replace(/\\number-of-column/gm, stringifier.nbOfColumns);
 }
\ No newline at end of file
diff --git a/packages/rebber-plugins/src/type/gridTable.js b/packages/rebber-plugins/src/type/gridTable.js
index 95b30612..5054c9d7 100644
--- a/packages/rebber-plugins/src/type/gridTable.js
+++ b/packages/rebber-plugins/src/type/gridTable.js
@@ -149,5 +149,9 @@ function gridTable (ctx, node) {
   overriddenCtx.tableCell = stringifier.gridTableCell.bind(stringifier)
   overriddenCtx.tableRow = stringifier.gridTableRow.bind(stringifier)
   overriddenCtx.headerParse = stringifier.gridTableHeaderParse.bind(stringifier)
+
+  overriddenCtx.image = overriddenCtx.image ? overriddenCtx.image : {}
+  overriddenCtx.image.inlineMatcher = () => true
+
   return table(overriddenCtx, node).replace(/\\number-of-column/gm, stringifier.nbOfColumns)
 }
diff --git a/packages/rebber/dist/types/image.js b/packages/rebber/dist/types/image.js
index 4aa85bd7..9c9888c3 100644
--- a/packages/rebber/dist/types/image.js
+++ b/packages/rebber/dist/types/image.js
@@ -3,6 +3,10 @@
 /* Expose. */
 module.exports = image;
 
+var defaultInlineMatcher = function defaultInlineMatcher(node, parent) {
+  return parent.type === 'paragraph' && parent.children.length - 1 || parent.type === 'heading';
+};
+
 var defaultMacro = function defaultMacro(node) {
   /*
   Note that MDAST `Image` nodes don't have a `width` property.
@@ -37,8 +41,9 @@ function image(ctx, node, _, parent) {
   }
 
   var macro = options.image ? options.image : defaultMacro;
+  var inlineMatcher = options.inlineMatcher ? options.inlineMatcher : defaultInlineMatcher;
 
-  if (parent.type === 'paragraph' && parent.children.length - 1) {
+  if (inlineMatcher(node, parent)) {
     macro = options.inlineImage ? options.inlineImage : defaultInline;
   }
 
diff --git a/packages/rebber/dist/types/table.js b/packages/rebber/dist/types/table.js
index 01ab793b..1537b03b 100644
--- a/packages/rebber/dist/types/table.js
+++ b/packages/rebber/dist/types/table.js
@@ -8,6 +8,8 @@ function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.
 
 function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
 
+var clone = require('clone');
+
 var one = require('../one');
 /* Expose. */
 
@@ -38,5 +40,12 @@ var defaultMacro = function defaultMacro(ctx, node) {
 
 function table(ctx, node) {
   var macro = ctx.table || defaultMacro;
-  return macro(ctx, node);
+  var overriddenCtx = clone(ctx);
+  overriddenCtx.image = overriddenCtx.image ? overriddenCtx.image : {};
+
+  overriddenCtx.image.inlineMatcher = function () {
+    return true;
+  };
+
+  return macro(overriddenCtx, node);
 }
\ No newline at end of file
diff --git a/packages/rebber/src/types/image.js b/packages/rebber/src/types/image.js
index 7f00a1bf..9d70c1f5 100644
--- a/packages/rebber/src/types/image.js
+++ b/packages/rebber/src/types/image.js
@@ -1,6 +1,11 @@
 /* Expose. */
 module.exports = image
 
+const defaultInlineMatcher = (node, parent) => {
+  return (parent.type === 'paragraph' && parent.children.length - 1) ||
+    parent.type === 'heading'
+}
+
 const defaultMacro = (node) => {
   /*
   Note that MDAST `Image` nodes don't have a `width` property.
@@ -40,7 +45,9 @@ function image (ctx, node, _, parent) {
   }
 
   let macro = options.image ? options.image : defaultMacro
-  if (parent.type === 'paragraph' && parent.children.length - 1) {
+  const inlineMatcher = options.inlineMatcher ? options.inlineMatcher : defaultInlineMatcher
+
+  if (inlineMatcher(node, parent)) {
     macro = options.inlineImage ? options.inlineImage : defaultInline
   }
 
diff --git a/packages/rebber/src/types/table.js b/packages/rebber/src/types/table.js
index b297a0bc..3711053a 100644
--- a/packages/rebber/src/types/table.js
+++ b/packages/rebber/src/types/table.js
@@ -1,3 +1,5 @@
+const clone = require('clone')
+
 const one = require('../one')
 
 /* Expose. */
@@ -24,5 +26,10 @@ const defaultMacro = (ctx, node) => {
 /* Stringify a table `node`. */
 function table (ctx, node) {
   const macro = ctx.table || defaultMacro
-  return macro(ctx, node)
+  const overriddenCtx = clone(ctx)
+
+  overriddenCtx.image = overriddenCtx.image ? overriddenCtx.image : {}
+  overriddenCtx.image.inlineMatcher = () => true
+
+  return macro(overriddenCtx, node)
 }


Test patch:
diff --git a/packages/rebber-plugins/__tests__/__snapshots__/rebber.test.js.snap b/packages/rebber-plugins/__tests__/__snapshots__/rebber.test.js.snap
index 4e36989a..0a5264a7 100644
--- a/packages/rebber-plugins/__tests__/__snapshots__/rebber.test.js.snap
+++ b/packages/rebber-plugins/__tests__/__snapshots__/rebber.test.js.snap
@@ -283,7 +283,7 @@ multi \\\\par line \\\\par  \\\\par cells \\\\par too & \\\\multicolumn{2}{|p{\\
 \\\\rowfont[c]{\\\\bfseries}
 title & image \\\\\\\\ \\\\hline
 \\\\rowfont[c]{\\\\bfseries}
-space & \\\\image{https://i.ytimg.com/vi/lt0WQ8JzLz4/maxresdefault.jpg} \\\\\\\\ \\\\hline
+space & \\\\inlineImage{https://i.ytimg.com/vi/lt0WQ8JzLz4/maxresdefault.jpg} \\\\\\\\ \\\\hline
 \\\\end{longtabu}
 
 
@@ -461,6 +461,12 @@ exports[`heading 1`] = `
 
 
 \\\\part{a \\\\} b}
+
+
+\\\\part{\\\\includegraphics{https://www.johnfdoherty.com/wp-content/uploads/2011/07/Titles1.jpg}}
+
+
+\\\\part{a title with \\\\includegraphics{https://www.johnfdoherty.com/wp-content/uploads/2011/07/Titles1.jpg} and text}
 "
 `;
 
@@ -493,6 +499,12 @@ exports[`heading with custom config 1`] = `
 
 
 \\\\LevelOneTitle{a \\\\} b}
+
+
+\\\\LevelOneTitle{\\\\inlineImage{https://www.johnfdoherty.com/wp-content/uploads/2011/07/Titles1.jpg}}
+
+
+\\\\LevelOneTitle{a title with \\\\inlineImage{https://www.johnfdoherty.com/wp-content/uploads/2011/07/Titles1.jpg} and text}
 "
 `;
 
@@ -794,7 +806,7 @@ multi \\\\par line \\\\par  \\\\par cells \\\\par too & \\\\multicolumn{2}{|p{\\
 \\\\rowfont[c]{\\\\bfseries}
 title & image \\\\\\\\ \\\\hline
 \\\\rowfont[c]{\\\\bfseries}
-space & \\\\image{https://i.ytimg.com/vi/lt0WQ8JzLz4/maxresdefault.jpg} \\\\\\\\ \\\\hline
+space & \\\\inlineImage{https://i.ytimg.com/vi/lt0WQ8JzLz4/maxresdefault.jpg} \\\\\\\\ \\\\hline
 \\\\end{longtabu}
 
 
@@ -1073,5 +1085,17 @@ exports[`table 1`] = `
 1 & 2 \\\\\\\\ \\\\hline
 1 & 2  & 3 \\\\\\\\ \\\\hline
 1 & 2  & 3 \\\\\\\\ \\\\hline
+\\\\end{longtabu}
+
+
+Another test for inline image with overridden configuration:
+
+
+
+\\\\begin{longtabu} spread 0pt {|X[-1]|X[-1]|} \\\\hline
+\\\\rowfont[c]{\\\\bfseries}
+c1 & c2 \\\\\\\\ \\\\hline
+\\\\rowfont[l]{}
+c3 & \\\\inlineImage{https://zestedesavoir.com/media/galleries/426/56dc4a1e-416b-4a9d-830d-95b45d58a17a.png} \\\\\\\\ \\\\hline
 \\\\end{longtabu}"
 `;
diff --git a/packages/rebber-plugins/__tests__/fixtures/heading.fixture.md b/packages/rebber-plugins/__tests__/fixtures/heading.fixture.md
index 0e5f1b89..2b2be1cd 100644
--- a/packages/rebber-plugins/__tests__/fixtures/heading.fixture.md
+++ b/packages/rebber-plugins/__tests__/fixtures/heading.fixture.md
@@ -9,3 +9,6 @@
 # a } b
 # a } \ b
 # a \} b
+
+# ![searching for bugs](https://www.johnfdoherty.com/wp-content/uploads/2011/07/Titles1.jpg)
+# a title with ![image](https://www.johnfdoherty.com/wp-content/uploads/2011/07/Titles1.jpg) and text
diff --git a/packages/rebber-plugins/__tests__/fixtures/table.fixture.md b/packages/rebber-plugins/__tests__/fixtures/table.fixture.md
index f2d1bc6e..ac3eb8d4 100644
--- a/packages/rebber-plugins/__tests__/fixtures/table.fixture.md
+++ b/packages/rebber-plugins/__tests__/fixtures/table.fixture.md
@@ -10,3 +10,10 @@
 1 | 2
 1 | 2 | 3
 1 | 2 | 3
+
+
+Another test for inline image with overridden configuration:
+
+c1 | c2
+---|--
+c3 | ![image](https://zestedesavoir.com/media/galleries/426/56dc4a1e-416b-4a9d-830d-95b45d58a17a.png)
diff --git a/packages/rebber-plugins/__tests__/rebber.test.js b/packages/rebber-plugins/__tests__/rebber.test.js
index 11a8996d..9ea5602d 100644
--- a/packages/rebber-plugins/__tests__/rebber.test.js
+++ b/packages/rebber-plugins/__tests__/rebber.test.js
@@ -122,6 +122,10 @@ test('heading with custom config', () => {
         (val) => `\\LevelSixTitle{${val}}\n`,
         (val) => `\\LevelSevenTitle{${val}}\n`,
       ],
+      image: {
+        inlineImage: (node) => `\\inlineImage{${node.url}}`,
+        image: (node) => `\\image{${node.url}}`,
+      },
     })
     .processSync(fixture)
 
@@ -168,7 +172,12 @@ test('table', () => {
   const fixture = fixtures['table']
   const {contents} = unified()
     .use(reParse)
-    .use(rebber, {})
+    .use(rebber, {
+      image: {
+        inlineImage: (node) => `\\inlineImage{${node.url}}`,
+        image: (node) => `\\image{${node.url}}`,
+      },
+    })
     .processSync(fixture)
 
   expect(contents.trim()).toMatchSnapshot()
diff --git a/packages/rebber/__tests__/__snapshots__/mdast.tests.js.snap b/packages/rebber/__tests__/__snapshots__/mdast.tests.js.snap
index 4508ce12..d33318c1 100644
--- a/packages/rebber/__tests__/__snapshots__/mdast.tests.js.snap
+++ b/packages/rebber/__tests__/__snapshots__/mdast.tests.js.snap
@@ -6746,6 +6746,19 @@ Cell 3 & Cell 4 \\\\\\\\ \\\\hline
 \\\\end{longtabu}"
 `;
 
+exports[`rebber: remark specs table-with-image: table-with-image 1`] = `
+"Someone wanted to do this, let's implement it!
+
+
+
+\\\\begin{longtabu} spread 0pt {|X[-1]|X[-1]|} \\\\hline
+\\\\rowfont[c]{\\\\bfseries}
+c1 & c2 \\\\\\\\ \\\\hline
+\\\\rowfont[l]{}
+c3 & \\\\includegraphics{https://zestedesavoir.com/media/galleries/426/56dc4a1e-416b-4a9d-830d-95b45d58a17a.png} \\\\\\\\ \\\\hline
+\\\\end{longtabu}"
+`;
+
 exports[`rebber: remark specs tabs: tabs 1`] = `
 "\\\\begin{itemize}
 \\\\item this is a list item
@@ -12718,6 +12731,19 @@ Cell 3 & Cell 4 \\\\\\\\ \\\\hline
 \\\\end{longtabu}"
 `;
 
+exports[`rebber: remark specs with config: custom macros table-with-image 1`] = `
+"Someone wanted to do this, let's implement it!
+
+
+
+\\\\begin{longtabu} spread 0pt {|X[-1]|X[-1]|} \\\\hline
+\\\\rowfont[c]{\\\\bfseries}
+c1 & c2 \\\\\\\\ \\\\hline
+\\\\rowfont[l]{}
+c3 & \\\\includegraphics{https://zestedesavoir.com/media/galleries/426/56dc4a1e-416b-4a9d-830d-95b45d58a17a.png} \\\\\\\\ \\\\hline
+\\\\end{longtabu}"
+`;
+
 exports[`rebber: remark specs with config: custom macros tabs 1`] = `
 "[unorderedList([listItem(this is a list item
 indented with tabs)][listItem(this is a list item
@@ -20064,6 +20090,20 @@ Cell 3 & Cell 4 \\\\\\\\ \\\\hline
 "
 `;
 
+exports[`toLaTeX: remark specs table-with-image: table-with-image 1`] = `
+"Someone wanted to do this, let's implement it!
+
+
+
+\\\\begin{longtabu} spread 0pt {|X[-1]|X[-1]|} \\\\hline
+\\\\rowfont[c]{\\\\bfseries}
+c1 & c2 \\\\\\\\ \\\\hline
+\\\\rowfont[l]{}
+c3 & \\\\includegraphics{https://zestedesavoir.com/media/galleries/426/56dc4a1e-416b-4a9d-830d-95b45d58a17a.png} \\\\\\\\ \\\\hline
+\\\\end{longtabu}
+"
+`;
+
 exports[`toLaTeX: remark specs tabs: tabs 1`] = `
 "\\\\begin{itemize}
 \\\\item this is a list item
diff --git a/packages/rebber/__tests__/fixtures/remark/table-with-image.text b/packages/rebber/__tests__/fixtures/remark/table-with-image.text
new file mode 100644
index 00000000..25258dc2
--- /dev/null
+++ b/packages/rebber/__tests__/fixtures/remark/table-with-image.text
@@ -0,0 +1,5 @@
+Someone wanted to do this, let's implement it!
+
+c1 | c2
+---|--
+c3 | ![image](https://zestedesavoir.com/media/galleries/426/56dc4a1e-416b-4a9d-830d-95b45d58a17a.png)