Skip to content

Commit 938b9c8

Browse files
authored
Merge pull request #5 from codeskills-dev/fix/p-bold
Fix: parsing-inconsistencies and optimisations
2 parents 644836c + 82017f8 commit 938b9c8

18 files changed

Lines changed: 6276 additions & 4510 deletions

.DS_Store

6 KB
Binary file not shown.

.changeset/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Changesets
2+
3+
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4+
with multi-package repos, or single-package repos to help you version and publish your code. You can
5+
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6+
7+
We have a quick list of common questions to get you started engaging with this project in
8+
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

.changeset/config.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json",
3+
"changelog": "@changesets/cli/changelog",
4+
"commit": false,
5+
"fixed": [],
6+
"linked": [],
7+
"access": "restricted",
8+
"baseBranch": "master",
9+
"updateInternalDependencies": "patch",
10+
"ignore": []
11+
}

.changeset/late-squids-join.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
"md-to-react-email": patch
3+
---
4+
5+
### Bug fixes
6+
7+
- Fixed issue with parsing paragraphs
8+
- Converted bold and italics tag to <strong> and <em>
9+
- Fixed issue with parsing nested blockquotes
10+
- Fixed issue with parsing code blocks
11+
12+
### Optimisations
13+
14+
This PR added optimisations for the following:
15+
16+
- Cleaning up unused style tags for the generated markup
17+
- Moved the changesets
18+
- Added CI workflows

.github/workflows/main.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: CI
2+
on:
3+
push:
4+
branches:
5+
- "**"
6+
7+
jobs:
8+
build:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v3
12+
- uses: pnpm/action-setup@v2
13+
with:
14+
version: 7
15+
- uses: actions/setup-node@v3
16+
with:
17+
node-version: 16.x
18+
cache: "pnpm"
19+
20+
- run: pnpm install --frozen-lockfile
21+
- run: pnpm run lint && pnpm run build

.github/workflows/publish.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Publish
2+
on:
3+
workflow_run:
4+
workflows: ["CI"]
5+
types:
6+
- completed
7+
push:
8+
branches:
9+
- "master"
10+
11+
concurrency: ${{ github.workflow }}-${{ github.ref }}
12+
13+
jobs:
14+
publish:
15+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v3
19+
- uses: pnpm/action-setup@v2
20+
with:
21+
version: 7
22+
- uses: actions/setup-node@v3
23+
with:
24+
node-version: 16.x
25+
cache: "pnpm"
26+
27+
- run: pnpm install --frozen-lockfile
28+
- name: Create Release Pull Request or Publish
29+
id: changesets
30+
uses: changesets/action@v1
31+
with:
32+
publish: pnpm run release
33+
env:
34+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
35+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@
55
/coverage/
66

77
# Build files
8-
/dist
8+
/dist
9+
10+
# JS files
11+
*.js
12+
*.txt
13+
*.html

__tests__/parseMarkdownToReactEmail.test.ts

Lines changed: 88 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,169 +1,130 @@
1-
import { parseMarkdownToReactEmail, styles } from "../src";
1+
import { parseMarkdownToReactEmail } from "../src";
22

33
describe("Markdown to React Mail Parser", () => {
4-
it("converts header one correctly", () => {
4+
it("converts headers correctly", () => {
55
const markdown = "# Hello, World!";
6-
const expected = `<Section><Heading as="h1" style={${JSON.stringify(
7-
styles.h1
8-
)}}>Hello, World!</Heading></Section>`;
6+
const expected = `<Section><Heading as=\"h1\" style={{\"fontWeight\":\"500\",\"paddingTop\":20,\"fontSize\":\"2.5rem\"}}>Hello, World!</Heading></Section>`;
97

108
const rendered = parseMarkdownToReactEmail(markdown);
119
expect(rendered).toBe(expected);
1210
});
1311

14-
it("converts header two correctly", () => {
15-
const markdown = "## Heading Two";
16-
const expected = `<Section><Heading as="h2" style={${JSON.stringify(
17-
styles.h2
18-
)}}>Heading Two</Heading></Section>`;
12+
it("converts paragraphs, headers, lists, and tables correctly", () => {
13+
const markdown = `# Header 1
1914
20-
const result = parseMarkdownToReactEmail(markdown);
21-
expect(result).toEqual(expected);
22-
});
15+
This is a paragraph with some text. You can have multiple paragraphs separated by empty lines.
2316
24-
it("converts header three correctly", () => {
25-
const markdown = "### Heading Three";
26-
const expected = `<Section><Heading as="h3" style={${JSON.stringify(
27-
styles.h3
28-
)}}>Heading Three</Heading></Section>`;
17+
## Header 2
2918
30-
const result = parseMarkdownToReactEmail(markdown);
31-
expect(result).toEqual(expected);
32-
});
19+
Here is an unordered list:
20+
- Item 1
21+
- Item 2
22+
- Item 3
3323
34-
it("converts header four correctly", () => {
35-
const markdown = "#### Heading Four";
36-
const expected = `<Section><Heading as="h4" style={${JSON.stringify(
37-
styles.h4
38-
)}}>Heading Four</Heading></Section>`;
24+
### Header 3
3925
40-
const result = parseMarkdownToReactEmail(markdown);
41-
expect(result).toEqual(expected);
42-
});
26+
Here is an ordered list:
27+
1. First
28+
2. Second
29+
3. Third
4330
44-
it("converts header five correctly", () => {
45-
const markdown = "##### Heading Five";
46-
const expected = `<Section><Heading as="h5" style={${JSON.stringify(
47-
styles.h5
48-
)}}>Heading Five</Heading></Section>`;
31+
#### Header 4
4932
50-
const result = parseMarkdownToReactEmail(markdown);
51-
expect(result).toEqual(expected);
52-
});
33+
A table example:
5334
54-
it("converts header six correctly", () => {
55-
const markdown = "###### Heading Six";
56-
const expected = `<Section><Heading as="h6" style={${JSON.stringify(
57-
styles.h6
58-
)}}>Heading Six</Heading></Section>`;
35+
| Column 1 | Column 2 |
36+
|----------|----------|
37+
| Cell 1 | Cell 2 |
38+
| Cell 3 | Cell 4 |
39+
`;
5940

60-
const result = parseMarkdownToReactEmail(markdown);
61-
expect(result).toEqual(expected);
62-
});
41+
const expected = `<Section><Heading as="h1" style={{"fontWeight":"500","paddingTop":20,"fontSize":"2.5rem"}}>Header 1</Heading>
6342
64-
it("should handle block quote", () => {
65-
const markdown = "> This is a block quote.";
66-
const expected = `<Section><Text style={${JSON.stringify(
67-
styles.blockQuote
68-
)}}>This is a block quote.</Text></Section>`;
43+
<Text>This is a paragraph with some text. You can have multiple paragraphs separated by empty lines.</Text>
6944
70-
const result = parseMarkdownToReactEmail(markdown);
71-
expect(result).toEqual(expected);
72-
});
45+
<Heading as="h2" style={{"fontWeight":"500","paddingTop":20,"fontSize":"2rem"}}>Header 2</Heading>
7346
74-
it("converts paragraphs correctly", () => {
75-
const markdown = "This is a paragraph.";
76-
const expected = `<Section>This is a paragraph.</Section>`;
47+
<Text>Here is an unordered list:</Text>
48+
<ul><li>Item 1</li>
49+
<li>Item 2</li>
50+
<li>Item 3</li></ul>
7751
78-
const rendered = parseMarkdownToReactEmail(markdown);
79-
expect(rendered).toBe(expected);
80-
});
52+
<Heading as="h3" style={{"fontWeight":"500","paddingTop":20,"fontSize":"1.75rem"}}>Header 3</Heading>
8153
82-
it("converts bold text correctly", () => {
83-
const markdown = "**bold text**";
84-
const expected = `<Section><Text style={${JSON.stringify(
85-
styles.bold
86-
)}}>bold text</Text></Section>`;
54+
<Text>Here is an ordered list:</Text>
55+
<ol><li>First</li>
56+
<li>Second</li>
57+
<li>Third</li>
58+
</ol>
59+
<Heading as="h4" style={{"fontWeight":"500","paddingTop":20,"fontSize":"1.5rem"}}>Header 4</Heading>
60+
61+
<Text>A table example:</Text>
62+
<table><thead><tr><th align="center">Column 1</th><th align="center">Column 2</th></tr></thead><tbody><tr><td align="center">Cell 1</td><td align="center">Cell 2</td></tr><tr><td align="center">Cell 3</td><td align="center">Cell 4</td></tr></tbody></table></Section>`;
8763

8864
const rendered = parseMarkdownToReactEmail(markdown);
8965
expect(rendered).toBe(expected);
9066
});
9167

92-
it("converts italic text correctly", () => {
93-
const markdown = "*italic text*";
94-
const expected = `<Section><Text style={${JSON.stringify(
95-
styles.italic
96-
)}}>italic text</Text></Section>`;
68+
it("converts images, codeblocks, blockquotes and nested blockquotes correctly", () => {
69+
const markdown = `##### Header 5
9770
98-
const rendered = parseMarkdownToReactEmail(markdown);
99-
expect(rendered).toBe(expected);
100-
});
71+
An image example:
72+
![Alt Text](https://example.com/image.jpg)
10173
102-
it("converts lists correctly", () => {
103-
const markdown = "- Item 1\n- Item 2\n- Item 3";
104-
const expected = `<Section><ul style={${JSON.stringify(
105-
styles.ul
106-
)}}><li style={${JSON.stringify(styles.li)}}>Item 1</li>
107-
<li style={${JSON.stringify(styles.li)}}>Item 2</li>
108-
<li style={${JSON.stringify(styles.li)}}>Item 3</li></ul></Section>`;
74+
###### Header 6
10975
110-
const rendered = parseMarkdownToReactEmail(markdown);
111-
expect(rendered).toBe(expected);
112-
});
76+
Some **bold text** and *italic text* _italic text_.
11377
114-
it("converts images correctly", () => {
115-
const markdown = "![alt text](image.jpg)";
116-
const expected = `<Section><Img style={${JSON.stringify(
117-
styles.image
118-
)}} alt="alt text" src="image.jpg" /></Section>`;
78+
Code block example:
79+
\`\`\`
80+
javascript
81+
function greet() {
82+
console.log('Hello!');
83+
}
84+
\`\`\`
11985
120-
const rendered = parseMarkdownToReactEmail(markdown);
121-
expect(rendered).toBe(expected);
122-
});
86+
Here is a block quote example:
12387
124-
it("converts links correctly", () => {
125-
const markdown = "[Codeskills](https://codeskills.dev)";
126-
const expected = `<Section><Link href="https://codeskills.dev" style={${JSON.stringify(
127-
styles.link
128-
)}}>Codeskills</Link></Section>`;
88+
> This is a block quote.
89+
> It can span multiple lines.
90+
> > This is a nested quote
91+
> > With multiple
92+
> > Lines of code
12993
130-
const rendered = parseMarkdownToReactEmail(markdown);
131-
expect(rendered).toBe(expected);
132-
});
94+
> Block quotes are often used to highlight important information or provide references.`;
13395

134-
it("converts code blocks correctly", () => {
135-
const markdown = '```javascript\nconsole.log("Hello, World!");\n```';
136-
const expected = `<Section><pre style={${JSON.stringify(
137-
styles.codeBlock
138-
)}}><Text>{\`javascript
139-
console.log("Hello, World!");
140-
\`}</Text></pre></Section>`;
96+
const expected = `<Section><Heading as=\"h5\" style={{\"fontWeight\":\"500\",\"paddingTop\":20,\"fontSize\":\"1.25rem\"}}>Header 5</Heading>
14197
142-
const rendered = parseMarkdownToReactEmail(markdown);
143-
expect(rendered).toBe(expected);
144-
});
98+
<Text>An image example:</Text>
99+
<Img src=\"https://example.com/image.jpg\" alt=\"Alt Text\" />
145100
146-
it("converts tables correctly", () => {
147-
const markdown = `
148-
| Header 1 | Header 2 |
149-
| -------- | -------- |
150-
| Cell 1 | Cell 2 |
151-
| Cell 3 | Cell 4 |
152-
`;
153-
const expected =
154-
'<Section><table style={{}}><thead style={{}}><tr style={{"color":"red"}}><th style={{}} align="center">Header 1</th><th style={{}} align="center">Header 2</th></tr></thead><tbody style={{}}><tr style={{"color":"red"}}><td style={{}} align="center">Cell 1</td><td style={{}} align="center">Cell 2</td></tr><tr style={{"color":"red"}}><td style={{}} align="center">Cell 3</td><td style={{}} align="center">Cell 4</td></tr></tbody></table></Section>';
101+
<Heading as=\"h6\" style={{\"fontWeight\":\"500\",\"paddingTop\":20,\"fontSize\":\"1rem\"}}>Header 6</Heading>
155102
156-
const rendered = parseMarkdownToReactEmail(markdown, {
157-
tr: { color: "red" },
158-
});
159-
expect(rendered).toBe(expected);
160-
});
103+
<Text>Some <strong style={{\"fontWeight\":\"bold\"}}>bold text</strong> and <em style={{\"fontStyle\":\"italic\"}}>italic text</em> <em style={{\"fontStyle\":\"italic\"}}>italic text</em>.</Text>
104+
105+
<Text>Code block example:</Text>
106+
<pre style={{\"color\":\"#212529\",\"fontSize\":\"87.5%\",\"display\":\"inline\",\"background\":\" #f8f8f8\",\"fontFamily\":\"SFMono-Regular,Menlo,Monaco,Consolas,monospace\",\"paddingTop\":10,\"paddingRight\":10,\"paddingLeft\":10,\"paddingBottom\":1,\"marginBottom\":20,\"wordWrap\":\"break-word\"}}>
107+
javascript
108+
function greet() {
109+
console.log('Hello!');
110+
}
111+
</pre>
112+
113+
<Text>Here is a block quote example:</Text>
114+
115+
<Text style={{"background":"#f9f9f9","borderLeft":"10px solid #ccc","margin":"1.5em 10px","padding":"1em 10px"}}>
116+
<Text>This is a block quote.</Text>
117+
<Text>It can span multiple lines.</Text>
118+
<Text style={{"background":"#f9f9f9","borderLeft":"10px solid #ccc","margin":"1.5em 10px","padding":"1em 10px"}}>
119+
<Text>This is a nested quote</Text>
120+
<Text>With multiple</Text>
121+
<Text>Lines of code</Text>
122+
</Text>
123+
</Text>
161124
162-
it("converts strikethrough blocks correctly", () => {
163-
const markdown = "~~This is a paragraph.~~";
164-
const expected = `<Section><del style={${JSON.stringify(
165-
styles.strikethrough
166-
)}}>This is a paragraph.</del></Section>`;
125+
<Text style={{"background":"#f9f9f9","borderLeft":"10px solid #ccc","margin":"1.5em 10px","padding":"1em 10px"}}>
126+
<Text>Block quotes are often used to highlight important information or provide references.</Text>
127+
</Text></Section>`;
167128

168129
const rendered = parseMarkdownToReactEmail(markdown);
169130
expect(rendered).toBe(expected);

0 commit comments

Comments
 (0)