8
0
Pārlūkot izejas kodu

Improved the content styles script.

Kamil Piechaczek 5 gadi atpakaļ
vecāks
revīzija
69b85e964e

+ 1 - 0
package.json

@@ -98,6 +98,7 @@
     "lint-staged": "^10.2.6",
     "mini-css-extract-plugin": "^0.9.0",
     "minimatch": "^3.0.4",
+    "mkdirp": "^1.0.4",
     "nyc": "^15.0.1",
     "postcss-loader": "^3.0.0",
     "progress-bar-webpack-plugin": "^2.1.0",

+ 292 - 18
scripts/docs/build-content-styles.js

@@ -7,26 +7,66 @@
 
 const path = require( 'path' );
 const fs = require( 'fs' );
+const chalk = require( 'chalk' );
+const glob = require( 'glob' );
+const mkdirp = require( 'mkdirp' );
+const postcss = require( 'postcss' );
 const webpack = require( 'webpack' );
-const { styles } = require( '@ckeditor/ckeditor5-dev-utils' );
+const { tools, styles } = require( '@ckeditor/ckeditor5-dev-utils' );
 const { version } = require( '../../package.json' );
 
 const DESTINATION_DIRECTORY = path.join( __dirname, '..', '..', 'build', 'content-styles' );
 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 contentRules = {
 	selector: [],
 	variables: [],
 	atRules: {}
 };
-
-const webpackConfig = getWebpackConfig();
 const packagesPath = path.join( process.cwd(), 'packages' );
+const shouldUpdateGuide = process.argv.includes( '--update-guide' );
+
+logProcess( 'Gathering all CKEditor 5 modules...' );
+
+getCkeditor5ModulePaths()
+	.then( files => {
+		console.log( `Found ${ files.length } files.` );
+		logProcess( 'Filtering CKEditor 5 plugins...' );
+
+		let promise = Promise.resolve();
+		const ckeditor5Modules = [];
+
+		for ( const modulePath of files ) {
+			promise = promise.then( () => {
+				return checkWhetherIsCKEditor5Plugin( modulePath )
+					.then( isModule => {
+						if ( isModule ) {
+							ckeditor5Modules.push( path.join( process.cwd(), modulePath ) );
+						}
+					} );
+			} );
+		}
 
-runWebpack( webpackConfig )
+		return promise.then( () => ckeditor5Modules );
+	} )
+	.then( ckeditor5Modules => {
+		console.log( `Found ${ ckeditor5Modules.length } plugins.` );
+		logProcess( 'Generating source file...' );
+
+		return mkdirp( DESTINATION_DIRECTORY ).then( () => generateCKEditor5Source( ckeditor5Modules ) );
+	} )
 	.then( () => {
+		logProcess( 'Building the editor...' );
+		const webpackConfig = getWebpackConfig();
+
+		return runWebpack( webpackConfig );
+	} )
+	.then( () => {
+		logProcess( 'Preparing the content styles file...' );
+
 		// All variables are placed inside the `:root` selector. Let's extract their names and values as a map.
 		const cssVariables = new Map( contentRules.variables
 			.map( rule => {
@@ -121,12 +161,131 @@ runWebpack( webpackConfig )
 	} )
 	.then( () => {
 		console.log( `Content styles have been extracted to ${ path.join( DESTINATION_DIRECTORY, 'content-styles.css' ) }` );
+
+		if ( !shouldUpdateGuide ) {
+			logProcess( 'Done.' );
+
+			return Promise.resolve();
+		}
+
+		logProcess( 'Updating the content styles guide...' );
+
+		const promises = [
+			readFile( CONTENT_STYLES_GUIDE_PATH ),
+			readFile( path.join( DESTINATION_DIRECTORY, 'content-styles.css' ) )
+		];
+
+		return Promise.all( promises )
+			.then( ( [ guideContent, newContentStyles ] ) => {
+				guideContent = guideContent.replace( /```css([^`]+)```/, newContentStyles );
+
+				return writeFile( CONTENT_STYLES_GUIDE_PATH, guideContent );
+			} )
+			.then( () => {
+				logProcess( 'Saving and committing...' );
+
+				const contentStyleFile = CONTENT_STYLES_GUIDE_PATH.replace( process.cwd() + path.sep, '' );
+
+				// Commit the documentation.
+				if ( exec( `git diff --name-only ${ contentStyleFile }` ).trim().length ) {
+					exec( `git add ${ contentStyleFile }` );
+					exec( 'git commit -m "Docs (ckeditor5): Updated the content styles stylesheet."' );
+
+					console.log( 'Successfully updated the content styles guide.' );
+				} else {
+					console.log( 'Nothing to commit. The content styles guide is up to date.' );
+				}
+
+				logProcess( 'Done.' );
+			} );
 	} )
 	.catch( err => {
 		console.log( err );
 	} );
 
 /**
+ * Resolves the promise with an array of paths to CKEditor 5 modules.
+ *
+ * @returns {Promise.<Array>}
+ */
+function getCkeditor5ModulePaths() {
+	return new Promise( ( resolve, reject ) => {
+		glob( 'packages/*/src/**/*.js', ( err, files ) => {
+			if ( err ) {
+				return reject( err );
+			}
+
+			return resolve( files );
+		} );
+	} );
+}
+
+/**
+ * Resolves the promise with a boolean value that indicates whether the module under `modulePath` is the CKEditor 5 plugin.
+ *
+ * @param modulePath
+ * @returns {Promise.<Boolean>}
+ */
+function checkWhetherIsCKEditor5Plugin( modulePath ) {
+	return readFile( path.join( process.cwd(), modulePath ) )
+		.then( content => {
+			const pluginName = path.basename( modulePath, '.js' );
+
+			if ( content.match( new RegExp( `export default class ${ pluginName } extends Plugin`, 'i' ) ) ) {
+				return Promise.resolve( true );
+			}
+
+			return Promise.resolve( false );
+		} );
+}
+
+/**
+ * Generates a source file that will be used to build the editor.
+ *
+ * @param {Array.<String>} ckeditor5Modules Paths to CKEditor 5 modules.
+ * @returns {Promise>}
+ */
+function generateCKEditor5Source( ckeditor5Modules ) {
+	ckeditor5Modules = ckeditor5Modules.map( modulePath => {
+		const pluginName = capitalize( path.basename( modulePath, '.js' ) );
+		return { modulePath, pluginName };
+	} );
+
+	const sourceFileContent = [
+		'/**',
+		` * @license Copyright (c) 2003-${ new Date().getFullYear() }, CKSource - Frederico Knabben. All rights reserved.`,
+		' * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license',
+		' */',
+		'',
+		'// The editor creator to use.',
+		'import ClassicEditorBase from \'@ckeditor/ckeditor5-editor-classic/src/classiceditor\';',
+		''
+	];
+
+	for ( const { modulePath, pluginName } of ckeditor5Modules ) {
+		sourceFileContent.push( `import ${ pluginName } from '${ modulePath }';` );
+	}
+
+	sourceFileContent.push( '' );
+	sourceFileContent.push( 'export default class ClassicEditor extends ClassicEditorBase {}' );
+	sourceFileContent.push( '' );
+	sourceFileContent.push( '// Plugins to include in the build.' );
+	sourceFileContent.push( 'ClassicEditor.builtinPlugins = [' );
+
+	for ( const { pluginName } of ckeditor5Modules ) {
+		sourceFileContent.push( '\t' + pluginName + ',' );
+	}
+
+	sourceFileContent.push( '];' );
+
+	return writeFile( path.join( DESTINATION_DIRECTORY, 'source.js' ), sourceFileContent.join( '\n' ) );
+
+	function capitalize( value ) {
+		return value.charAt( 0 ).toUpperCase() + value.slice( 1 );
+	}
+}
+
+/**
  * Prepares the configuration for webpack.
  *
  * @returns {Object}
@@ -139,34 +298,24 @@ function getWebpackConfig() {
 		minify: false
 	} );
 
-	const contentStylesPlugin = require( './content-styles/list-content-styles' )( { contentRules } );
-
-	postCssConfig.plugins.push( contentStylesPlugin );
+	postCssConfig.plugins.push( postCssContentStylesPlugin( contentRules ) );
 
 	return {
 		mode: 'development',
-
 		devtool: 'source-map',
-
 		entry: {
-			ckeditor5: path.join( __dirname, 'content-styles', 'ckeditor.js' )
+			ckeditor5: path.join( DESTINATION_DIRECTORY, 'source.js' )
 		},
-
 		output: {
 			path: DESTINATION_DIRECTORY,
 			filename: '[name].js'
 		},
-
-		// Configure the paths so building CKEditor 5 snippets work even if the script
-		// is triggered from a directory outside `ckeditor5` (e.g. in a multi-project case).
 		resolve: {
 			modules: getModuleResolvePaths()
 		},
-
 		resolveLoader: {
 			modules: getModuleResolvePaths()
 		},
-
 		module: {
 			rules: [
 				{
@@ -189,6 +338,92 @@ function getWebpackConfig() {
 }
 
 /**
+ * Returns the PostCSS plugin that allows intercepting CSS definition used in the editor's build.
+ *
+ * @param {Object} contentRules
+ * @param {Array.<String>} contentRules.variables Variables defined as `:root`.
+ * @param {Object} contentRules.atRules Definitions of behaves.
+ * @param {Array.<String>} contentRules.selector CSS definitions for all selectors.
+ * @returns {Function}
+ */
+function postCssContentStylesPlugin( contentRules ) {
+	return postcss.plugin( 'list-content-styles', function() {
+		const selectorStyles = contentRules.selector;
+		const variables = contentRules.variables;
+
+		return root => {
+			root.walkRules( rule => {
+				for ( const selector of rule.selectors ) {
+					const data = {
+						file: root.source.input.file,
+						css: rule.toString()
+					};
+
+					if ( selector.match( ':root' ) ) {
+						addDefinition( variables, data );
+					}
+
+					if ( selector.match( '.ck-content' ) ) {
+						if ( rule.parent.name && rule.parent.params ) {
+							const atRule = getAtRuleArray( contentRules.atRules, rule.parent.name, rule.parent.params );
+
+							addDefinition( atRule, data );
+						} else {
+							addDefinition( selectorStyles, data );
+						}
+					}
+				}
+			} );
+		};
+	} );
+
+	/**
+	 * @param {Object} collection
+	 * @param {String} name Name of an `at-rule`.
+	 * @param {String} params Parameters that describes the `at-rule`.
+	 * @returns {Array}
+	 */
+	function getAtRuleArray( collection, name, params ) {
+		const definition = `${ name } ${ params }`;
+
+		if ( !collection[ definition ] ) {
+			collection[ definition ] = [];
+		}
+
+		return collection[ definition ];
+	}
+
+	/**
+	 * Checks whether specified definition is duplicated in the colletion.
+	 *
+	 * @param {Array.<StyleStructure>} collection
+	 * @param {StyleStructure} def
+	 * @returns {Boolean}
+	 */
+	function isDuplicatedDefinition( collection, def ) {
+		for ( const item of collection ) {
+			if ( item.file === def.file && item.css === def.css ) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Adds definition to the collection if it does not exist in the collection.
+	 *
+	 * @param {Array.<StyleStructure>} collection
+	 * @param {StyleStructure} def
+	 */
+	function addDefinition( collection, def ) {
+		if ( !isDuplicatedDefinition( collection, def ) ) {
+			collection.push( def );
+		}
+	}
+}
+
+/**
  * @param {Object} webpackConfig
  * @returns {Promise}
  */
@@ -216,9 +451,34 @@ function getModuleResolvePaths() {
 	];
 }
 
-function writeFile( file, data ) {
+/**
+ * Resolves the promise with the content of the file saved under the `filePath` location.
+ *
+ * @param {String} filePath The path to fhe file.
+ * @returns {Promise.<String>}
+ */
+function readFile( filePath ) {
 	return new Promise( ( resolve, reject ) => {
-		fs.writeFile( file, data, err => {
+		fs.readFile( filePath, 'utf-8', ( err, content ) => {
+			if ( err ) {
+				return reject( err );
+			}
+
+			return resolve( content );
+		} );
+	} );
+}
+
+/**
+ * Saves the `data` value to the file saved under the `filePath` location.
+ *
+ * @param {String} filePath The path to fhe file.
+ * @param {String} data The content to save.
+ * @returns {Promise.<String>}
+ */
+function writeFile( filePath, data ) {
+	return new Promise( ( resolve, reject ) => {
+		fs.writeFile( filePath, data, err => {
 			if ( err ) {
 				return reject( err );
 			}
@@ -275,3 +535,17 @@ function transformCssRules( rules ) {
 		} )
 		.join( '\n' );
 }
+
+function exec( command ) {
+	return tools.shExec( command, { verbosity: 'error' } );
+}
+
+function logProcess( message ) {
+	console.log( '\n📍 ' + chalk.cyan( message ) );
+}
+
+/**
+ * @typedef {Object} StyleStructure
+ * @property {String} file An absolute path to the file where a definition is defined.
+ * @property {String} css Definition.
+ */

+ 0 - 96
scripts/docs/content-styles/ckeditor.js

@@ -1,96 +0,0 @@
-/**
- * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
- */
-
-// The editor creator to use.
-import ClassicEditorBase from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
-
-import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
-import UploadAdapter from '@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter';
-import Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat';
-import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
-import Code from '@ckeditor/ckeditor5-basic-styles/src/code';
-import CodeBlock from '@ckeditor/ckeditor5-code-block/src/codeblock';
-import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
-import Strikethrough from '@ckeditor/ckeditor5-basic-styles/src/strikethrough';
-import Subscript from '@ckeditor/ckeditor5-basic-styles/src/subscript';
-import Superscript from '@ckeditor/ckeditor5-basic-styles/src/superscript';
-import Underline from '@ckeditor/ckeditor5-basic-styles/src/underline';
-import BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote';
-import CKFinder from '@ckeditor/ckeditor5-ckfinder/src/ckfinder';
-import EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage';
-import Heading from '@ckeditor/ckeditor5-heading/src/heading';
-import HorizontalLine from '@ckeditor/ckeditor5-horizontal-line/src/horizontalline';
-import Image from '@ckeditor/ckeditor5-image/src/image';
-import ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption';
-import ImageResize from '@ckeditor/ckeditor5-image/src/imageresize';
-import ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle';
-import ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar';
-import ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload';
-import Link from '@ckeditor/ckeditor5-link/src/link';
-import List from '@ckeditor/ckeditor5-list/src/list';
-import TodoList from '@ckeditor/ckeditor5-list/src/todolist';
-import MediaEmbed from '@ckeditor/ckeditor5-media-embed/src/mediaembed';
-import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
-import PageBreak from '@ckeditor/ckeditor5-page-break/src/pagebreak';
-import PasteFromOffice from '@ckeditor/ckeditor5-paste-from-office/src/pastefromoffice';
-import SpecialCharacters from '@ckeditor/ckeditor5-special-characters/src/specialcharacters';
-import SpecialCharactersEssentials from '@ckeditor/ckeditor5-special-characters/src/specialcharactersessentials';
-import StandardEditingMode from '@ckeditor/ckeditor5-restricted-editing/src/standardeditingmode';
-import RestrictedEditingMode from '@ckeditor/ckeditor5-restricted-editing/src/restrictededitingmode';
-import Table from '@ckeditor/ckeditor5-table/src/table';
-import TableProperties from '@ckeditor/ckeditor5-table/src/tableproperties';
-import TableCellProperties from '@ckeditor/ckeditor5-table/src/tablecellproperties';
-import TableSelection from '@ckeditor/ckeditor5-table/src/tableselection';
-import TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar';
-import Font from '@ckeditor/ckeditor5-font/src/font';
-import Highlight from '@ckeditor/ckeditor5-highlight/src/highlight';
-import Alignment from '@ckeditor/ckeditor5-alignment/src/alignment';
-
-export default class ClassicEditor extends ClassicEditorBase {}
-
-// Plugins to include in the build.
-ClassicEditor.builtinPlugins = [
-	Essentials,
-	UploadAdapter,
-	Autoformat,
-	Bold,
-	Code,
-	CodeBlock,
-	Italic,
-	Strikethrough,
-	Subscript,
-	Superscript,
-	Underline,
-	BlockQuote,
-	CKFinder,
-	EasyImage,
-	Heading,
-	HorizontalLine,
-	Image,
-	ImageCaption,
-	ImageResize,
-	ImageStyle,
-	ImageToolbar,
-	ImageUpload,
-	Link,
-	List,
-	TodoList,
-	MediaEmbed,
-	PageBreak,
-	Paragraph,
-	PasteFromOffice,
-	SpecialCharacters,
-	SpecialCharactersEssentials,
-	StandardEditingMode,
-	RestrictedEditingMode,
-	Table,
-	TableProperties,
-	TableCellProperties,
-	TableSelection,
-	TableToolbar,
-	Font,
-	Highlight,
-	Alignment
-];

+ 0 - 91
scripts/docs/content-styles/list-content-styles.js

@@ -1,91 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
- */
-
-/* eslint-env node */
-
-const postcss = require( 'postcss' );
-
-module.exports = postcss.plugin( 'list-content-styles', function( options ) {
-	const selectorStyles = options.contentRules.selector;
-	const variables = options.contentRules.variables;
-
-	return root => {
-		root.walkRules( rule => {
-			for ( const selector of rule.selectors ) {
-				const data = {
-					file: root.source.input.file,
-					css: rule.toString()
-				};
-
-				if ( selector.match( ':root' ) ) {
-					addDefinition( variables, data );
-				}
-
-				if ( selector.match( '.ck-content' ) ) {
-					if ( rule.parent.name && rule.parent.params ) {
-						const atRule = getAtRuleArray( options.contentRules.atRules, rule.parent.name, rule.parent.params );
-
-						addDefinition( atRule, data );
-					} else {
-						addDefinition( selectorStyles, data );
-					}
-				}
-			}
-		} );
-	};
-} );
-
-/**
- * @param {Object} collection
- * @param {String} name Name of an `at-rule`.
- * @param {String} params Parameters that describes the `at-rule`.
- * @returns {Array}
- */
-function getAtRuleArray( collection, name, params ) {
-	const definition = `${ name } ${ params }`;
-
-	if ( !collection[ definition ] ) {
-		collection[ definition ] = [];
-	}
-
-	return collection[ definition ];
-}
-
-/**
- * Checks whether specified definition is duplicated in the colletion.
- *
- * @param {Array.<StyleStructure>} collection
- * @param {StyleStructure} def
- * @returns {Boolean}
- */
-function isDuplicatedDefinition( collection, def ) {
-	for ( const item of collection ) {
-		if ( item.file === def.file && item.css === def.css ) {
-			return true;
-		}
-	}
-
-	return false;
-}
-
-/**
- * Adds definition to the collection if it does not exist in the collection.
- *
- * @param {Array.<StyleStructure>} collection
- * @param {StyleStructure} def
- */
-function addDefinition( collection, def ) {
-	if ( !isDuplicatedDefinition( collection, def ) ) {
-		collection.push( def );
-	}
-}
-
-/**
- * @typedef {Object} StyleStructure
- * @property {String} file An absolute path to the file where a definition is defined.
- * @property {String} css Definition.
- */

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1384 - 140
yarn.lock