Skip to content

Commit

Permalink
Merge pull request #3 from instantish/mm/support-tables
Browse files Browse the repository at this point in the history
Basic support for tables
  • Loading branch information
marissamarym authored Oct 19, 2021
2 parents 417a089 + ba69bbb commit 4ac0c64
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 11 deletions.
28 changes: 17 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ objects.

### Supported Markdown Elements

* All inline elements (italics, bold, strikethrough, inline code, hyperlinks)
* Lists (ordered, unordered, checkboxes)
* All headers
* Code blocks
* Block quotes (with some limitations)
* Images
* Thematic Breaks / Dividers
- All inline elements (italics, bold, strikethrough, inline code, hyperlinks)
- Lists (ordered, unordered, checkboxes)
- All headers
- Code blocks
- Block quotes (with some limitations)
- Images
- Thematic Breaks / Dividers
- Tables (alignment not preserved)

### Not Yet Supported Markdown Elements

- - Block quotes (limited functionality; does not support lists, headings, or images within the block quote)

## Installation

```
npm install @instantish/mack
```
Expand All @@ -29,7 +35,6 @@ npm install @instantish/mack
```ts
import {markdownToBlocks} from '@instantish/mack';


const blocks = markdownToBlocks(`
# Hello world
Expand All @@ -39,16 +44,17 @@ const blocks = markdownToBlocks(`
abc _123_
![cat](https://images.unsplash.com/photo-1574158622682-e40e69881006)
`)
`);
```

The `blocks` object now results in [this](https://app.slack.com/block-kit-builder/T01BFUV9UPJ#%7B%22blocks%22:%5B%7B%22text%22:%7B%22text%22:%22Hello%20world%22,%22type%22:%22plain_text%22%7D,%22type%22:%22header%22%7D,%7B%22text%22:%7B%22text%22:%22•%20bulleted%20item%201%5Cn•%20bulleted%20item%202%22,%22type%22:%22mrkdwn%22%7D,%22type%22:%22section%22%7D,%7B%22text%22:%7B%22text%22:%22abc%20_123_%22,%22type%22:%22mrkdwn%22%7D,%22type%22:%22section%22%7D,%7B%22alt_text%22:%22cat%22,%22image_url%22:%22https://images.unsplash.com/photo-1574158622682-e40e69881006?w=640%22,%22type%22:%22image%22%7D%5D%7D) payload.

## API

`function markdownToBlocks(text: string, options: ParsingOptions): KnownBlock[]`
* `text`: the content to parse
* `options`: the options to use when parsing.

- `text`: the content to parse
- `options`: the options to use when parsing.

### Parsing Options

Expand Down
64 changes: 64 additions & 0 deletions src/parser/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ function addMrkdwn(
}
}

function parsePhrasingContentToStrings(
element: md.PhrasingContent,
accumulator: String[]
) {
if (element.type === 'image') {
accumulator.push(element.url ?? element.title ?? element.alt ?? 'image');
} else {
const text = parseMrkdwn(element);
accumulator.push(text);
}
}

function parsePhrasingContent(
element: md.PhrasingContent,
accumulator: (SectionBlock | ImageBlock)[],
Expand Down Expand Up @@ -173,6 +185,55 @@ function parseList(element: md.List, options: ListOptions = {}): SectionBlock {
};
}

function combineBetweenPipes(texts: String[]): String {
return `| ${texts.join(' | ')} |`;
}

function parseTableRows(rows: md.TableRow[]): String[] {
const parsedRows: String[] = [];
rows.forEach((row, index) => {
const parsedCells = parseTableRow(row);
if (index === 1) {
const headerRowArray = new Array(parsedCells.length).fill('---');
const headerRow = combineBetweenPipes(headerRowArray);
parsedRows.push(headerRow);
}
parsedRows.push(combineBetweenPipes(parsedCells));
});
return parsedRows;
}

function parseTableRow(row: md.TableRow): String[] {
const parsedCells: String[] = [];
row.children.forEach(cell => {
parsedCells.push(parseTableCell(cell));
});
return parsedCells;
}

function parseTableCell(cell: md.TableCell): String {
const texts = cell.children.reduce(
(accumulator: String[], child: md.PhrasingContent) => {
parsePhrasingContentToStrings(child, accumulator);
return accumulator;
},
[] as String[]
);
return texts.join(' ');
}

function parseTable(element: md.Table): SectionBlock {
const parsedRows = parseTableRows(element.children);

return {
type: 'section',
text: {
type: 'mrkdwn',
text: `\`\`\`\n${parsedRows.join('\n')}\n\`\`\``,
},
};
}

function parseBlockquote(node: md.Blockquote): KnownBlock[] {
return node.children
.filter((child): child is md.Paragraph => child.type === 'paragraph')
Expand Down Expand Up @@ -205,6 +266,9 @@ function parseNode(
case 'list':
return [parseList(node, options.lists)];

case 'table':
return [parseTable(node)];

case 'thematicBreak':
return [parseThematicBreak()];

Expand Down
13 changes: 13 additions & 0 deletions test/integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ a **b** _c_ **_d_ e**
- [ ] checkbox false
- [x] checkbox true
| Syntax | Description |
| ----------- | ----------- |
| Header | Title |
| Paragraph | Text |
`;

const actual = await markdownToBlocks(text);
Expand All @@ -45,6 +50,14 @@ a **b** _c_ **_d_ e**
slack.section('• bullet _a_\n• bullet _b_'),
slack.section('1. number _a_\n2. number _b_'),
slack.section('• checkbox false\n• checkbox true'),
slack.section(
'```\n' +
'| Syntax | Description |\n' +
'| --- | --- |\n' +
'| Header | Title |\n' +
'| Paragraph | Text |\n' +
'```'
),
];

console.log(JSON.stringify(expected, null, 3));
Expand Down

0 comments on commit 4ac0c64

Please sign in to comment.