diff --git a/frontend_tests/node_tests/markdown.js b/frontend_tests/node_tests/markdown.js index fce285420e..0f4d2c60b5 100644 --- a/frontend_tests/node_tests/markdown.js +++ b/frontend_tests/node_tests/markdown.js @@ -184,7 +184,7 @@ stream_data.add_sub(amp_stream); run_test("fenced_block_defaults", () => { const input = "\n```\nfenced code\n```\n\nand then after\n"; const expected = - '\n\n
fenced code\n
fenced code\n
fenced code\n
and then after
', + 'fenced code\n
and then after
', }, { input: "\n```\n fenced code trailing whitespace \n```\n\nand then after\n", expected: - ' fenced code trailing whitespace\n
and then after
', + ' fenced code trailing whitespace\n
and then after
', }, { input: "* a\n* list \n* here", @@ -309,12 +309,12 @@ run_test("marked", () => { { input: "\n```c#\nfenced code special\n```\n\nand then after\n", expected: - 'fenced code special\n
and then after
', + 'fenced code special\n
and then after
', }, { input: "\n```vb.net\nfenced code dot\n```\n\nand then after\n", expected: - 'fenced code dot\n
and then after
', + 'fenced code dot\n
and then after
', }, { input: "Some text first\n* a\n* list \n* here\n\nand then after", diff --git a/requirements/dev.txt b/requirements/dev.txt index 293e88fe62..6f4d2d98bc 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -578,9 +578,9 @@ lxml==4.5.2 \ markdown-include==0.6.0 \ --hash=sha256:6f5d680e36f7780c7f0f61dca53ca581bd50d1b56137ddcd6353efafa0c3e4a2 \ # via -r requirements/common.in -markdown==3.2.2 \ - --hash=sha256:1fafe3f1ecabfb514a5285fca634a53c1b32a81cb0feb154264d55bf2ff22c17 \ - --hash=sha256:c467cd6233885534bf0fe96e62e3cf46cfc1605112356c4f9981512b8174de59 \ +markdown==3.3.1 \ + --hash=sha256:10db1204a6c4aff7c7cf3cf25cc02761703baea54b6fb5e2b9ce2c186d81116f \ + --hash=sha256:c3ce9ebb035c078cac0f2036068d054e7dc34354eeecc49c173c33c96b124af6 \ # via -r requirements/common.in, markdown-include markupsafe==1.1.1 \ --hash=sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473 \ diff --git a/requirements/prod.txt b/requirements/prod.txt index 785c16edbe..bb173de28d 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -407,9 +407,9 @@ lxml==4.5.2 \ markdown-include==0.6.0 \ --hash=sha256:6f5d680e36f7780c7f0f61dca53ca581bd50d1b56137ddcd6353efafa0c3e4a2 \ # via -r requirements/common.in -markdown==3.2.2 \ - --hash=sha256:1fafe3f1ecabfb514a5285fca634a53c1b32a81cb0feb154264d55bf2ff22c17 \ - --hash=sha256:c467cd6233885534bf0fe96e62e3cf46cfc1605112356c4f9981512b8174de59 \ +markdown==3.3.1 \ + --hash=sha256:10db1204a6c4aff7c7cf3cf25cc02761703baea54b6fb5e2b9ce2c186d81116f \ + --hash=sha256:c3ce9ebb035c078cac0f2036068d054e7dc34354eeecc49c173c33c96b124af6 \ # via -r requirements/common.in, markdown-include markupsafe==1.1.1 \ --hash=sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473 \ diff --git a/static/shared/js/fenced_code.js b/static/shared/js/fenced_code.js index b65f42a817..cf29e276e3 100644 --- a/static/shared/js/fenced_code.js +++ b/static/shared/js/fenced_code.js @@ -51,7 +51,7 @@ export function wrap_code(code, lang) { } // Trim trailing \n until there's just one left // This mirrors how pygments handles code input - return header + _.escape(code.replace(/^\n+|\n+$/g, "")) + "\n\n"; + return header + _.escape(code.replace(/^\n+|\n+$/g, "")) + "\n"; } function wrap_quote(text) { diff --git a/static/third/marked/lib/marked.js b/static/third/marked/lib/marked.js index 12b69d4179..a8fd74bbba 100644 --- a/static/third/marked/lib/marked.js +++ b/static/third/marked/lib/marked.js @@ -1188,8 +1188,6 @@ Parser.prototype.parse = function(src) { safe = stash[2]; if (!safe) { html = escape(html); - } else { - html += '\n'; } output = output.replace('' + key + '
', html) } diff --git a/version.py b/version.py index 60a0ababf4..663d32cf94 100644 --- a/version.py +++ b/version.py @@ -44,4 +44,4 @@ API_FEATURE_LEVEL = 34 # historical commits sharing the same major version, in which case a # minor version bump suffices. -PROVISION_VERSION = '111.3' +PROVISION_VERSION = '112.0' diff --git a/zerver/lib/markdown/fenced_code.py b/zerver/lib/markdown/fenced_code.py index ed116b8860..50f127cc50 100644 --- a/zerver/lib/markdown/fenced_code.py +++ b/zerver/lib/markdown/fenced_code.py @@ -391,7 +391,7 @@ class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor): lang=(lang or None), noclasses=self.codehilite_conf['noclasses'][0]) - code = highliter.hilite() + code = highliter.hilite().rstrip('\n') else: code = CODE_WRAP.format(langclass, self._escape(text)) diff --git a/zerver/tests/fixtures/markdown_test_cases.json b/zerver/tests/fixtures/markdown_test_cases.json index 291414d3fd..5dd482675a 100644 --- a/zerver/tests/fixtures/markdown_test_cases.json +++ b/zerver/tests/fixtures/markdown_test_cases.json @@ -23,7 +23,7 @@ { "name": "ampampamp", "input": "& & &\n~~~~\n& & &\n~~~~\n & & &", - "expected_output": "& & &
\n& & &\n
& & &\n
& & &
\n& & &\n
& & &\n
Hamlet once said
\ndef func():\n x = 1\n\n y = 2\n\n z = 3\n
And all was good.
", - "text_content": "Hamlet once said\ndef func():\n x = 1\n\n y = 2\n\n z = 3\n\n\n\nAnd all was good." + "expected_output": "Hamlet once said
\ndef func():\n x = 1\n\n y = 2\n\n z = 3\n
And all was good.
", + "text_content": "Hamlet once said\ndef func():\n x = 1\n\n y = 2\n\n z = 3\n\nAnd all was good." }, { "name": "test", @@ -45,8 +45,8 @@ { "name": "codeblock_trailing_whitespace", "input": "Hamlet once said\n~~~~\ndef func():\n x = 1\n\n y = 2\t\t\n\n z = 3 \n~~~~\nAnd all was good.", - "expected_output": "Hamlet once said
\ndef func():\n x = 1\n\n y = 2\n\n z = 3\n
And all was good.
", - "text_content": "Hamlet once said\ndef func():\n x = 1\n\n y = 2\n\n z = 3\n\n\n\nAnd all was good." + "expected_output": "Hamlet once said
\ndef func():\n x = 1\n\n y = 2\n\n z = 3\n
And all was good.
", + "text_content": "Hamlet once said\ndef func():\n x = 1\n\n y = 2\n\n z = 3\n\nAnd all was good." }, { "name": "inline_code_spaces", @@ -63,14 +63,14 @@ { "name": "codeblock_backticks", "input": "\n```\nfenced code\n```\n\n```inline code```\n", - "expected_output": "fenced code\n
inline code
fenced code\n
inline code
Hamlet said:
\ndef speak(self):\n x = 1\n# Comment to make this code block longer to test Trac #1162\n
Then he mentioned y = 4 + x**2
and
def foobar(self):\n return self.baz()\n
Hamlet said:
\ndef speak(self):\n x = 1\n# Comment to make this code block longer to test Trac #1162\n
Then he mentioned y = 4 + x**2
and
def foobar(self):\n return self.baz()\n
I heard about this second hand...
\n\n\nHe said:
\n\n\nThe customer is complaining.
\nThey looked at this code:
\n\n\n\ndef hello(): print 'hello\n
They would prefer:
\ndef hello()
\n
\n puts 'hello'
\nend
Please advise.
\nShe said:\n~~~ quote\nJust send them this:\n```\necho "hello\n"\n```\n
I heard about this second hand...
\n\n\nHe said:
\n\n\nThe customer is complaining.
\nThey looked at this code:
\n\ndef hello(): print 'hello\n
They would prefer:
\ndef hello()
\n
\n puts 'hello'
\nend
Please advise.
\nShe said:\n~~~ quote\nJust send them this:\n```\necho "hello\n"\n```\n
header
\ncontent
\noutside spoiler
", + "expected_output": "header
\ncontent
\noutside spoiler
", "text_content": "header (…)\noutside spoiler" }, { "name": "spoilers_empty_header", "input": "```spoiler\ncontent\n```\noutside spoiler\n", - "expected_output": "content
\noutside spoiler
", + "expected_output": "content
\noutside spoiler
", "text_content": "(…)\noutside spoiler" }, { "name": "spoilers_script_tags", "input": "```spoiler \n\n```", - "expected_output": "<script>alert(1)</script>
\n<script>alert(1)</script>
\n<script>alert(1)</script>\n\n
\n<script>alert(1)</script>\n\n
\n<script>alert(1)</script>
\n<script>alert(1)</script>
\n<script>alert(1)</script>\n\n
\n<script>alert(1)</script>\n\n
\n\n\n\n\n\n\nheader
\n\n\ncontent
\noutside spoiler
\n
outside quote
", + "expected_output": "\n\n\n\nheader
\n\ncontent
\noutside spoiler
\n
outside quote
", "text_content": "> header (…)\n> outside spoiler\n\noutside quote" }, { "name": "spoilers_with_header_markdown", "input": "```spoiler [Header](https://example.com) :smile:\ncontent\n```", - "expected_output": "Header :smile:
\ncontent
\nHeader :smile:
\ncontent
\nheader
\nContent http://example.com/image.png
\nheader
\nContent http://example.com/image.png
\nheader
\nContent http://example.com/image.png
\nheader
\nContent http://example.com/image.png
\n'\n
'\n
@Polonius
', ) imported_polonius_user = UserProfile.objects.get(delivery_email=self.example_email("polonius"), diff --git a/zerver/tests/test_markdown.py b/zerver/tests/test_markdown.py index 109b30ba8d..96c344ff15 100644 --- a/zerver/tests/test_markdown.py +++ b/zerver/tests/test_markdown.py @@ -725,7 +725,7 @@ class MarkdownTest(ZulipTestCase): msg = """\n```spoiler Check out this Pycon Video\nhttps://www.youtube.com/watch?v=0c46YHS3RY8\n```""" converted = markdown_convert_wrapper(msg) - self.assertEqual(converted, 'Check out this Pycon Video
\nCheck out this Pycon Video
\nsecret tweet
\nTweet: {}
\n{}secret tweet
\nTweet: {}
\n{}©
©
Test quote:
©