From 9332d501ad4862517e66c5b4a13eb0db09b3697a Mon Sep 17 00:00:00 2001
From: Evan Jacobs
Date: Mon, 20 Jan 2025 17:01:17 -0500
Subject: [PATCH] refactor: improve inline code performance
---
.changeset/plenty-dodos-collect.md | 5 +++++
.prettierignore | 1 +
__snapshots__/index.compiler.spec.tsx.snap | 6 +++---
fixture.md | 2 +-
index.tsx | 15 ++++++++++-----
5 files changed, 20 insertions(+), 9 deletions(-)
create mode 100644 .changeset/plenty-dodos-collect.md
create mode 100644 .prettierignore
diff --git a/.changeset/plenty-dodos-collect.md b/.changeset/plenty-dodos-collect.md
new file mode 100644
index 00000000..2ab20106
--- /dev/null
+++ b/.changeset/plenty-dodos-collect.md
@@ -0,0 +1,5 @@
+---
+'markdown-to-jsx': patch
+---
+
+Rework inline code syntax handling, handle escaped characters in code blocks correctly so they render without the backslash.
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 00000000..0aed9848
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1 @@
+fixture.md
diff --git a/__snapshots__/index.compiler.spec.tsx.snap b/__snapshots__/index.compiler.spec.tsx.snap
index ceabbfa8..1ca360b3 100644
--- a/__snapshots__/index.compiler.spec.tsx.snap
+++ b/__snapshots__/index.compiler.spec.tsx.snap
@@ -924,7 +924,7 @@ line. To avoid this, you can backslash-escape the period:
- 1986\\. What a great season.
+ 1986. What a great season.
@@ -1433,7 +1433,7 @@ escape it:
- \\*this text is surrounded by literal asterisks\\*
+ *this text is surrounded by literal asterisks*
@@ -1688,7 +1688,7 @@ backslashes before the asterisks, like this:
- \\*literal asterisks\\*
+ *literal asterisks*
diff --git a/fixture.md b/fixture.md
index 9434ec56..ee056899 100644
--- a/fixture.md
+++ b/fixture.md
@@ -745,7 +745,7 @@ escape it:
Code
-To indicate a span of code, wrap it with backtick quotes (`` ` ``).
+To indicate a span of code, wrap it with backtick quotes (`\``).
Unlike a pre-formatted code block, a code span indicates code within a
normal paragraph. For example:
diff --git a/index.tsx b/index.tsx
index bc1c579b..5f4ea85b 100644
--- a/index.tsx
+++ b/index.tsx
@@ -190,7 +190,7 @@ const BREAK_THEMATIC_R = /^(?:( *[-*_])){3,} *(?:\n *)+\n/
const CODE_BLOCK_FENCED_R =
/^(?: {1,3})?(`{3,}|~{3,}) *(\S+)? *([^\n]*?)?\n([\s\S]*?)(?:\1\n?|$)/
const CODE_BLOCK_R = /^(?: {4}[^\n]+\n*)+(?:\n *)+\n?/
-const CODE_INLINE_R = /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/
+const CODE_INLINE_R = /^(`+)((?:\\`|[^`])+)\1/
const CONSECUTIVE_NEWLINE_R = /^(?:\n *)*\n/
const CR_NEWLINE_R = /\r\n?/g
@@ -320,6 +320,7 @@ const TEXT_MARKED_R = new RegExp(`^==${INLINE_SKIP_R}==`)
const TEXT_STRIKETHROUGHED_R = new RegExp(`^~~${INLINE_SKIP_R}~~`)
const TEXT_ESCAPED_R = /^\\([^0-9A-Za-z\s])/
+const TEXT_UNESCAPE_R = /\\([^0-9A-Za-z\s])/g
/**
* Always take the first character, then eagerly take text until a double space
@@ -460,6 +461,7 @@ function generateListRule(
.match(LIST_ITEM_R)
let lastItemWasAParagraph = false
+
const itemContent = items.map(function (item, i) {
// We need to see how far indented the item is:
const space = LIST_ITEM_PREFIX_R.exec(item)[0].length
@@ -495,7 +497,7 @@ function generateListRule(
containsBlocks || (isLastItem && lastItemWasAParagraph)
lastItemWasAParagraph = thisItemIsAParagraph
- // backup our state for restoration afterwards. We're going to
+ // backup our state for delta afterwards. We're going to
// want to set state.list to true, and state.inline depending
// on our list's looseness.
const oldStateInline = state.inline
@@ -1400,7 +1402,10 @@ export function compiler(
parse(capture /*, parse, state*/) {
return {
lang: undefined,
- text: capture[0].replace(/^ {4}/gm, '').replace(/\n+$/, ''),
+ text: capture[0]
+ .replace(/^ {4}/gm, '')
+ .replace(/\n+$/, '')
+ .replaceAll(TEXT_UNESCAPE_R, '$1'),
}
},
@@ -1430,7 +1435,7 @@ export function compiler(
// if capture[3] it's additional metadata
attrs: attrStringToMap('code', capture[3] || ''),
lang: capture[2] || undefined,
- text: capture[4],
+ text: capture[4].replaceAll(TEXT_UNESCAPE_R, '$1'),
type: RuleType.codeBlock,
}
},
@@ -1441,7 +1446,7 @@ export function compiler(
order: Priority.LOW,
parse(capture /*, parse, state*/) {
return {
- text: capture[2],
+ text: capture[2].replaceAll(TEXT_UNESCAPE_R, '$1'),
}
},
render(node, output, state) {