瀏覽代碼

Merge branch 'release'

Piotrek Koszuliński 5 年之前
父節點
當前提交
8dbcf21788

+ 1 - 0
package.json

@@ -93,6 +93,7 @@
     "@webspellchecker/wproofreader-ckeditor5": "^1.0.5",
     "@wiris/mathtype-ckeditor5": "^7.24.0",
     "babel-standalone": "^6.26.0",
+    "cli-table": "^0.3.1",
     "coveralls": "^3.1.0",
     "css-loader": "^3.5.3",
     "eslint": "^7.1.0",

+ 3 - 0
packages/ckeditor5-engine/src/conversion/downcastdispatcher.js

@@ -314,6 +314,9 @@ export default class DowncastDispatcher {
 			}
 		}
 
+		// After reconversion is done we can unbind the old view.
+		mapper.unbindViewElement( currentView );
+
 		this._clearConversionApi();
 	}
 

+ 49 - 0
packages/ckeditor5-engine/tests/conversion/downcasthelpers.js

@@ -38,6 +38,8 @@ import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_uti
 import { StylesProcessor } from '../../src/view/stylesmap';
 import DowncastWriter from '../../src/view/downcastwriter';
 
+import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils';
+
 describe( 'DowncastHelpers', () => {
 	let model, modelRoot, viewRoot, downcastHelpers, controller, modelRootStart;
 
@@ -192,6 +194,53 @@ describe( 'DowncastHelpers', () => {
 					expectResult( '<div class="is-classy"></div>' );
 				} );
 
+				it( 'should properly re-bind mapper mappings and retain markers', () => {
+					downcastHelpers.elementToElement( {
+						model: 'simpleBlock',
+						view: ( modelElement, { writer } ) => {
+							const viewElement = writer.createContainerElement( 'div', getViewAttributes( modelElement ) );
+
+							return toWidget( viewElement, writer );
+						},
+						triggerBy: {
+							attributes: [ 'toStyle', 'toClass' ]
+						},
+						converterPriority: 'high'
+					} );
+
+					const mapper = controller.mapper;
+
+					downcastHelpers.markerToHighlight( {
+						model: 'myMarker',
+						view: { classes: 'foo' }
+					} );
+
+					setModelData( model, '<simpleBlock></simpleBlock>' );
+
+					const modelElement = modelRoot.getChild( 0 );
+					const [ viewBefore ] = getNodes();
+
+					model.change( writer => {
+						writer.addMarker( 'myMarker', { range: writer.createRangeOn( modelElement ), usingOperation: false } );
+					} );
+
+					expect( mapper.toViewElement( modelElement ) ).to.equal( viewBefore );
+					expect( mapper.toModelElement( viewBefore ) ).to.equal( modelElement );
+					expect( mapper.markerNameToElements( 'myMarker' ).has( viewBefore ) ).to.be.true;
+
+					model.change( writer => {
+						writer.setAttribute( 'toStyle', 'display:block', modelElement );
+					} );
+
+					const [ viewAfter ] = getNodes();
+
+					expect( mapper.toViewElement( modelElement ) ).to.equal( viewAfter );
+					expect( mapper.toModelElement( viewBefore ) ).to.be.undefined;
+					expect( mapper.toModelElement( viewAfter ) ).to.equal( modelElement );
+					expect( mapper.markerNameToElements( 'myMarker' ).has( viewAfter ) ).to.be.true;
+					expect( mapper.markerNameToElements( 'myMarker' ).has( viewBefore ) ).to.be.false;
+				} );
+
 				it( 'should do nothing if non-triggerBy attribute has changed', () => {
 					setModelData( model, '<simpleBlock></simpleBlock>' );
 

+ 85 - 6
packages/ckeditor5-html-embed/docs/features/html-embed.md

@@ -5,11 +5,30 @@ menu-title: HTML embed
 
 # HTML embed
 
-The {@link module:html-embed/htmlembed~HtmlEmbed} plugin provides the possibility to insert a HTML codeinto the rich-text editor.
+The {@link module:html-embed/htmlembed~HtmlEmbed} plugin allows embedding an arbitrary HTML snippet in the editor. The feature is targeted at more advanced users who want to directly interact with HTML fragments.
+
+This feature can be used to embed any HTML code and bypass CKEditor 5's filtering mechanisms. Thanks to that it is possible to enrich content produced by CKEditor 5 with fragments of HTML that are not supported by any other CKEditor 5 feature.
+
+Example of content that can be embedded thanks to the HTML embed feature:
+
+* analytics code (that usually require embedding `<script>` elements),
+* social page widgets (that also require embedding `<script>` elements),
+* content embeddable by `<iframe>`s,
+* HTML media elements such as audio and video,
+* HTML snippets produced by external tools (e.g reports),
+* interactive content that requires a combination of rich HTML and scripts.
+
+It is recommended to use the {@link features/media-embed media embed} feature for embeddable media that are supported by this feature. The HTML embed feature can be used to handle remaining content.
+
+<info-box warning>
+	Read the [Security](#security) section before installing this plugin.
+
+	Incorrect configuration may **lead to security issues**.
+</info-box>
 
 ## Demo
 
-Use the editor below to see the {@link module:html-embed/htmlembed~HtmlEmbed} plugin in action.
+Use the editor below to see the plugin in action.
 
 {@snippet features/html-embed}
 
@@ -39,10 +58,69 @@ ClassicEditor
 	Read more about {@link builds/guides/integration/installing-plugins installing plugins}.
 </info-box>
 
+## Configuration
+
+### Content previews
+
+The feature is by default configured to not show previews of the HTML snippets. The previews can be enabled by setting the {@link module:html-embed/htmlembed~HtmlEmbedConfig#showPreviews `config.htmlEmbed.showPreviews`} option to `true`.
+
+However, by showing previews of embedded HTML snippets you expose the users of your system to the risk of executing malicious JavaScript code inside the editor. Therefore, it is highly recommended to plug an HTML sanitizier that will strip the malicious code from create snippets before rendering their previous. The sanitizer can be plugged by defining the {@link module:html-embed/htmlembed~HtmlEmbedConfig#sanitizeHtml `config.htmlEmbed.sanitizeHtml`} option.
+
+```js
+ClassicEditor
+	.create( document.querySelector( '#editor' ), {
+		plugins: [ HtmlEmbed, ... ],
+		toolbar: [ 'htmlEmbed', ... ],
+		htmlEmbed: {
+			showPreviews: true,
+			sanitizeHtml: ( inputHtml ) => {
+				// Strip unsafe elements and attributes, e.g.:
+				// the `<script>` elements and `on*` attributes.
+				const outputHtml = sanitize( inputHtml );
+
+				return {
+					html: outputHtml,
+					// true or false depending on whether the sanitizer stripped anything.
+					hasChanged: true
+				};
+			}
+		}
+	} )
+	.then( ... )
+	.catch( ... );
+```
+
+Currently, the [feature does not execute `<script>` tags](https://github.com/ckeditor/ckeditor5/issues/8326) so content that requires executing JavaScript in order to generate a preview will not show in the editor. However, other JavaScript code – e.g. used in `on*` observers and `scr="javascript:..."` attributes will be executed and therefore a sanitizer still needs to be enabled.
+
+Read more about the security aspect in the next section.
+
 ### Security
 
-TODO
-Note: it's mentioned in the config.htmlEmbed.* options so if we'll decide to rename this section we'll need to change it there.
+If the HTML embed feature is configured to [show content previews](#content-previews), the HTML that the user inserts into the HTML embed widget is then rendered back to the user. If the HTML was rendered as-is, any JavaScript code included in these HTML snippets would be executed by the browser in context of your website.
+
+This, in turn, is a plain security risk. The HTML provided by the user might be mistakenly copied from a malicious website or end up in the users clipboard (as it would usually be copied and pasted) by any other mean.
+
+In some cases, advanced users can be instructed to never paste HTML code from untrusted sources. However, in most cases, it is highly recommended to properly secure the system by configuring the HTML embed feature to use an HTML sanitizer and, optionally, setting strict CSP rules.
+
+<info-box>
+	The HTML embed feature [does not currently execute code in `<script>` tags](https://github.com/ckeditor/ckeditor5/issues/8326). However, it will execute code in `on*` and `scr="javascript:..."` attributes.
+
+	The tricky part is that some HTML snippets require JavaScript to be executed to render any meaningful previews (e.g. Facebook embeds). Some, in turn, does not make sense to be executed (analytics code).
+
+	Therefore, when configuring the sanitizer and CSP rules, you can take those situations into consideration and for instance allow `<script>` tags pointing only to certain domains (e.g. a trusted external page that requires JavaScript).
+</info-box>
+
+#### Sanitizer
+
+The {@link module:html-embed/htmlembed~HtmlEmbedConfig#sanitizeHtml `config.htmlEmbed.sanitizeHtml`} option allow plugging an external sanitizer.
+
+Some popular JavaScript libraries that can be used include [sanitize-html](https://www.npmjs.com/package/sanitize-html) and [DOMPurify](https://www.npmjs.com/package/dompurify).
+
+The default settings of these libraries usually strip all potentially malicious content including `<iframe>`, `<video>`, etc. elements and JavaScript code coming from trusted sources so you may need to adjust their settings to match your needs.
+
+#### CSP
+
+In addition to using a sanitizer you can use the built browser mechanism called [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). By using CSP you can let the browser know what sources and means to execute JavaScript code and include other resources such as stylesheets, images and fonts are allowed.
 
 ## Common API
 
@@ -51,10 +129,11 @@ The {@link module:html-embed/htmlembed~HtmlEmbed} plugin registers:
 * the `'updateHtmlEmbed'` command implemented by {@link module:html-embed/updatehtmlembedcommand~UpdateHtmlEmbedCommand}.
 * the `'insertHtmlEmbed'` command implemented by {@link module:html-embed/inserthtmlembedcommand~InsertHtmlEmbedCommand}.
 
-The command can be executed using the {@link module:core/editor/editor~Editor#execute `editor.execute()`} method:
+Both commands can be executed using the {@link module:core/editor/editor~Editor#execute `editor.execute()`} method:
 
 ```js
-editor.execute( 'htmlEmbed', { html: 'HTML to insert.' } );
+editor.execute( 'insertHtmlEmbed' );
+editor.execute( 'updateHtmlEmbed', '<p>HTML string</p>' );
 ```
 
 <info-box>

+ 2 - 1
packages/ckeditor5-html-embed/src/htmlembed.js

@@ -88,8 +88,9 @@ export default class HtmlEmbed extends Plugin {
  *
  * 						return {
  * 							html: outputHtml,
+ *							// true or false depending on whether the sanitizer stripped anything.
  * 							hasChanged: ...
- * 						}
+ * 						};
  * 					},
  * 				}
  * 			} )

+ 0 - 1
packages/ckeditor5-media-embed/src/mediaembedui.js

@@ -41,7 +41,6 @@ export default class MediaEmbedUI extends Plugin {
 		const command = editor.commands.get( 'mediaEmbed' );
 		const registry = editor.plugins.get( MediaEmbedEditing ).registry;
 
-		// Setup `imageUpload` button.
 		editor.ui.componentFactory.add( 'mediaEmbed', locale => {
 			const dropdown = createDropdown( locale );
 

+ 101 - 11
scripts/docs/build-content-styles.js

@@ -5,6 +5,8 @@
 
 /* eslint-env node */
 
+const cwd = process.cwd();
+
 const path = require( 'path' );
 const fs = require( 'fs' );
 const chalk = require( 'chalk' );
@@ -12,22 +14,32 @@ const glob = require( 'glob' );
 const mkdirp = require( 'mkdirp' );
 const postcss = require( 'postcss' );
 const webpack = require( 'webpack' );
+const Table = require( 'cli-table' );
 const { tools, styles } = require( '@ckeditor/ckeditor5-dev-utils' );
 const { version } = require( '../../package.json' );
 
 const DESTINATION_DIRECTORY = path.join( __dirname, '..', '..', 'build', 'content-styles' );
+const CONTENT_STYLES_GUIDE_PATH = path.join( __dirname, '..', '..', 'docs', 'builds', 'guides', 'integration', 'content-styles.md' );
+const CONTENT_STYLES_DETAILS_PATH = path.join( __dirname, 'content-styles-details.json' );
+
 const DOCUMENTATION_URL = 'https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/content-styles.html';
+
 const VARIABLE_DEFINITION_REGEXP = /(--[\w-]+):\s+(.*);/g;
 const VARIABLE_USAGE_REGEXP = /var\((--[\w-]+)\)/g;
-const CONTENT_STYLES_GUIDE_PATH = path.join( __dirname, '..', '..', 'docs', 'builds', 'guides', 'integration', 'content-styles.md' );
+
+const contentStylesDetails = require( CONTENT_STYLES_DETAILS_PATH );
+
+// An array of objects with plugins used to generate the current version of the content styles.
+let foundModules;
 
 const contentRules = {
 	selector: [],
 	variables: [],
 	atRules: {}
 };
-const packagesPath = path.join( process.cwd(), 'packages' );
-const shouldUpdateGuide = process.argv.includes( '--commit' );
+
+const packagesPath = path.join( cwd, 'packages' );
+const shouldCommitChanges = process.argv.includes( '--commit' );
 
 logProcess( 'Gathering all CKEditor 5 modules...' );
 
@@ -44,7 +56,7 @@ getCkeditor5ModulePaths()
 				return checkWhetherIsCKEditor5Plugin( modulePath )
 					.then( isModule => {
 						if ( isModule ) {
-							ckeditor5Modules.push( path.join( process.cwd(), modulePath ) );
+							ckeditor5Modules.push( path.join( cwd, modulePath ) );
 						}
 					} );
 			} );
@@ -58,7 +70,9 @@ getCkeditor5ModulePaths()
 
 		return mkdirp( DESTINATION_DIRECTORY ).then( () => generateCKEditor5Source( ckeditor5Modules ) );
 	} )
-	.then( () => {
+	.then( ckeditor5Modules => {
+		foundModules = ckeditor5Modules;
+
 		logProcess( 'Building the editor...' );
 		const webpackConfig = getWebpackConfig();
 
@@ -162,12 +176,40 @@ getCkeditor5ModulePaths()
 	.then( () => {
 		console.log( `Content styles have been extracted to ${ path.join( DESTINATION_DIRECTORY, 'content-styles.css' ) }` );
 
-		if ( !shouldUpdateGuide ) {
+		logProcess( 'Looking for new plugins...' );
+
+		const newPlugins = findNewPlugins( foundModules, contentStylesDetails.plugins );
+
+		if ( newPlugins.length ) {
+			console.log( 'Found new plugins.' );
+			displayNewPluginsTable( newPlugins );
+		} else {
+			console.log( 'Previous and current versions of the content styles stylesheet were generated with the same set of plugins.' );
+		}
+
+		if ( !shouldCommitChanges ) {
 			logProcess( 'Done.' );
 
 			return Promise.resolve();
 		}
 
+		if ( newPlugins.length ) {
+			logProcess( 'Updating the content styles details file...' );
+
+			tools.updateJSONFile( CONTENT_STYLES_DETAILS_PATH, json => {
+				const newPluginsObject = {};
+
+				for ( const data of foundModules ) {
+					const modulePath = normalizePath( data.modulePath.replace( cwd + path.sep, '' ) );
+					newPluginsObject[ modulePath ] = data.pluginName;
+				}
+
+				json.plugins = newPluginsObject;
+
+				return json;
+			} );
+		}
+
 		logProcess( 'Updating the content styles guide...' );
 
 		const promises = [
@@ -184,11 +226,12 @@ getCkeditor5ModulePaths()
 			.then( () => {
 				logProcess( 'Saving and committing...' );
 
-				const contentStyleFile = CONTENT_STYLES_GUIDE_PATH.replace( process.cwd() + path.sep, '' );
+				const contentStyleGuide = CONTENT_STYLES_GUIDE_PATH.replace( cwd + path.sep, '' );
+				const contentStyleDetails = CONTENT_STYLES_DETAILS_PATH.replace( cwd + path.sep, '' );
 
 				// Commit the documentation.
-				if ( exec( `git diff --name-only ${ contentStyleFile }` ).trim().length ) {
-					exec( `git add ${ contentStyleFile }` );
+				if ( exec( `git diff --name-only ${ contentStyleGuide } ${ contentStyleDetails }` ).trim().length ) {
+					exec( `git add ${ contentStyleGuide } ${ contentStyleDetails }` );
 					exec( 'git commit -m "Docs (ckeditor5): Updated the content styles stylesheet."' );
 
 					console.log( 'Successfully updated the content styles guide.' );
@@ -227,7 +270,7 @@ function getCkeditor5ModulePaths() {
  * @returns {Promise.<Boolean>}
  */
 function checkWhetherIsCKEditor5Plugin( modulePath ) {
-	return readFile( path.join( process.cwd(), modulePath ) )
+	return readFile( path.join( cwd, modulePath ) )
 		.then( content => {
 			const pluginName = path.basename( modulePath, '.js' );
 
@@ -278,7 +321,8 @@ function generateCKEditor5Source( ckeditor5Modules ) {
 
 	sourceFileContent.push( '];' );
 
-	return writeFile( path.join( DESTINATION_DIRECTORY, 'source.js' ), sourceFileContent.join( '\n' ) );
+	return writeFile( path.join( DESTINATION_DIRECTORY, 'source.js' ), sourceFileContent.join( '\n' ) )
+		.then( () => ckeditor5Modules );
 
 	function capitalize( value ) {
 		return value.charAt( 0 ).toUpperCase() + value.slice( 1 );
@@ -536,6 +580,52 @@ function transformCssRules( rules ) {
 		.join( '\n' );
 }
 
+/**
+ * Returns an object that contains objects with new plugins.
+ *
+ * @param {Array.<Object>} currentPlugins
+ * @param {Array.<Object>} previousPlugins
+ * @returns {{Array.<Object>}}
+ */
+function findNewPlugins( currentPlugins, previousPlugins ) {
+	const newPlugins = [];
+
+	for ( const data of currentPlugins ) {
+		// Use relative paths.
+		const modulePath = normalizePath( data.modulePath.replace( cwd + path.sep, '' ) );
+
+		if ( !previousPlugins[ modulePath ] ) {
+			newPlugins.push( data );
+		}
+	}
+
+	return newPlugins;
+}
+
+/**
+ * Displays a table with new plugins.
+ *
+ * @param {Array.<Object>} newPlugins
+ */
+function displayNewPluginsTable( newPlugins ) {
+	const table = new Table( {
+		head: [ 'Plugin name', 'Module path' ],
+		style: { compact: true }
+	} );
+
+	for ( const data of newPlugins ) {
+		const modulePath = normalizePath( data.modulePath.replace( cwd + path.sep, '' ) );
+
+		table.push( [ data.pluginName, modulePath ] );
+	}
+
+	console.log( table.toString() );
+}
+
+function normalizePath( modulePath ) {
+	return modulePath.split( path.sep ).join( path.posix.sep );
+}
+
 function exec( command ) {
 	return tools.shExec( command, { verbosity: 'error' } );
 }

+ 178 - 0
scripts/docs/content-styles-details.json

@@ -0,0 +1,178 @@
+{
+  "plugins": {
+    "packages/ckeditor5-alignment/src/alignment.js": "Alignment",
+    "packages/ckeditor5-alignment/src/alignmentediting.js": "Alignmentediting",
+    "packages/ckeditor5-alignment/src/alignmentui.js": "Alignmentui",
+    "packages/ckeditor5-autoformat/src/autoformat.js": "Autoformat",
+    "packages/ckeditor5-autosave/src/autosave.js": "Autosave",
+    "packages/ckeditor5-basic-styles/src/bold.js": "Bold",
+    "packages/ckeditor5-basic-styles/src/bold/boldediting.js": "Boldediting",
+    "packages/ckeditor5-basic-styles/src/bold/boldui.js": "Boldui",
+    "packages/ckeditor5-basic-styles/src/code.js": "Code",
+    "packages/ckeditor5-basic-styles/src/code/codeediting.js": "Codeediting",
+    "packages/ckeditor5-basic-styles/src/code/codeui.js": "Codeui",
+    "packages/ckeditor5-basic-styles/src/italic.js": "Italic",
+    "packages/ckeditor5-basic-styles/src/italic/italicediting.js": "Italicediting",
+    "packages/ckeditor5-basic-styles/src/italic/italicui.js": "Italicui",
+    "packages/ckeditor5-basic-styles/src/strikethrough.js": "Strikethrough",
+    "packages/ckeditor5-basic-styles/src/strikethrough/strikethroughediting.js": "Strikethroughediting",
+    "packages/ckeditor5-basic-styles/src/strikethrough/strikethroughui.js": "Strikethroughui",
+    "packages/ckeditor5-basic-styles/src/subscript.js": "Subscript",
+    "packages/ckeditor5-basic-styles/src/subscript/subscriptediting.js": "Subscriptediting",
+    "packages/ckeditor5-basic-styles/src/subscript/subscriptui.js": "Subscriptui",
+    "packages/ckeditor5-basic-styles/src/superscript.js": "Superscript",
+    "packages/ckeditor5-basic-styles/src/superscript/superscriptediting.js": "Superscriptediting",
+    "packages/ckeditor5-basic-styles/src/superscript/superscriptui.js": "Superscriptui",
+    "packages/ckeditor5-basic-styles/src/underline.js": "Underline",
+    "packages/ckeditor5-basic-styles/src/underline/underlineediting.js": "Underlineediting",
+    "packages/ckeditor5-basic-styles/src/underline/underlineui.js": "Underlineui",
+    "packages/ckeditor5-block-quote/src/blockquote.js": "Blockquote",
+    "packages/ckeditor5-block-quote/src/blockquoteediting.js": "Blockquoteediting",
+    "packages/ckeditor5-block-quote/src/blockquoteui.js": "Blockquoteui",
+    "packages/ckeditor5-ckfinder/src/ckfinder.js": "Ckfinder",
+    "packages/ckeditor5-ckfinder/src/ckfinderediting.js": "Ckfinderediting",
+    "packages/ckeditor5-ckfinder/src/ckfinderui.js": "Ckfinderui",
+    "packages/ckeditor5-clipboard/src/clipboard.js": "Clipboard",
+    "packages/ckeditor5-clipboard/src/pasteplaintext.js": "Pasteplaintext",
+    "packages/ckeditor5-code-block/src/codeblock.js": "Codeblock",
+    "packages/ckeditor5-code-block/src/codeblockediting.js": "Codeblockediting",
+    "packages/ckeditor5-code-block/src/codeblockui.js": "Codeblockui",
+    "packages/ckeditor5-easy-image/src/cloudservicesuploadadapter.js": "Cloudservicesuploadadapter",
+    "packages/ckeditor5-easy-image/src/easyimage.js": "Easyimage",
+    "packages/ckeditor5-enter/src/enter.js": "Enter",
+    "packages/ckeditor5-enter/src/shiftenter.js": "Shiftenter",
+    "packages/ckeditor5-essentials/src/essentials.js": "Essentials",
+    "packages/ckeditor5-font/src/font.js": "Font",
+    "packages/ckeditor5-font/src/fontbackgroundcolor.js": "Fontbackgroundcolor",
+    "packages/ckeditor5-font/src/fontbackgroundcolor/fontbackgroundcolorediting.js": "Fontbackgroundcolorediting",
+    "packages/ckeditor5-font/src/fontcolor.js": "Fontcolor",
+    "packages/ckeditor5-font/src/fontcolor/fontcolorediting.js": "Fontcolorediting",
+    "packages/ckeditor5-font/src/fontfamily.js": "Fontfamily",
+    "packages/ckeditor5-font/src/fontfamily/fontfamilyediting.js": "Fontfamilyediting",
+    "packages/ckeditor5-font/src/fontfamily/fontfamilyui.js": "Fontfamilyui",
+    "packages/ckeditor5-font/src/fontsize.js": "Fontsize",
+    "packages/ckeditor5-font/src/fontsize/fontsizeediting.js": "Fontsizeediting",
+    "packages/ckeditor5-font/src/fontsize/fontsizeui.js": "Fontsizeui",
+    "packages/ckeditor5-font/src/ui/colorui.js": "Colorui",
+    "packages/ckeditor5-heading/src/heading.js": "Heading",
+    "packages/ckeditor5-heading/src/headingbuttonsui.js": "Headingbuttonsui",
+    "packages/ckeditor5-heading/src/headingediting.js": "Headingediting",
+    "packages/ckeditor5-heading/src/headingui.js": "Headingui",
+    "packages/ckeditor5-heading/src/title.js": "Title",
+    "packages/ckeditor5-highlight/src/highlight.js": "Highlight",
+    "packages/ckeditor5-highlight/src/highlightediting.js": "Highlightediting",
+    "packages/ckeditor5-highlight/src/highlightui.js": "Highlightui",
+    "packages/ckeditor5-horizontal-line/src/horizontalline.js": "Horizontalline",
+    "packages/ckeditor5-horizontal-line/src/horizontallineediting.js": "Horizontallineediting",
+    "packages/ckeditor5-horizontal-line/src/horizontallineui.js": "Horizontallineui",
+    "packages/ckeditor5-image/src/image.js": "Image",
+    "packages/ckeditor5-image/src/image/imageediting.js": "Imageediting",
+    "packages/ckeditor5-image/src/imagecaption.js": "Imagecaption",
+    "packages/ckeditor5-image/src/imagecaption/imagecaptionediting.js": "Imagecaptionediting",
+    "packages/ckeditor5-image/src/imageinsert.js": "Imageinsert",
+    "packages/ckeditor5-image/src/imageinsert/imageinsertui.js": "Imageinsertui",
+    "packages/ckeditor5-image/src/imageresize.js": "Imageresize",
+    "packages/ckeditor5-image/src/imageresize/imageresizebuttons.js": "Imageresizebuttons",
+    "packages/ckeditor5-image/src/imageresize/imageresizeediting.js": "Imageresizeediting",
+    "packages/ckeditor5-image/src/imageresize/imageresizehandles.js": "Imageresizehandles",
+    "packages/ckeditor5-image/src/imagestyle.js": "Imagestyle",
+    "packages/ckeditor5-image/src/imagestyle/imagestyleediting.js": "Imagestyleediting",
+    "packages/ckeditor5-image/src/imagestyle/imagestyleui.js": "Imagestyleui",
+    "packages/ckeditor5-image/src/imagetextalternative.js": "Imagetextalternative",
+    "packages/ckeditor5-image/src/imagetextalternative/imagetextalternativeediting.js": "Imagetextalternativeediting",
+    "packages/ckeditor5-image/src/imagetextalternative/imagetextalternativeui.js": "Imagetextalternativeui",
+    "packages/ckeditor5-image/src/imagetoolbar.js": "Imagetoolbar",
+    "packages/ckeditor5-image/src/imageupload.js": "Imageupload",
+    "packages/ckeditor5-image/src/imageupload/imageuploadediting.js": "Imageuploadediting",
+    "packages/ckeditor5-image/src/imageupload/imageuploadprogress.js": "Imageuploadprogress",
+    "packages/ckeditor5-image/src/imageupload/imageuploadui.js": "Imageuploadui",
+    "packages/ckeditor5-indent/src/indent.js": "Indent",
+    "packages/ckeditor5-indent/src/indentblock.js": "Indentblock",
+    "packages/ckeditor5-indent/src/indentediting.js": "Indentediting",
+    "packages/ckeditor5-indent/src/indentui.js": "Indentui",
+    "packages/ckeditor5-link/src/autolink.js": "Autolink",
+    "packages/ckeditor5-link/src/link.js": "Link",
+    "packages/ckeditor5-link/src/linkediting.js": "Linkediting",
+    "packages/ckeditor5-link/src/linkimage.js": "Linkimage",
+    "packages/ckeditor5-link/src/linkimageediting.js": "Linkimageediting",
+    "packages/ckeditor5-link/src/linkimageui.js": "Linkimageui",
+    "packages/ckeditor5-link/src/linkui.js": "Linkui",
+    "packages/ckeditor5-list/src/list.js": "List",
+    "packages/ckeditor5-list/src/listediting.js": "Listediting",
+    "packages/ckeditor5-list/src/liststyle.js": "Liststyle",
+    "packages/ckeditor5-list/src/liststyleediting.js": "Liststyleediting",
+    "packages/ckeditor5-list/src/liststyleui.js": "Liststyleui",
+    "packages/ckeditor5-list/src/listui.js": "Listui",
+    "packages/ckeditor5-list/src/todolist.js": "Todolist",
+    "packages/ckeditor5-list/src/todolistediting.js": "Todolistediting",
+    "packages/ckeditor5-list/src/todolistui.js": "Todolistui",
+    "packages/ckeditor5-markdown-gfm/src/markdown.js": "Markdown",
+    "packages/ckeditor5-media-embed/src/automediaembed.js": "Automediaembed",
+    "packages/ckeditor5-media-embed/src/mediaembed.js": "Mediaembed",
+    "packages/ckeditor5-media-embed/src/mediaembedediting.js": "Mediaembedediting",
+    "packages/ckeditor5-media-embed/src/mediaembedtoolbar.js": "Mediaembedtoolbar",
+    "packages/ckeditor5-media-embed/src/mediaembedui.js": "Mediaembedui",
+    "packages/ckeditor5-mention/src/mention.js": "Mention",
+    "packages/ckeditor5-mention/src/mentionediting.js": "Mentionediting",
+    "packages/ckeditor5-mention/src/mentionui.js": "Mentionui",
+    "packages/ckeditor5-page-break/src/pagebreak.js": "Pagebreak",
+    "packages/ckeditor5-page-break/src/pagebreakediting.js": "Pagebreakediting",
+    "packages/ckeditor5-page-break/src/pagebreakui.js": "Pagebreakui",
+    "packages/ckeditor5-paragraph/src/paragraph.js": "Paragraph",
+    "packages/ckeditor5-paragraph/src/paragraphbuttonui.js": "Paragraphbuttonui",
+    "packages/ckeditor5-paste-from-office/src/pastefromoffice.js": "Pastefromoffice",
+    "packages/ckeditor5-remove-format/src/removeformat.js": "Removeformat",
+    "packages/ckeditor5-remove-format/src/removeformatediting.js": "Removeformatediting",
+    "packages/ckeditor5-remove-format/src/removeformatui.js": "Removeformatui",
+    "packages/ckeditor5-restricted-editing/src/restrictededitingmode.js": "Restrictededitingmode",
+    "packages/ckeditor5-restricted-editing/src/restrictededitingmodeediting.js": "Restrictededitingmodeediting",
+    "packages/ckeditor5-restricted-editing/src/restrictededitingmodeui.js": "Restrictededitingmodeui",
+    "packages/ckeditor5-restricted-editing/src/standardeditingmode.js": "Standardeditingmode",
+    "packages/ckeditor5-restricted-editing/src/standardeditingmodeediting.js": "Standardeditingmodeediting",
+    "packages/ckeditor5-restricted-editing/src/standardeditingmodeui.js": "Standardeditingmodeui",
+    "packages/ckeditor5-select-all/src/selectall.js": "Selectall",
+    "packages/ckeditor5-select-all/src/selectallediting.js": "Selectallediting",
+    "packages/ckeditor5-select-all/src/selectallui.js": "Selectallui",
+    "packages/ckeditor5-special-characters/src/specialcharacters.js": "Specialcharacters",
+    "packages/ckeditor5-special-characters/src/specialcharactersarrows.js": "Specialcharactersarrows",
+    "packages/ckeditor5-special-characters/src/specialcharacterscurrency.js": "Specialcharacterscurrency",
+    "packages/ckeditor5-special-characters/src/specialcharactersessentials.js": "Specialcharactersessentials",
+    "packages/ckeditor5-special-characters/src/specialcharacterslatin.js": "Specialcharacterslatin",
+    "packages/ckeditor5-special-characters/src/specialcharactersmathematical.js": "Specialcharactersmathematical",
+    "packages/ckeditor5-special-characters/src/specialcharacterstext.js": "Specialcharacterstext",
+    "packages/ckeditor5-table/src/table.js": "Table",
+    "packages/ckeditor5-table/src/tablecellproperties.js": "Tablecellproperties",
+    "packages/ckeditor5-table/src/tablecellproperties/tablecellpropertiesediting.js": "Tablecellpropertiesediting",
+    "packages/ckeditor5-table/src/tablecellproperties/tablecellpropertiesui.js": "Tablecellpropertiesui",
+    "packages/ckeditor5-table/src/tableclipboard.js": "Tableclipboard",
+    "packages/ckeditor5-table/src/tableediting.js": "Tableediting",
+    "packages/ckeditor5-table/src/tablekeyboard.js": "Tablekeyboard",
+    "packages/ckeditor5-table/src/tablemouse.js": "Tablemouse",
+    "packages/ckeditor5-table/src/tableproperties.js": "Tableproperties",
+    "packages/ckeditor5-table/src/tableproperties/tablepropertiesediting.js": "Tablepropertiesediting",
+    "packages/ckeditor5-table/src/tableproperties/tablepropertiesui.js": "Tablepropertiesui",
+    "packages/ckeditor5-table/src/tableselection.js": "Tableselection",
+    "packages/ckeditor5-table/src/tabletoolbar.js": "Tabletoolbar",
+    "packages/ckeditor5-table/src/tableui.js": "Tableui",
+    "packages/ckeditor5-table/src/tableutils.js": "Tableutils",
+    "packages/ckeditor5-typing/src/delete.js": "Delete",
+    "packages/ckeditor5-typing/src/input.js": "Input",
+    "packages/ckeditor5-typing/src/texttransformation.js": "Texttransformation",
+    "packages/ckeditor5-typing/src/twostepcaretmovement.js": "Twostepcaretmovement",
+    "packages/ckeditor5-typing/src/typing.js": "Typing",
+    "packages/ckeditor5-ui/src/panel/balloon/contextualballoon.js": "Contextualballoon",
+    "packages/ckeditor5-ui/src/toolbar/balloon/balloontoolbar.js": "Balloontoolbar",
+    "packages/ckeditor5-ui/src/toolbar/block/blocktoolbar.js": "Blocktoolbar",
+    "packages/ckeditor5-undo/src/undo.js": "Undo",
+    "packages/ckeditor5-undo/src/undoediting.js": "Undoediting",
+    "packages/ckeditor5-undo/src/undoui.js": "Undoui",
+    "packages/ckeditor5-upload/src/adapters/base64uploadadapter.js": "Base64uploadadapter",
+    "packages/ckeditor5-upload/src/adapters/simpleuploadadapter.js": "Simpleuploadadapter",
+    "packages/ckeditor5-upload/src/filerepository.js": "Filerepository",
+    "packages/ckeditor5-widget/src/widget.js": "Widget",
+    "packages/ckeditor5-widget/src/widgetresize.js": "Widgetresize",
+    "packages/ckeditor5-widget/src/widgettoolbarrepository.js": "Widgettoolbarrepository",
+    "packages/ckeditor5-widget/src/widgettypearound/widgettypearound.js": "Widgettypearound",
+    "packages/ckeditor5-word-count/src/wordcount.js": "Wordcount"
+  }
+}