Skip to content

Commit

Permalink
fix: don't escape markdown underscores
Browse files Browse the repository at this point in the history
  • Loading branch information
ocavue committed May 7, 2024
1 parent e72a0b2 commit b75115f
Show file tree
Hide file tree
Showing 5 changed files with 735 additions and 634 deletions.
6 changes: 4 additions & 2 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"prettier": "prettier --check \"**/*.{js,ts,tsx,md}\" --cache",
"prettier:fix": "prettier --write \"**/*.{js,ts,tsx,md}\" --cache",
"start": "next start --port 4783",
"test:dev": "vitest run",
"typecheck": "tsc --pretty"
},
"dependencies": {
Expand Down Expand Up @@ -85,13 +86,14 @@
"@hey/types": "workspace:*",
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/forms": "^0.5.6",
"@types/node": "^20.12.9",
"@types/node": "^20.12.9",
"@types/react": "^18.3.1",
"@types/react-dom": "^18.3.0",
"@types/uuid": "^9.0.8",
"autoprefixer": "^10.4.19",
"postcss": "^8.4.38",
"tailwindcss": "^3.4.3",
"typescript": "^5.4.5"
"typescript": "^5.4.5",
"vitest": "^1.6.0"
}
}
53 changes: 53 additions & 0 deletions apps/web/src/helpers/prosekit/markdown.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { describe, expect, test } from 'vitest';

import { htmlFromMarkdown, markdownFromHTML } from './markdown';

describe('markdownFromHTML', () => {
test('should convert HTML to markdown', () => {
const html = '<p>Text <strong>Bold</strong> <em>italic</em></p>';
const markdown = markdownFromHTML(html);
expect(markdown).toMatchInlineSnapshot(`
"Text **Bold** *italic*
"
`);
});

test('should not escape mention handles with _', () => {
const html =
'<p>A normal handle: <span>@lens/foo</span></p>' +
'<p>A handle with underscore: <span>@lens/foo_bar</span></p>'
const markdown = markdownFromHTML(html);
expect(markdown).toContain('@lens/foo');
expect(markdown).toContain('@lens/foo_bar');
expect(markdown).toMatchInlineSnapshot(`
"A normal handle: @lens/foo
A handle with underscore: @lens/foo_bar
"
`);
});
});

describe('htmlFromMarkdown', () => {
test('should convert markdown to HTML', () => {
const markdown = 'Text **Bold** _italic_';
const html = htmlFromMarkdown(markdown);
expect(html).toMatchInlineSnapshot(`
"<p>Text <strong>Bold</strong> <em>italic</em></p>
"
`);
});

test('should not escape mention handles with _', () => {
const markdown = [
'A normal handle: @lens/foo',
'A handle with underscore: @lens/foo_bar'
].join('\n\n');
const html = htmlFromMarkdown(markdown);
expect(html).toMatchInlineSnapshot(`
"<p>A normal handle: @lens/foo</p>
<p>A handle with underscore: @lens/foo_bar</p>
"
`);
});
});
10 changes: 9 additions & 1 deletion apps/web/src/helpers/prosekit/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,22 @@ import remarkParse from 'remark-parse';
import remarkStringify from 'remark-stringify';
import { unified } from 'unified';

// By default, remark-stringify escapes underscores (i.e. "_" => "\_"). We want
// to disable this behavior so that we can have underscores in mention handles.
const unescapeUnderscore = (str: string) => {
return str.replace(/(^|[^\\])\\_/g, '$1_');
};

export const markdownFromHTML = (html: string): string => {
return unified()
const markdown = unified()
.use(rehypeParse)
.use(rehypeRemark)
.use(remarkLinkProtocol)
.use(remarkStringify)
.processSync(html)
.toString();

return unescapeUnderscore(markdown);
};

export const htmlFromMarkdown = (markdown: string): string => {
Expand Down
5 changes: 5 additions & 0 deletions apps/web/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineConfig } from 'vitest/config';

export default defineConfig({
test: { globals: true, testTimeout: 30000, alias: { '@helpers': '/src/helpers' } },
});
Loading

0 comments on commit b75115f

Please sign in to comment.