Skip to content

Commit

Permalink
fix: handle wide code blocks (#93)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: wide code blocks inside cells are line wrapped by inserting a "no-break-here" (U+0083) character.

fixes #92
  • Loading branch information
tripodsan authored Jan 29, 2024
1 parent d9d806e commit 6a4cbbf
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 3 deletions.
11 changes: 9 additions & 2 deletions src/from-markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,19 @@ import {
TYPE_BODY, TYPE_CELL, TYPE_HEADER, TYPE_FOOTER, TYPE_ROW, TYPE_TABLE,
} from './types.js';

function unescapeDelimsInCode(tree) {
function unescapeCode(tree) {
visit(tree, (node) => {
if (node.type === 'inlineCode' || node.type === 'code') {
// remove escaped pipes and plusses in code
// eslint-disable-next-line no-param-reassign
node.value = node.value.replace(/\\([+|])/gm, '$1');
}
if (node.type === 'code') {
// remove non-break-here characters
// eslint-disable-next-line no-param-reassign
node.value = node.value.replace(/\u0083 ?\n/ugm, '');
}

return CONTINUE;
});
}
Expand Down Expand Up @@ -126,7 +133,7 @@ function createExitTable(options) {
}

// remove escaped pipes and plusses in code
unescapeDelimsInCode(tree);
unescapeCode(tree);

node.children = tree.children;
if (colSpan > 1) {
Expand Down
19 changes: 18 additions & 1 deletion src/to-markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -567,11 +567,28 @@ function blockCodeWithTable(node, parent, context) {

if (context.stack.includes(TYPE_CELL)) {
value = value.replace(/[|+]/mg, '\\$&');
}

// break code if wider than lineWidth or 256 chars, but at least 150
const lineWidth = Math.min(256, Math.max(150, context.options.lineWidth));
if (value.length > lineWidth) {
// iterate over lines and break if needed
const lines = [];
for (let line of value.split('\n')) {
while (line.length > lineWidth) {
lines.push(`${line.substring(0, lineWidth)}\u0083`);
line = line.substring(lineWidth);
}
lines.push(line);
}
value = lines.join('\n');
}
}
return value;
}

// don't wrap for peek operations
blockCodeWithTable.peek = code;

/**
* Escapes cell delimiters in inline code
*/
Expand Down
12 changes: 12 additions & 0 deletions test/fixtures/gt-wide-text.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## Table with wide text

+-----------------------------------------------------------------------------------------------------------------------+
| Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore |
| magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd |
| gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing |
| elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos |
| et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor |
| sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore |
| et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita |
| kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. |
+-----------------------------------------------------------------------------------------------------------------------+
37 changes: 37 additions & 0 deletions test/fixtures/gt-wide.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<h2>Table with wide code block</h2>
<table>
<tbody>
<tr>
<td>Super Code Example</td>
</tr>
<tr>
<td>
<pre><code class="language-json">"examples": {
"0": {
"value": "{\n \"events\": [\n {\n \"xdm\": {\n \"eventType\": \"media.adStart\",\n \"mediaCollection\": {\n \"advertisingDetails\": {\n \"friendlyName\": \"Ad 1\",\n \"name\": \"/uri-reference/001\",\n \"length\": 10,\n \"advertiser\": \"Adobe Marketing\",\n \"campaignID\": \"Adobe Analytics\",\n \"creativeID\": \"creativeID\",\n \"creativeURL\": \"https://creativeurl.com\",\n \"placementID\": \"placementID\",\n \"siteID\": \"siteID\",\n \"podPosition\": 11,\n \"playerName\": \"HTML5 player\"\n },\n \"customMetadata\": [\n {\n \"name\": \"myCustomValue3\",\n \"value\": \"c3\"\n },\n {\n \"name\": \"myCustomValue2\",\n \"value\": \"c2\"\n },\n {\n \"name\": \"myCustomValue1\",\n \"value\": \"c1\"\n }\n ],\n \"sessionID\": \"5c32e1a6ef6b58be5136ba8db2f79f1d251d3121a898bc8fb60123b8fdb9aa1c\",\n \"playhead\": 15\n },\n \"timestamp\": \"2022-03-04T13:38:26+00:00\"\n }\n }\n ]\n}"
}
}
</code></pre>
</td>
</tr>
</tbody>
</table>
<table>
<tbody>
<tr>
<td>
<h1>Wide Heading: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</h1>
</td>
</tr>
<tr>
<td>
<pre><code class="language-json">"examples": {
"0": {
"value": "{\n \"events\": [\n {\n \"xdm\": {\n \"eventType\": \"media.adStart\",\n \"mediaCollection\": {\n \"advertisingDetails\": {\n \"friendlyName\": \"Ad 1\",\n \"name\": \"/uri-reference/001\",\n \"length\": 10,\n \"advertiser\": \"Adobe Marketing\",\n \"campaignID\": \"Adobe Analytics\",\n \"creativeID\": \"creativeID\",\n \"creativeURL\": \"https://creativeurl.com\",\n \"placementID\": \"placementID\",\n \"siteID\": \"siteID\",\n \"podPosition\": 11,\n \"playerName\": \"HTML5 player\"\n },\n \"customMetadata\": [\n {\n \"name\": \"myCustomValue3\",\n \"value\": \"c3\"\n },\n {\n \"name\": \"myCustomValue2\",\n \"value\": \"c2\"\n },\n {\n \"name\": \"myCustomValue1\",\n \"value\": \"c1\"\n }\n ],\n \"sessionID\": \"5c32e1a6ef6b58be5136ba8db2f79f1d251d3121a898bc8fb60123b8fdb9aa1c\",\n \"playhead\": 15\n },\n \"timestamp\": \"2022-03-04T13:38:26+00:00\"\n }\n }\n ]\n}"
}
}
</code></pre>
</td>
</tr>
</tbody>
</table>
37 changes: 37 additions & 0 deletions test/fixtures/gt-wide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## Table with wide code block

+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| Super Code Example |
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| ```json |
| "examples": { |
| "0": { |
| "value": "{\n \"events\": [\n {\n \"xdm\": {\n \"eventType\": \"media.adStart\",\n \"mediaCollection\": {\n \"adverƒ |
| tisingDetails\": {\n \"friendlyName\": \"Ad 1\",\n \"name\": \"/uri-reference/001\",\n \"length\": 10,\n \"ƒ |
| advertiser\": \"Adobe Marketing\",\n \"campaignID\": \"Adobe Analytics\",\n \"creativeID\": \"creativeID\",\n \"creatiƒ |
| veURL\": \"https://creativeurl.com\",\n \"placementID\": \"placementID\",\n \"siteID\": \"siteID\",\n \"podPosition\"|
| 11,\n \"playerName\": \"HTML5 player\"\n },\n \"customMetadata\": [\n {\n \"name\": \"myCustomValƒ |
| ue3\",\n \"value\": \"c3\"\n },\n {\n \"name\": \"myCustomValue2\",\n \"value\": \"c2\"\n ƒ |
| },\n {\n \"name\": \"myCustomValue1\",\n \"value\": \"c1\"\n }\n ],\n \"seƒ |
| ssionID\": \"5c32e1a6ef6b58be5136ba8db2f79f1d251d3121a898bc8fb60123b8fdb9aa1c\",\n \"playhead\": 15\n },\n \"timestamp\": \"2022ƒ |
| -03-04T13:38:26\+00:00\"\n }\n }\n ]\n}" |
| } |
| } |
| ``` |
+----------------------------------------------------------------------------------------------------------------------------------------------------------+

+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| # Wide Heading: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ```json |
| "examples": { |
| "0": { |
| "value": "{\n \"events\": [\n {\n \"xdm\": {\n \"eventType\": \"media.adStart\",\n \"mediaCollection\": {\n \"advertisingDetails\": {\n \"friendlyName\": \"Ad 1\",\n \"name\": \"/uri-reference/001\"ƒ |
| ,\n \"length\": 10,\n \"advertiser\": \"Adobe Marketing\",\n \"campaignID\": \"Adobe Analytics\",\n \"creativeID\": \"creativeID\",\n \"creativeURL\": \"https://creativeurl.com\",\n \"placemƒ |
| entID\": \"placementID\",\n \"siteID\": \"siteID\",\n \"podPosition\": 11,\n \"playerName\": \"HTML5 player\"\n },\n \"customMetadata\": [\n {\n \"name\": \"myCustomValue3\",\n ƒ |
| \"value\": \"c3\"\n },\n {\n \"name\": \"myCustomValue2\",\n \"value\": \"c2\"\n },\n {\n \"name\": \"myCustomValue1\",\n \"value\": \"c1\"\n ƒ |
| }\n ],\n \"sessionID\": \"5c32e1a6ef6b58be5136ba8db2f79f1d251d3121a898bc8fb60123b8fdb9aa1c\",\n \"playhead\": 15\n },\n \"timestamp\": \"2022-03-04T13:38:26\+00:00\"\n }\n }\n ]\n}" |
| } |
| } |
| ``` |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
4 changes: 4 additions & 0 deletions test/gridtable-from-md.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ describe('gridtable from markdown', () => {
await testMD('gt-large');
});

it('wide table', async () => {
await testMD('gt-wide');
});

it('footer no header table', async () => {
await testMD('gt-footer-no-header');
});
Expand Down
4 changes: 4 additions & 0 deletions test/gridtable-to-html.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ describe('html from markdown gridtable', () => {
await testMD2HTML('gt-nbsp');
});

it('table with wide code block', async () => {
await testMD2HTML('gt-wide');
});

it('table with no gtHead', async () => {
const mdast = {
type: 'root',
Expand Down
41 changes: 41 additions & 0 deletions test/gridtable-to-md.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ const CODE = `for (const row of this.rows) {
}
}`;

const CODE_WIDE = `"examples": {
"0": {
"value": "{\\n \\"events\\": [\\n {\\n \\"xdm\\": {\\n \\"eventType\\": \\"media.adStart\\",\\n \\"mediaCollection\\": {\\n \\"advertisingDetails\\": {\\n \\"friendlyName\\": \\"Ad 1\\",\\n \\"name\\": \\"/uri-reference/001\\",\\n \\"length\\": 10,\\n \\"advertiser\\": \\"Adobe Marketing\\",\\n \\"campaignID\\": \\"Adobe Analytics\\",\\n \\"creativeID\\": \\"creativeID\\",\\n \\"creativeURL\\": \\"https://creativeurl.com\\",\\n \\"placementID\\": \\"placementID\\",\\n \\"siteID\\": \\"siteID\\",\\n \\"podPosition\\": 11,\\n \\"playerName\\": \\"HTML5 player\\"\\n },\\n \\"customMetadata\\": [\\n {\\n \\"name\\": \\"myCustomValue3\\",\\n \\"value\\": \\"c3\\"\\n },\\n {\\n \\"name\\": \\"myCustomValue2\\",\\n \\"value\\": \\"c2\\"\\n },\\n {\\n \\"name\\": \\"myCustomValue1\\",\\n \\"value\\": \\"c1\\"\\n }\\n ],\\n \\"sessionID\\": \\"5c32e1a6ef6b58be5136ba8db2f79f1d251d3121a898bc8fb60123b8fdb9aa1c\\",\\n \\"playhead\\": 15\\n },\\n \\"timestamp\\": \\"2022-03-04T13:38:26+00:00\\"\\n }\\n }\\n ]\\n}"
}
}`;

function brk() {
return {
type: 'break',
Expand Down Expand Up @@ -558,6 +564,41 @@ describe('gridtable to md', () => {
await assertMD(mdast, 'gt-code-with-delim.md');
});

it('table with very wide code block', async () => {
const mdast = root([
heading(2, text('Table with wide code block')),
gridTable([
gtRow([
gtCell(text('Super Code Example')),
]),
gtRow([
gtCell(code('json', CODE_WIDE)),
]),
]),
gridTable([
gtRow([
gtCell(heading(1, text('Wide Heading: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.'))),
]),
gtRow([
gtCell(code('json', CODE_WIDE)),
]),
]),
]);
await assertMD(mdast, 'gt-wide.md');
});

it('table with very wide normal text', async () => {
const mdast = root([
heading(2, text('Table with wide text')),
gridTable([
gtRow([
gtCell(text('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.')),
]),
]),
]);
await assertMD(mdast, 'gt-wide-text.md');
});

it('unbalanced tables', async () => {
const mdast = root([
heading(2, text('Table with larger colspan')),
Expand Down

0 comments on commit 6a4cbbf

Please sign in to comment.