Răsfoiți Sursa

Removed load.js and the ability to load plugins by name from PluginCollection.

Piotrek Koszuliński 9 ani în urmă
părinte
comite
6bd4ec4ad4

+ 0 - 6
packages/ckeditor5-core/src/editor/editor.js

@@ -12,7 +12,6 @@ import Document from '../../engine/model/document.js';
 import FocusTracker from '../../utils/focustracker.js';
 
 import CKEditorError from '../../utils/ckeditorerror.js';
-import isArray from '../../utils/lib/lodash/isArray.js';
 import mix from '../../utils/mix.js';
 
 /**
@@ -120,11 +119,6 @@ export default class Editor {
 		function loadPlugins() {
 			let plugins = config.get( 'features' ) || [];
 
-			// Handle features passed as a string.
-			if ( !isArray( plugins ) ) {
-				plugins = plugins.split( ',' );
-			}
-
 			return that.plugins.load( plugins );
 		}
 

+ 0 - 35
packages/ckeditor5-core/src/load__amd.js

@@ -1,35 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-// We import the 'require' module, so Require.JS gives us a localized version of require().
-// Otherwise we would use the global one which resolves paths relatively to the base dir.
-import require from 'require';
-
-/**
- * Loads a module.
- *
- *		load( 'ckeditor5/editor.js' )
- *			.then( ( EditorModule ) => {
- *				const Editor = EditorModule.default;
- *			} );
- *
- * @param {String} modulePath Path to the module, relative to `ckeditor.js`'s parent directory (the root).
- * @returns {Promise}
- */
-export default function load( modulePath ) {
-	modulePath = '../../' + modulePath;
-
-	return new Promise( ( resolve, reject ) => {
-		require(
-			[ modulePath ],
-			( module ) => {
-				resolve( module );
-			},
-			( err ) => {
-				reject( err );
-			}
-		);
-	} );
-}

+ 0 - 14
packages/ckeditor5-core/src/load__cjs.js

@@ -1,14 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* global require */
-
-export default function load( modulePath ) {
-	modulePath = '../../' + modulePath;
-
-	return new Promise( ( resolve ) => {
-		resolve( require( modulePath ) );
-	} );
-}

+ 0 - 16
packages/ckeditor5-core/src/load__esnext.js

@@ -1,16 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* global System */
-
-export default function load( modulePath ) {
-	modulePath = '../../' + modulePath;
-
-	return System
-		.import( modulePath )
-		.then( ( module ) => {
-			return module;
-		} );
-}

+ 20 - 60
packages/ckeditor5-core/src/plugincollection.js

@@ -6,7 +6,6 @@
 import Plugin from './plugin.js';
 import CKEditorError from '../utils/ckeditorerror.js';
 import log from '../utils/log.js';
-import load from './load.js';
 
 /**
  * Manages a list of CKEditor plugins, including loading, resolving dependencies and initialization.
@@ -34,17 +33,16 @@ export default class PluginCollection {
 	}
 
 	/**
-	 * Collection iterator. Returns `[ key, plugin ]` pairs. Plugins which are
-	 * kept in the collection twice (under their name and class) will be returned twice.
+	 * Collection iterator. Returns `[ PluginConstructor, pluginInstance ]` pairs.
 	 */
 	[ Symbol.iterator ]() {
 		return this._plugins[ Symbol.iterator ]();
 	}
 
 	/**
-	 * Gets the plugin instance by its name or class.
+	 * Gets the plugin instance by its constructor.
 	 *
-	 * @param {String/Function} key The name of the plugin or the class.
+	 * @param {Function} key The plugin constructor.
 	 * @returns {core.Plugin}
 	 */
 	get( key ) {
@@ -54,7 +52,7 @@ export default class PluginCollection {
 	/**
 	 * Loads a set of plugins and add them to the collection.
 	 *
-	 * @param {String[]} plugins An array of plugins to load.
+	 * @param {Function[]} plugins An array of {@link core.Plugin plugin constructors}.
 	 * @returns {Promise} A promise which gets resolved once all plugins are loaded and available into the
 	 * collection.
 	 * @param {core.Plugin[]} returns.loadedPlugins The array of loaded plugins.
@@ -68,17 +66,13 @@ export default class PluginCollection {
 		return Promise.all( plugins.map( loadPlugin ) )
 			.then( () => loaded );
 
-		function loadPlugin( pluginClassOrName ) {
+		function loadPlugin( PluginConstructor ) {
 			// The plugin is already loaded or being loaded - do nothing.
-			if ( that.get( pluginClassOrName ) || loading.has( pluginClassOrName ) ) {
+			if ( that.get( PluginConstructor ) || loading.has( PluginConstructor ) ) {
 				return;
 			}
 
-			let promise = ( typeof pluginClassOrName == 'string' ) ?
-				loadPluginByName( pluginClassOrName ) :
-				loadPluginByClass( pluginClassOrName );
-
-			return promise
+			return instantiatePlugin( PluginConstructor )
 				.catch( ( err ) => {
 					/**
 					 * It was not possible to load the plugin.
@@ -86,85 +80,51 @@ export default class PluginCollection {
 					 * @error plugincollection-load
 					 * @param {String} plugin The name of the plugin that could not be loaded.
 					 */
-					log.error( 'plugincollection-load: It was not possible to load the plugin.', { plugin: pluginClassOrName } );
+					log.error( 'plugincollection-load: It was not possible to load the plugin.', { plugin: PluginConstructor } );
 
 					throw err;
 				} );
 		}
 
-		function loadPluginByName( pluginName ) {
-			return load( PluginCollection.getPluginPath( pluginName ) )
-				.then( ( PluginModule ) => {
-					return loadPluginByClass( PluginModule.default, pluginName );
-				} );
-		}
-
-		function loadPluginByClass( PluginClass, pluginName ) {
+		function instantiatePlugin( PluginConstructor ) {
 			return new Promise( ( resolve ) => {
-				loading.add( PluginClass );
+				loading.add( PluginConstructor );
 
-				assertIsPlugin( PluginClass );
+				assertIsPlugin( PluginConstructor );
 
-				if ( PluginClass.requires ) {
-					PluginClass.requires.forEach( loadPlugin );
+				if ( PluginConstructor.requires ) {
+					PluginConstructor.requires.forEach( loadPlugin );
 				}
 
-				const plugin = new PluginClass( editor );
-				that._add( PluginClass, plugin );
+				const plugin = new PluginConstructor( editor );
+				that._add( PluginConstructor, plugin );
 				loaded.push( plugin );
 
-				// Expose the plugin also by its name if loaded through load() by name.
-				if ( pluginName ) {
-					that._add( pluginName, plugin );
-				}
-
 				resolve();
 			} );
 		}
 
-		function assertIsPlugin( LoadedPlugin ) {
-			if ( !( LoadedPlugin.prototype instanceof Plugin ) ) {
+		function assertIsPlugin( PluginConstructor ) {
+			if ( !( PluginConstructor.prototype instanceof Plugin ) ) {
 				/**
 				 * The loaded plugin module is not an instance of Plugin.
 				 *
 				 * @error plugincollection-instance
-				 * @param {LoadedPlugin} plugin The class which is meant to be loaded as a plugin.
+				 * @param {*} plugin The constructor which is meant to be loaded as a plugin.
 				 */
 				throw new CKEditorError(
 					'plugincollection-instance: The loaded plugin module is not an instance of Plugin.',
-					{ plugin: LoadedPlugin }
+					{ plugin: PluginConstructor }
 				);
 			}
 		}
 	}
 
-	/**
-	 * Resolves a simplified plugin name to a real path. The returned
-	 * paths are relative to the main `ckeditor.js` file, but they do not start with `./`.
-	 *
-	 * For instance:
-	 *
-	 * * `foo` will be transformed to `ckeditor5/foo/foo.js`,
-	 * * `ui/controller` to `ckeditor5/ui/controller.js` and
-	 * * `foo/bar/bom` to `ckeditor5/foo/bar/bom.js`.
-	 *
-	 * @param {String} name
-	 * @returns {String} Path to the module.
-	 */
-	static getPluginPath( name ) {
-		// Resolve shortened feature names to `featureName/featureName`.
-		if ( name.indexOf( '/' ) < 0 ) {
-			name = name + '/' + name;
-		}
-
-		return 'ckeditor5/' + name + '.js';
-	}
-
 	/**
 	 * Adds the plugin to the collection. Exposed mainly for testing purposes.
 	 *
 	 * @protected
-	 * @param {String/Function} key The name or the plugin class.
+	 * @param {Function} key The plugin constructor.
 	 * @param {core.Plugin} plugin The instance of the plugin.
 	 */
 	_add( key, plugin ) {

+ 0 - 135
packages/ckeditor5-core/tests/_utils-tests/module__amd.js

@@ -1,135 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* globals bender, window, require:true, define:true */
-
-import testUtils from '/tests/core/_utils/utils.js';
-import moduleTestUtils from '/tests/core/_utils/module.js';
-
-testUtils.createSinonSandbox();
-
-describe( 'amdTestUtils', () => {
-	const getModulePath = moduleTestUtils.getModulePath;
-
-	describe( 'getModulePath()', () => {
-		it( 'generates a path from a simple name', () => {
-			const path = getModulePath( 'foo' );
-
-			expect( path ).to.equal( '/ckeditor5/foo.js' );
-		} );
-
-		it( 'generates an absolute path from a simple path', () => {
-			const path = getModulePath( 'engine/dataController' );
-
-			expect( path ).to.equal( '/ckeditor5/engine/dataController.js' );
-		} );
-
-		it( 'does not process an absolute path', () => {
-			const path = getModulePath( '/foo/bar/bom.js' );
-
-			expect( path ).to.equal( '/foo/bar/bom.js' );
-		} );
-	} );
-
-	describe( 'define()', () => {
-		it( 'defines a module by using global define()', () => {
-			const spy = testUtils.sinon.spy( window, 'define' );
-
-			// Required for Sinon's problems with spies on global objects in Safari.
-			define = window.define;
-
-			const expectedDeps = [ 'exports' ].concat( [ 'bar', 'ckeditor' ].map( getModulePath ) );
-
-			moduleTestUtils.define( 'test1', [ 'bar', 'ckeditor' ], () => {} );
-
-			expect( spy.calledOnce ).to.be.true;
-			expect( spy.args[ 0 ][ 0 ] ).to.equal( getModulePath( 'test1' ) );
-			expect( spy.args[ 0 ][ 1 ] ).to.deep.equal( expectedDeps );
-		} );
-
-		it( 'maps body args and returned value', () => {
-			const spy = testUtils.sinon.spy( window, 'define' );
-
-			// Required for Sinon's problems with spies on global objects in Safari.
-			define = window.define;
-
-			const bodySpy = sinon.spy( () => 'ret' );
-
-			moduleTestUtils.define( 'test2', [ 'bar', 'ckeditor' ], bodySpy );
-
-			const realBody = spy.args[ 0 ][ 2 ];
-			const exportsObj = {};
-
-			expect( realBody ).to.be.a( 'function' );
-
-			realBody( exportsObj, { default: 'arg' } );
-
-			expect( exportsObj ).to.have.property( 'default', 'ret', 'it wraps the ret value with an ES6 module obj' );
-			expect( bodySpy.calledOnce ).to.be.true;
-			expect( bodySpy.args[ 0 ][ 0 ] ).to.equal( 'arg', 'it unwraps the args' );
-		} );
-
-		it( 'works with module name and body', () => {
-			const spy = testUtils.sinon.spy( window, 'define' );
-
-			// Required for Sinon's problems with spies on global objects in Safari.
-			define = window.define;
-
-			moduleTestUtils.define( 'test1', () => {} );
-
-			expect( spy.calledOnce ).to.be.true;
-			expect( spy.args[ 0 ][ 0 ] ).to.equal( getModulePath( 'test1' ) );
-			expect( spy.args[ 0 ][ 1 ] ).to.deep.equal( [ 'exports' ] );
-			expect( spy.args[ 0 ][ 2 ] ).to.be.a( 'function' );
-		} );
-
-		// Note: this test only checks whether Require.JS doesn't totally fail when creating a circular dependency.
-		// The value of dependencies are not available anyway inside the amdTestUtils.define() callbacks because
-		// we lose the late-binding by immediately mapping modules to their default exports.
-		it( 'works with circular dependencies', ( done ) => {
-			moduleTestUtils.define( 'test-circular-a', [ 'test-circular-b' ], () => {
-				return 'a';
-			} );
-
-			moduleTestUtils.define( 'test-circular-b', [ 'test-circular-a' ], () => {
-				return 'b';
-			} );
-
-			require( [ 'test-circular-a', 'test-circular-b' ].map( moduleTestUtils.getModulePath ), ( a, b ) => {
-				expect( a ).to.have.property( 'default', 'a' );
-				expect( b ).to.have.property( 'default', 'b' );
-
-				done();
-			} );
-		} );
-	} );
-
-	describe( 'require', () => {
-		it( 'blocks Bender and loads modules through global require()', () => {
-			let requireCb = () => {};
-			const deferCbSpy = sinon.spy();
-
-			testUtils.sinon.stub( bender, 'defer', () => deferCbSpy );
-
-			testUtils.sinon.stub( window, 'require', ( deps, cb ) => {
-				requireCb = cb;
-			} );
-
-			// Required for Sinon's problems with spies on global objects in Safari.
-			require = window.require;
-
-			const modules = moduleTestUtils.require( { foo: 'foo/oof', bar: 'bar' } );
-
-			expect( deferCbSpy.called ).to.be.false;
-
-			requireCb( { default: 1 }, { default: 2 } );
-
-			expect( deferCbSpy.calledOnce ).to.be.true;
-
-			expect( modules ).to.have.property( 'foo', 1 );
-			expect( modules ).to.have.property( 'bar', 2 );
-		} );
-	} );
-} );

+ 0 - 101
packages/ckeditor5-core/tests/_utils-tests/module__cjs.js

@@ -1,101 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* global require, process */
-
-import testUtils from '/tests/core/_utils/utils.js';
-import moduleTestUtils from '/tests/core/_utils/module.js';
-
-testUtils.createSinonSandbox();
-
-const path = require( 'path' );
-const cjsDir = path.join( process.cwd(), 'build', 'cjs' );
-
-describe( 'module utilities', () => {
-	const getModulePath = moduleTestUtils.getModulePath;
-
-	describe( 'getModulePath()', () => {
-		it( 'generates absolute path from a plugin name', () => {
-			const modulePath = getModulePath( 'foo' );
-
-			expect( modulePath ).to.equal( path.join( cjsDir,  '/ckeditor5/foo/foo.js' ) );
-		} );
-
-		it( 'generates an absolute path from a simple path', () => {
-			const modulePath = getModulePath( 'core/editor' );
-
-			expect( modulePath ).to.equal( path.join( cjsDir, '/ckeditor5/core/editor.js' ) );
-		} );
-
-		it( 'does not process an absolute path', () => {
-			const modulePath = getModulePath( '/foo/bar/bom.js' );
-
-			expect( modulePath ).to.equal( path.join( cjsDir, '/foo/bar/bom.js' ) );
-		} );
-	} );
-
-	describe( 'define()', () => {
-		it( 'defines a module using mockery', () => {
-			const mockery = require( 'mockery' );
-			const spy = testUtils.sinon.spy( mockery, 'registerMock' );
-
-			moduleTestUtils.define( 'test1', [ '/ckeditor.js', 'bar' ],  () => {}  );
-
-			expect( spy.calledOnce ).to.be.true;
-			expect( spy.args[ 0 ][ 0 ] ).to.equal( getModulePath( 'test1' ) );
-		} );
-
-		it( 'works with module name and body', () => {
-			const mockery = require( 'mockery' );
-			const spy = testUtils.sinon.spy( mockery, 'registerMock' );
-			const bodySpy = testUtils.sinon.spy( () => {} );
-
-			moduleTestUtils.define( 'test1', bodySpy );
-
-			expect( spy.calledOnce ).to.be.true;
-			expect( spy.args[ 0 ][ 0 ] ).to.equal( getModulePath( 'test1' ) );
-			expect( bodySpy.calledOnce ).to.be.true;
-
-			// No dependencies are passed - check if no arguments were passed to the function.
-			expect( bodySpy.args[ 0 ].length ).to.equal( 0 );
-		} );
-
-		// Note: this test only checks whether CommonJS version of `define()` doesn't totally fail when creating a
-		// circular dependency. The value of dependencies are not available anyway inside the
-		// amdTestUtils.define() callbacks because we lose the late-binding by immediately mapping modules to
-		// their default exports.
-		it( 'works with circular dependencies', () => {
-			moduleTestUtils.define( 'test-circular-a', [ 'test-circular-b' ], () => {
-				return 'a';
-			} );
-
-			moduleTestUtils.define( 'test-circular-b', [ 'test-circular-a' ], () => {
-				return 'b';
-			} );
-
-			const a = require( moduleTestUtils.getModulePath( 'test-circular-a' ) );
-			expect( a ).to.have.property( 'default', 'a' );
-
-			const b = require( moduleTestUtils.getModulePath( 'test-circular-b' ) );
-			expect( b ).to.have.property( 'default', 'b' );
-		} );
-	} );
-
-	describe( 'require', () => {
-		it( 'creates object with loaded modules', () => {
-			// Create first module using mockery library.
-			const mockery = require( 'mockery' );
-			mockery.registerMock( moduleTestUtils.getModulePath( 'module1' ), { default: 'foo' } );
-
-			// Create second module using define.
-			moduleTestUtils.define( 'module2', () => 'bar' );
-
-			const loadedModules = moduleTestUtils.require( { module1: 'module1',  module2: 'module2' } );
-
-			expect( loadedModules.module1 ).to.equal( 'foo' );
-			expect( loadedModules.module2 ).to.equal( 'bar' );
-		} );
-	} );
-} );

+ 0 - 132
packages/ckeditor5-core/tests/_utils/module__amd.js

@@ -1,132 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* globals bender, window */
-
-/**
- * AMD tools related to CKEditor.
- */
-const utils = {
-	/**
-	 * Helper for generating a full module path from a simplified name (similar to simplified plugin naming convention).
-	 *
-	 * Transforms:
-	 *
-	 * * `foo/bar` -> `/ckeditor5/foo/bar.js`
-	 *
-	 * If the path is already absolute, then it will be returned without any changes.
-	 *
-	 * @param {String} modulePath The simplified path.
-	 * @returns {String} The real path.
-	 */
-	getModulePath( modulePath ) {
-		// Do nothing – path is already absolute.
-		if ( modulePath.startsWith( '/' ) ) {
-			return modulePath;
-		}
-
-		return '/ckeditor5/' + modulePath + '.js';
-	},
-
-	/**
-	 * Shorthand for defining an AMD module.
-	 *
-	 * This method uses {@link #getModulePath} to process module and dependency paths so you need to use
-	 * the simplified notation.
-	 *
-	 * For simplicity the dependencies passed to the `body` will be unwrapped
-	 * from the ES6 module object (so only the default export will be available). Also the returned value
-	 * will be automatically handled as a default export.
-	 *
-	 * If you need to define a module which has access to other exports or can export more values,
-	 * use the global `define()` function:
-	 *
-	 *		define( 'my/module', [ 'exports', 'foo', ... ], ( FooModule, ... ) {
-	 *			const FooClass = FooModule.default;
-	 *			const FooOtherProp = FooModule.otherProp;
-	 *
-	 *			exports.default = MyClass;
-	 *			exports.otherProp = 1;
-	 *		} );
-	 *
-	 * **Note:** Since this method automatically unwraps modules from the ES6 module object when passing them
-	 * to the `body` function, circular dependencies will not work. If you need them, either use the raw `define()`
-	 * as shown above, or keep all the definitions outside modules and only access the variables from the scope:
-	 *
-	 *		PluginE = createPlugin( 'E' );
-	 *		PluginF = createPlugin( 'F' );
-	 *
-	 *		PluginF.requires = [ PluginE ];
-	 *		PluginE.requires = [ PluginF ];
-	 *
-	 *		amdTestUtils.define( 'E/E', [ 'plugin', 'F/F' ], () => {
-	 *			return PluginE;
-	 *		} );
-	 *
-	 *		amdTestUtils.define( 'F/F', [ 'plugin', 'E/E' ], () => {
-	 *			return PluginF;
-	 *		} );
-	 *
-	 * @param {String} path Path to the module.
-	 * @param {String[]} deps Dependencies of the module.
-	 * @param {Function} body Module body.
-	 */
-	define( path, deps, body ) {
-		if ( arguments.length == 2 ) {
-			body = deps;
-			deps = [];
-		}
-
-		deps = deps.map( utils.getModulePath );
-
-		// Use the exports object instead of returning from modules in order to handle circular deps.
-		// http://requirejs.org/docs/api.html#circular
-		deps.unshift( 'exports' );
-		window.define( utils.getModulePath( path ), deps, function( exports ) {
-			const loadedDeps = Array.from( arguments ).slice( 1 ).map( ( module ) => module.default );
-
-			exports.default = body.apply( this, loadedDeps );
-		} );
-	},
-
-	/**
-	 * Gets an object which holds the CKEditor modules guaranteed to be loaded before tests start.
-	 *
-	 * This method uses {@link #getModulePath} to process module and dependency paths so you need to use
-	 * the simplified notation.
-	 *
-	 *		const modules = amdTestUtils.require( { modelDocument: 'engine/model/document' } );
-	 *
-	 *		// Later on, inside tests:
-	 *		const ModelDocument = modules.modelDocument;
-	 *
-	 * @params {Object} modules The object (`ref => modulePath`) with modules to be loaded.
-	 * @returns {Object} The object that will hold the loaded modules.
-	 */
-	require( modules ) {
-		const resolved = {};
-		const paths = [];
-		const names = [];
-		const done = bender.defer();
-
-		for ( let name in modules ) {
-			names.push( name );
-			paths.push( utils.getModulePath( modules[ name ] ) );
-		}
-
-		window.require( paths, function( ...loaded ) {
-			for ( let i = 0; i < names.length; i++ ) {
-				resolved[ names[ i ] ] = loaded[ i ].default;
-			}
-
-			// Finally give green light for tests to start.
-			done();
-		} );
-
-		return resolved;
-	}
-};
-
-export default utils;

+ 0 - 119
packages/ckeditor5-core/tests/_utils/module__cjs.js

@@ -1,119 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* globals require, process */
-
-const mockery = require( 'mockery' );
-mockery.enable( {
-	warnOnReplace: false,
-	warnOnUnregistered: false
-} );
-const mocked = [];
-
-const path = require( 'path' );
-
-/**
- * CommonJS tools related to CKEditor.
- */
-const utils = {
-	/**
-	 * Helper for generating an absolute module path from a simplified name.
-	 *
-	 * Transforms:
-	 *
-	 * * `foo` -> `/path/dist/cjs/ckeditor5/foo/foo.js`
-	 * * `foo/bar` -> `/path/dist/cjs/ckeditor5/foo/bar.js`
-	 * * `/ckeditor5/foo.js` -> `/path/dist/cjs/ckeditor5/foo.js`
-	 *
-	 * @param {String} modulePath The simplified path.
-	 * @returns {String} The real path.
-	 */
-	getModulePath( modulePath ) {
-		// Do nothing – path is already absolute.
-		if ( modulePath.startsWith( '/' ) ) {
-			return path.join( process.cwd(), 'build', 'cjs', modulePath );
-		}
-
-		if ( modulePath.indexOf( '/' ) < 0 ) {
-			modulePath = modulePath + '/' + modulePath;
-		}
-
-		return path.join( process.cwd(), 'build', 'cjs', 'ckeditor5', modulePath + '.js' );
-	},
-
-	/**
-	 * Defines module in AMD style using CommonJS modules.
-	 *
-	 * This method uses {@link #getModulePath} to process module and dependency paths so you need to use
-	 * the simplified notation.
-	 *
-	 * For simplicity the dependencies passed to the `body` will be unwrapped
-	 * from the ES6 module object (so only the default export will be available). Also the returned value
-	 * will be automatically handled as a default export.
-	 *
-	 * See also module__amd.js file description.
-	 *
-	 * @param {String} path Path to the module.
-	 * @param {String[]} deps Dependencies of the module.
-	 * @param {Function} body Module body.
-	 */
-	define( path, deps, body ) {
-		if ( arguments.length == 2 ) {
-			body = deps;
-			deps = [];
-		}
-
-		deps = deps
-			.map( ( dependency ) => utils.getModulePath( dependency ) )
-			.map( ( dependency )  => {
-				// Checking if module is already mocked - if module was not mocked it might be a real module.
-				// Using require.resolve to check if module really exists without loading it ( it throws if module is
-				// not present). When module is not mocked and does not exist it will be undefined in module body.
-				try {
-					if ( mocked.indexOf( dependency ) < 0 ) {
-						// Test if required module exists without loading it.
-						require.resolve( dependency );
-					}
-				} catch ( e ) {
-					return;
-				}
-
-				// Return only default export.
-				return require( dependency ).default;
-			} );
-
-		mocked.push( utils.getModulePath( path ) );
-		mockery.registerMock( utils.getModulePath( path ), {
-			default: body.apply( this, deps )
-		} );
-	},
-
-	/**
-	 * Gets an object which holds the CKEditor modules. This function uses synchronous CommonJS `require()`
-	 * method, which means that after executing this method all modules are already loaded.
-	 *
-	 * This method uses {@link #getModulePath} to process module and dependency paths so you need to use
-	 * the simplified notation.
-	 *
-	 *		const modules = amdTestUtils.require( { editor: 'core/Editor' } );
-	 *
-	 *		// Later on, inside tests:
-	 *		const Editor = modules.editor;
-	 *
-	 * @params {Object} modules The object (`ref => modulePath`) with modules to be loaded.
-	 * @returns {Object} The object that will hold the loaded modules.
-	 */
-	require( modules ) {
-		const resolved = {};
-
-		for ( let name in modules ) {
-			resolved[ name ] = require( utils.getModulePath( modules[ name ] ) ).default;
-		}
-
-		return resolved;
-	}
-};
-
-export default utils;

+ 76 - 74
packages/ckeditor5-core/tests/editor/editor.js

@@ -6,21 +6,44 @@
 /* globals setTimeout */
 /* bender-tags: editor, browser-only */
 
-import moduleUtils from '/tests/core/_utils/module.js';
 import Editor from '/ckeditor5/core/editor/editor.js';
 import Plugin from '/ckeditor5/core/plugin.js';
 import Config from '/ckeditor5/utils/config.js';
 import PluginCollection from '/ckeditor5/core/plugincollection.js';
 import FocusTracker from '/ckeditor5/utils/focustracker.js';
 
-const pluginClasses = {};
+class PluginA extends Plugin {
+	constructor( editor ) {
+		super( editor );
+		this.init = sinon.spy().named( 'A' );
+	}
+}
+class PluginB extends Plugin {
+	constructor( editor ) {
+		super( editor );
+		this.init = sinon.spy().named( 'B' );
+	}
+}
+class PluginC extends Plugin {
+	constructor( editor ) {
+		super( editor );
+		this.init = sinon.spy().named( 'C' );
+	}
 
-before( () => {
-	pluginDefinition( 'A/A' );
-	pluginDefinition( 'B/B' );
-	pluginDefinition( 'C/C', [ 'B/B' ] );
-	pluginDefinition( 'D/D', [ 'C/C' ] );
-} );
+	static get requires() {
+		return [ PluginB ];
+	}
+}
+class PluginD extends Plugin {
+	constructor( editor ) {
+		super( editor );
+		this.init = sinon.spy().named( 'D' );
+	}
+
+	static get requires() {
+		return [ PluginC ];
+	}
+}
 
 describe( 'Editor', () => {
 	describe( 'constructor', () => {
@@ -55,12 +78,12 @@ describe( 'Editor', () => {
 
 		it( 'loads plugins', () => {
 			return Editor.create( {
-					features: [ 'A' ]
+					features: [ PluginA ]
 				} )
 				.then( editor => {
 					expect( getPlugins( editor ).length ).to.equal( 1 );
 
-					expect( editor.plugins.get( 'A' ) ).to.be.an.instanceof( Plugin );
+					expect( editor.plugins.get( PluginA ) ).to.be.an.instanceof( Plugin );
 				} );
 		} );
 	} );
@@ -68,7 +91,7 @@ describe( 'Editor', () => {
 	describe( 'initPlugins', () => {
 		it( 'should load features', () => {
 			const editor = new Editor( {
-				features: [ 'A', 'B' ]
+				features: [ PluginA, PluginB ]
 			} );
 
 			expect( getPlugins( editor ) ).to.be.empty;
@@ -76,103 +99,82 @@ describe( 'Editor', () => {
 			return editor.initPlugins().then( () => {
 				expect( getPlugins( editor ).length ).to.equal( 2 );
 
-				expect( editor.plugins.get( 'A' ) ).to.be.an.instanceof( Plugin );
-				expect( editor.plugins.get( 'B' ) ).to.be.an.instanceof( Plugin );
+				expect( editor.plugins.get( PluginA ) ).to.be.an.instanceof( Plugin );
+				expect( editor.plugins.get( PluginB ) ).to.be.an.instanceof( Plugin );
 			} );
 		} );
 
-		it( 'should load features passed as a string', () => {
+		it( 'should initialize plugins in the right order', () => {
 			const editor = new Editor( {
-				features: 'A,B'
+				features: [ PluginA, PluginD ]
 			} );
 
-			expect( getPlugins( editor ) ).to.be.empty;
-
 			return editor.initPlugins().then( () => {
-				expect( getPlugins( editor ).length ).to.equal( 2 );
+				editor.plugins.get( PluginA ).init;
 
-				expect( editor.plugins.get( 'A' ) ).to.be.an.instanceof( Plugin );
-				expect( editor.plugins.get( 'B' ) ).to.be.an.instanceof( Plugin );
-			} );
-		} );
+				editor.plugins.get( PluginB ).init;
 
-		it( 'should initialize plugins in the right order', () => {
-			const editor = new Editor( {
-				features: [ 'A', 'D' ]
-			} );
+				editor.plugins.get( PluginC ).init;
+
+				editor.plugins.get( PluginD ).init;
 
-			return editor.initPlugins().then( () => {
 				sinon.assert.callOrder(
-					editor.plugins.get( pluginClasses[ 'A/A' ] ).init,
-					editor.plugins.get( pluginClasses[ 'B/B' ] ).init,
-					editor.plugins.get( pluginClasses[ 'C/C' ] ).init,
-					editor.plugins.get( pluginClasses[ 'D/D' ] ).init
+					editor.plugins.get( PluginA ).init,
+					editor.plugins.get( PluginB ).init,
+					editor.plugins.get( PluginC ).init,
+					editor.plugins.get( PluginD ).init
 				);
 			} );
 		} );
 
 		it( 'should initialize plugins in the right order, waiting for asynchronous ones', () => {
-			class PluginAsync extends Plugin {}
 			const asyncSpy = sinon.spy().named( 'async-call-spy' );
 
 			// Synchronous plugin that depends on an asynchronous one.
-			pluginDefinition( 'sync/sync', [ 'async/async' ] );
-
-			moduleUtils.define( 'async/async', () => {
-				PluginAsync.prototype.init = sinon.spy( () => {
-					return new Promise( ( resolve ) => {
-						setTimeout( () => {
-							asyncSpy();
-							resolve();
-						}, 0 );
+			class PluginSync extends Plugin {
+				constructor( editor ) {
+					super( editor );
+					this.init = sinon.spy().named( 'sync' );
+				}
+
+				static get requires() {
+					return [ PluginAsync ];
+				}
+			}
+
+			class PluginAsync extends Plugin {
+				constructor( editor ) {
+					super( editor );
+
+					this.init = sinon.spy( () => {
+						return new Promise( ( resolve ) => {
+							setTimeout( () => {
+								asyncSpy();
+								resolve();
+							}, 0 );
+						} );
 					} );
-				} );
-
-				return PluginAsync;
-			} );
+				}
+			}
 
 			const editor = new Editor( {
-				features: [ 'A', 'sync' ]
+				features: [ PluginA, PluginSync ]
 			} );
 
 			return editor.initPlugins().then( () => {
 				sinon.assert.callOrder(
-					editor.plugins.get( pluginClasses[ 'A/A' ] ).init,
+					editor.plugins.get( PluginA ).init,
 					editor.plugins.get( PluginAsync ).init,
 					// This one is called with delay by the async init.
 					asyncSpy,
-					editor.plugins.get( pluginClasses[ 'sync/sync' ] ).init
+					editor.plugins.get( PluginSync ).init
 				);
 			} );
 		} );
 	} );
 } );
 
-// @param {String} name Name of the plugin.
-// @param {String[]} deps Dependencies of the plugin (only other plugins).
-function pluginDefinition( name, deps ) {
-	moduleUtils.define( name, deps || [], function() {
-		class NewPlugin extends Plugin {}
-
-		NewPlugin.prototype.init = sinon.spy().named( name );
-		NewPlugin.requires = Array.from( arguments );
-
-		pluginClasses[ name ] = NewPlugin;
-
-		return NewPlugin;
-	} );
-}
-
-// Returns an array of loaded plugins.
 function getPlugins( editor ) {
-	const plugins = [];
-
-	for ( let entry of editor.plugins ) {
-		// Keep only plugins kept under their classes.
-		if ( typeof entry[ 0 ] == 'function' ) {
-			plugins.push( entry[ 1 ] );
-		}
-	}
-
-	return plugins;
+	return Array.from( editor.plugins )
+		.map( entry => entry[ 1 ] ); // Get instances.
 }

+ 0 - 23
packages/ckeditor5-core/tests/load.js

@@ -1,23 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-import load from '/ckeditor5/core/load.js';
-
-describe( 'load()', () => {
-	it( 'loads plugin.js', () => {
-		return load( 'ckeditor5/core/plugin.js' )
-			.then( ( PluginModule ) => {
-				expect( PluginModule.default ).to.be.a( 'function' );
-			} );
-	} );
-
-	it( 'loads core/editor/editor.js', () => {
-		return load( 'ckeditor5/core/editor/editor.js' )
-			.then( ( EditorModule ) => {
-				expect( EditorModule.default ).to.be.a( 'function' );
-			} );
-	} );
-} );
-

+ 20 - 0
packages/ckeditor5-core/tests/plugin.js

@@ -19,3 +19,23 @@ describe( 'constructor', () => {
 		expect( plugin ).to.have.property( 'editor' ).to.equal( editor );
 	} );
 } );
+
+describe( 'init', () => {
+	it( 'should exist and do nothing', () => {
+		let plugin = new Plugin( editor );
+
+		expect( plugin.init ).to.be.a( 'function' );
+
+		plugin.init();
+	} );
+} );
+
+describe( 'destroy', () => {
+	it( 'should exist and do nothing', () => {
+		let plugin = new Plugin( editor );
+
+		expect( plugin.destroy ).to.be.a( 'function' );
+
+		plugin.destroy();
+	} );
+} );

+ 23 - 119
packages/ckeditor5-core/tests/plugincollection.js

@@ -5,7 +5,6 @@
 
 /* bender-tags: browser-only */
 
-import moduleUtils from '/tests/core/_utils/module.js';
 import testUtils from '/tests/core/_utils/utils.js';
 import Editor from '/ckeditor5/core/editor/editor.js';
 import PluginCollection from '/ckeditor5/core/plugincollection.js';
@@ -15,7 +14,7 @@ import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
 import log from '/ckeditor5/utils/log.js';
 
 let editor;
-let PluginA, PluginB, PluginC, PluginD, PluginE, PluginF, PluginG, PluginH, PluginI;
+let PluginA, PluginB, PluginC, PluginD, PluginE, PluginF, PluginG, PluginH, PluginI, PluginX;
 class TestError extends Error {}
 class GrandPlugin extends Feature {}
 
@@ -31,6 +30,13 @@ before( () => {
 	PluginG = createPlugin( 'G', GrandPlugin );
 	PluginH = createPlugin( 'H' );
 	PluginI = createPlugin( 'I' );
+	PluginX = class extends Plugin {
+		constructor( editor ) {
+			super( editor );
+
+			throw new TestError( 'Some error inside a plugin' );
+		}
+	};
 
 	PluginC.requires = [ PluginB ];
 	PluginD.requires = [ PluginA, PluginC ];
@@ -41,56 +47,6 @@ before( () => {
 	editor = new Editor();
 } );
 
-// Create fake plugins that will be used on tests.
-
-moduleUtils.define( 'A/A', () => {
-	return PluginA;
-} );
-
-moduleUtils.define( 'B/B', () => {
-	return PluginB;
-} );
-
-moduleUtils.define( 'C/C', [ 'core/editor/editor', 'B/B' ], () => {
-	return PluginC;
-} );
-
-moduleUtils.define( 'D/D', [ 'core/editor/editor', 'A/A', 'C/C' ], () => {
-	return PluginD;
-} );
-
-moduleUtils.define( 'E/E', [ 'core/editor/editor', 'F/F' ], () => {
-	return PluginE;
-} );
-
-moduleUtils.define( 'F/F', [ 'core/editor/editor', 'E/E' ], () => {
-	return PluginF;
-} );
-
-moduleUtils.define( 'G/G', () => {
-	return PluginG;
-} );
-
-moduleUtils.define( 'H/H', () => {
-	return PluginH;
-} );
-
-moduleUtils.define( 'I/I', () => {
-	return PluginI;
-} );
-
-// Erroneous cases.
-
-moduleUtils.define( 'X/X', () => {
-	throw new TestError( 'Some error inside a plugin' );
-} );
-
-moduleUtils.define( 'Y/Y', () => {
-	return class {};
-} );
-
-/////////////
-
 describe( 'load', () => {
 	it( 'should not fail when trying to load 0 plugins (empty array)', () => {
 		let plugins = new PluginCollection( editor );
@@ -104,15 +60,12 @@ describe( 'load', () => {
 	it( 'should add collection items for loaded plugins', () => {
 		let plugins = new PluginCollection( editor );
 
-		return plugins.load( [ 'A', 'B' ] )
+		return plugins.load( [ PluginA, PluginB ] )
 			.then( () => {
 				expect( getPlugins( plugins ).length ).to.equal( 2 );
 
 				expect( plugins.get( PluginA ) ).to.be.an.instanceof( PluginA );
 				expect( plugins.get( PluginB ) ).to.be.an.instanceof( PluginB );
-
-				expect( plugins.get( 'A' ) ).to.be.an.instanceof( PluginA );
-				expect( plugins.get( 'B' ) ).to.be.an.instanceof( PluginB );
 			} );
 	} );
 
@@ -120,7 +73,7 @@ describe( 'load', () => {
 		let plugins = new PluginCollection( editor );
 		let spy = sinon.spy( plugins, '_add' );
 
-		return plugins.load( [ 'A', 'C' ] )
+		return plugins.load( [ PluginA, PluginC ] )
 			.then( ( loadedPlugins ) => {
 				expect( getPlugins( plugins ).length ).to.equal( 3 );
 
@@ -135,7 +88,7 @@ describe( 'load', () => {
 		let plugins = new PluginCollection( editor );
 		let spy = sinon.spy( plugins, '_add' );
 
-		return plugins.load( [ 'A', 'B', 'C' ] )
+		return plugins.load( [ PluginA, PluginB, PluginC ] )
 			.then( ( loadedPlugins ) => {
 				expect( getPlugins( plugins ).length ).to.equal( 3 );
 
@@ -150,7 +103,7 @@ describe( 'load', () => {
 		let plugins = new PluginCollection( editor );
 		let spy = sinon.spy( plugins, '_add' );
 
-		return plugins.load( [ 'D' ] )
+		return plugins.load( [ PluginD ] )
 			.then( ( loadedPlugins ) => {
 				expect( getPlugins( plugins ).length ).to.equal( 4 );
 
@@ -166,7 +119,7 @@ describe( 'load', () => {
 		let plugins = new PluginCollection( editor );
 		let spy = sinon.spy( plugins, '_add' );
 
-		return plugins.load( [ 'A', 'E' ] )
+		return plugins.load( [ PluginA, PluginE ] )
 			.then( ( loadedPlugins ) => {
 				expect( getPlugins( plugins ).length ).to.equal( 3 );
 
@@ -181,48 +134,19 @@ describe( 'load', () => {
 	it( 'should load grand child classes', () => {
 		let plugins = new PluginCollection( editor );
 
-		return plugins.load( [ 'G' ] )
+		return plugins.load( [ PluginG ] )
 			.then( () => {
 				expect( getPlugins( plugins ).length ).to.equal( 1 );
 			} );
 	} );
 
-	it( 'should make plugin available to get by name when plugin was loaded as dependency first', () => {
-		let plugins = new PluginCollection( editor );
-
-		return plugins.load( [ 'H', 'I' ] )
-			.then( () => {
-				expect( plugins.get( 'I' ) ).to.be.instanceof( PluginI );
-			} );
-	} );
-
 	it( 'should set the `editor` property on loaded plugins', () => {
 		let plugins = new PluginCollection( editor );
 
-		return plugins.load( [ 'A', 'B' ] )
+		return plugins.load( [ PluginA, PluginB ] )
 			.then( () => {
-				expect( plugins.get( 'A' ).editor ).to.equal( editor );
-				expect( plugins.get( 'B' ).editor ).to.equal( editor );
-			} );
-	} );
-
-	it( 'should reject on invalid plugin names (forward require.js loading error)', () => {
-		let logSpy = testUtils.sinon.stub( log, 'error' );
-
-		let plugins = new PluginCollection( editor );
-
-		return plugins.load( [ 'A', 'BAD', 'B' ] )
-			// Throw here, so if by any chance plugins.load() was resolved correctly catch() will be stil executed.
-			.then( () => {
-				throw new Error( 'Test error: this promise should not be resolved successfully' );
-			} )
-			.catch( ( err ) => {
-				expect( err ).to.be.an.instanceof( Error );
-				// Make sure it's the Require.JS error, not the one thrown above.
-				expect( err.message ).to.match( /^Script error for/ );
-
-				sinon.assert.calledOnce( logSpy );
-				expect( logSpy.args[ 0 ][ 0 ] ).to.match( /^plugincollection-load:/ );
+				expect( plugins.get( PluginA ).editor ).to.equal( editor );
+				expect( plugins.get( PluginB ).editor ).to.equal( editor );
 			} );
 	} );
 
@@ -231,7 +155,7 @@ describe( 'load', () => {
 
 		let plugins = new PluginCollection( editor );
 
-		return plugins.load( [ 'A', 'X', 'B' ] )
+		return plugins.load( [ PluginA, PluginX, PluginB ] )
 			// Throw here, so if by any chance plugins.load() was resolved correctly catch() will be stil executed.
 			.then( () => {
 				throw new Error( 'Test error: this promise should not be resolved successfully' );
@@ -250,7 +174,9 @@ describe( 'load', () => {
 
 		let plugins = new PluginCollection( editor );
 
-		return plugins.load( [ 'Y' ] )
+		class Y {}
+
+		return plugins.load( [ Y ] )
 			// Throw here, so if by any chance plugins.load() was resolved correctly catch() will be stil executed.
 			.then( () => {
 				throw new Error( 'Test error: this promise should not be resolved successfully' );
@@ -265,20 +191,6 @@ describe( 'load', () => {
 	} );
 } );
 
-describe( 'getPluginPath()', () => {
-	it( 'generates path for modules within some package', () => {
-		const p = PluginCollection.getPluginPath( 'some/ba' );
-
-		expect( p ).to.equal( 'ckeditor5/some/ba.js' );
-	} );
-
-	it( 'generates path from simplified feature name', () => {
-		const p = PluginCollection.getPluginPath( 'foo' );
-
-		expect( p ).to.equal( 'ckeditor5/foo/foo.js' );
-	} );
-} );
-
 function createPlugin( name, baseClass ) {
 	baseClass = baseClass || Plugin;
 
@@ -295,16 +207,8 @@ function createPlugin( name, baseClass ) {
 }
 
 function getPlugins( pluginCollection ) {
-	const plugins = [];
-
-	for ( let entry of pluginCollection ) {
-		// Keep only plugins kept under their classes.
-		if ( typeof entry[ 0 ] == 'function' ) {
-			plugins.push( entry[ 1 ] );
-		}
-	}
-
-	return plugins;
+	return Array.from( pluginCollection )
+		.map( entry => entry[ 1 ] ); // Get instances.
 }
 
 function getPluginsFromSpy( addSpy ) {