Преглед изворни кода

HTML as text is now properly escaped in the output mardown.

fredck пре 5 година
родитељ
комит
52aed7f614

+ 14 - 0
packages/ckeditor5-markdown-gfm/src/html2markdown/html2markdown.js

@@ -6,11 +6,25 @@
 import TurndownService from 'turndown';
 import { gfm } from 'turndown-plugin-gfm';
 
+// Overrides the escape() method, enlarging it.
+{
+	const originalEscape = TurndownService.prototype.escape;
+	TurndownService.prototype.escape = function( string ) {
+		string = originalEscape( string );
+
+		// Escape "<".
+		string = string.replace( /</g, '\\<' );
+
+		return string;
+	};
+}
+
 const turndownService = new TurndownService( {
 	codeBlockStyle: 'fenced',
 	hr: '---',
 	headingStyle: 'atx'
 } );
+
 turndownService.use( [
 	gfm,
 	todoList

+ 41 - 7
packages/ckeditor5-markdown-gfm/tests/gfmdataprocessor/escaping.js

@@ -5,6 +5,7 @@
 
 import MarkdownDataProcessor from '../../src/gfmdataprocessor';
 import { stringify } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
+import { testDataProcessor } from '../../tests/_utils/utils';
 import ViewDocument from '@ckeditor/ckeditor5-engine/src/view/document';
 import { StylesProcessor } from '@ckeditor/ckeditor5-engine/src/view/stylesmap';
 
@@ -26,15 +27,15 @@ const testCases = {
 };
 
 describe( 'GFMDataProcessor', () => {
-	let dataProcessor;
-
-	beforeEach( () => {
-		const viewDocument = new ViewDocument( new StylesProcessor() );
-		dataProcessor = new MarkdownDataProcessor( viewDocument );
-	} );
-
 	describe( 'escaping', () => {
 		describe( 'toView', () => {
+			let dataProcessor;
+
+			beforeEach( () => {
+				const viewDocument = new ViewDocument( new StylesProcessor() );
+				dataProcessor = new MarkdownDataProcessor( viewDocument );
+			} );
+
 			for ( const key in testCases ) {
 				const test = testCases[ key ].test;
 				const result = testCases[ key ].result;
@@ -70,5 +71,38 @@ describe( 'GFMDataProcessor', () => {
 				expect( stringify( documentFragment ) ).to.equal( '<pre><code>\\`</code></pre>' );
 			} );
 		} );
+
+		describe( 'HTML', () => {
+			// To note that the test util inlines entities in text nodes, hence the expected HTML in these tests
+			// contain the raw characters but we "know" that those are text nodes and therefore should be converted
+			// back to entities when outputting markdown.
+
+			it( 'should escape <', () => {
+				testDataProcessor( '\\<', '<p><</p>' );
+			} );
+
+			it( 'should escape HTML as text', () => {
+				testDataProcessor( '\\<h1>Test\\</h1>', '<p><h1>Test</h1></p>' );
+			} );
+
+			it( 'should not escape \\< inside inline code', () => {
+				testDataProcessor( '`\\<`', '<p><code>\\<</code></p>' );
+			} );
+
+			it( 'should not touch escape-like HTML inside code blocks', () => {
+				testDataProcessor(
+					'```\n' +
+					'\\<h1>Test\\</h1>\n' +
+					'```',
+					'<pre><code>' +
+					'\\<h1>Test\\</h1>' +
+					'</code></pre>' );
+			} );
+
+			// Necessary test as we're overriding Turndown's escape(). Just to be sure.
+			it( 'should still escape markdown characters', () => {
+				testDataProcessor( '\\* \\_', '<p>* _</p>' );
+			} );
+		} );
 	} );
 } );