-
Notifications
You must be signed in to change notification settings - Fork 15
T/49 #70
Changes from 1 commit
fa1853b
839ca44
d1b12fe
14cd006
0d9e547
49a281a
71b38cf
1e7b1f6
a5d4686
c30db0d
3c29e04
394693e
e8c49ef
53068d4
80771ad
e0923a4
4a0e70f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -86,83 +86,114 @@ export default class PluginCollection { | |
* which should not be loaded (despite being specified in the `plugins` array). | ||
* @returns {Promise} A promise which gets resolved once all plugins are loaded and available into the | ||
* collection. | ||
* @returns {Array.<module:core/plugin~Plugin>} returns.loadedPlugins The array of loaded plugins. | ||
* @returns {Promise.<Array.<module:core/plugin~Plugin>>} returns.loadedPlugins The array of loaded plugins. | ||
*/ | ||
load( plugins, removePlugins = [] ) { | ||
const that = this; | ||
const editor = this._editor; | ||
const loading = new Set(); | ||
const loaded = []; | ||
|
||
// Plugins that will be removed can be the constructors or names. | ||
// We need to unify this because we are supporting loading plugins using both types. | ||
removePlugins = removePlugins.reduce( ( arr, PluginConstructorOrName ) => { | ||
arr.push( PluginConstructorOrName ); | ||
|
||
if ( typeof PluginConstructorOrName == 'string' ) { | ||
arr.push( getPluginConstructor( PluginConstructorOrName ) ); | ||
} else if ( PluginConstructorOrName.pluginName ) { | ||
arr.push( PluginConstructorOrName.pluginName ); | ||
} | ||
// In order to avoid using plugin names or constructors alternatively, we map all passed plugin as plugins constructors. | ||
const pluginConstructorsToLoad = plugins | ||
.map( ( item ) => getPluginConstructor( item ) ) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not an item. It's a plugin name or constructor. |
||
.filter( ( PluginConstructor ) => !!PluginConstructor ); | ||
|
||
// Check whether a length of passed array with plugins is the same like an array with mapped plugins. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As you noticed yourself, this comment needs to be refined :D There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Besides, I don't like splitting the filtering which is done above from the check which is done below because it's a single piece of logic – can't find a plugin – throw. OTOH, I can see that when using The code in here could look like this: const missingPlugins = getMissingPlugins( plugins, pluginConstructorsToLoad );
if ( missingPlugins ) {
return Promise.reject();
} |
||
if ( pluginConstructorsToLoad.length !== plugins.length ) { | ||
// Extract names of plugins which cannot be loaded. | ||
const notFoundPlugins = plugins.filter( ( item ) => !pluginConstructorsToLoad.includes( item ) ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that this is a wrong way of getting missing plugins. In |
||
|
||
log.error( 'plugincollection-load: It was not possible to load the plugins.', { plugins: notFoundPlugins } ); | ||
|
||
/** | ||
* The plugins cannot be loaded by name. | ||
* | ||
* Plugin classes need to be provided to the editor before they can be loaded by name. | ||
* This is usually done by the builder. | ||
* | ||
* @error plugincollection-plugin-not-found | ||
* @param {Array.<String>} plugins The name of the plugins which could not be loaded. | ||
*/ | ||
return Promise.reject( new CKEditorError( | ||
'plugincollection-plugin-not-found: The plugin cannot be loaded by name.', | ||
{ plugins: notFoundPlugins } | ||
) ); | ||
|
||
// TODO update this error with links to docs because it will be a frequent problem. | ||
} | ||
|
||
return arr; | ||
}, [] ); | ||
// Plugins that will be removed can be the constructors or names. We need to transform plugin names to plugin constructors. | ||
const pluginConstructorsToRemove = removePlugins.map( ( item ) => getPluginConstructor( item ) ) | ||
.filter( ( PluginConstructor ) => !!PluginConstructor ); | ||
|
||
return Promise.all( plugins.map( loadPlugin ) ) | ||
return Promise.all( pluginConstructorsToLoad.map( loadPlugin ) ) | ||
.then( () => loaded ); | ||
|
||
function loadPlugin( PluginConstructorOrName ) { | ||
function loadPlugin( PluginConstructor ) { | ||
// Don't load the plugin if it cannot be loaded. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment is unnecessary. |
||
if ( removePlugins.includes( PluginConstructorOrName ) ) { | ||
if ( pluginConstructorsToRemove.includes( PluginConstructor ) ) { | ||
return; | ||
} | ||
|
||
// The plugin is already loaded or being loaded - do nothing. | ||
if ( that.get( PluginConstructorOrName ) || loading.has( PluginConstructorOrName ) ) { | ||
if ( that.get( PluginConstructor ) || loading.has( PluginConstructor ) ) { | ||
return; | ||
} | ||
|
||
return instantiatePlugin( PluginConstructorOrName ) | ||
return instantiatePlugin( PluginConstructor ) | ||
.catch( ( err ) => { | ||
/** | ||
* It was not possible to load the plugin. | ||
* | ||
* @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: PluginConstructorOrName } ); | ||
log.error( 'plugincollection-load: It was not possible to load the plugin.', { plugin: PluginConstructor } ); | ||
|
||
throw err; | ||
} ); | ||
} | ||
|
||
function instantiatePlugin( PluginConstructorOrName ) { | ||
function instantiatePlugin( PluginConstructor ) { | ||
return new Promise( ( resolve ) => { | ||
const PluginConstructor = getPluginConstructor( PluginConstructorOrName ); | ||
|
||
loading.add( PluginConstructor ); | ||
|
||
assertIsPlugin( PluginConstructor ); | ||
|
||
if ( PluginConstructor.requires ) { | ||
PluginConstructor.requires.forEach( ( RequiredPluginConstructorOrName ) => { | ||
if ( removePlugins.includes( RequiredPluginConstructorOrName ) ) { | ||
const RequiredPluginConstructor = getPluginConstructor( RequiredPluginConstructorOrName ); | ||
|
||
if ( !RequiredPluginConstructor ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is unnecessary in this PR. It doesn't make sense for a to require other plugins by their names. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PS. I meant that this may be a possible feature in the future, but it's not part of the ticket for which you're making a PR, so it shouldn't be included in it. |
||
/** | ||
* The plugin cannot be loaded by name. | ||
* | ||
* @error plugincollection-plugin-not-found | ||
* @param {String} plugin The name of the plugin which could not be loaded. | ||
*/ | ||
throw new CKEditorError( | ||
'plugincollection-plugin-not-found: The plugin cannot be loaded by name.', | ||
{ plugins: RequiredPluginConstructorOrName } | ||
); | ||
} | ||
|
||
if ( removePlugins.includes( RequiredPluginConstructor ) ) { | ||
/** | ||
* Cannot load a plugin because one of its dependencies is | ||
* listed in the `removePlugins` options. | ||
* Cannot load a plugin because one of its dependencies is listed in the `removePlugins` options. | ||
* | ||
* @error plugincollection-required | ||
* @param {*} plugin The required plugin. | ||
* @param {*} requiredBy The parent plugin. | ||
* @param {Function} plugin The required plugin. | ||
* @param {Function} requiredBy The parent plugin. | ||
*/ | ||
throw new CKEditorError( | ||
'plugincollection-required: Cannot load a plugin because one of its dependencies is listed in' + | ||
'the `removePlugins` options.', | ||
{ plugin: RequiredPluginConstructorOrName, requiredBy: PluginConstructorOrName } | ||
{ plugin: RequiredPluginConstructor, requiredBy: PluginConstructor } | ||
); | ||
} | ||
|
||
loadPlugin( RequiredPluginConstructorOrName ); | ||
loadPlugin( RequiredPluginConstructor ); | ||
} ); | ||
} | ||
|
||
|
@@ -179,27 +210,7 @@ export default class PluginCollection { | |
return PluginConstructorOrName; | ||
} | ||
|
||
const PluginConstructor = that._availablePlugins.get( PluginConstructorOrName ); | ||
|
||
if ( !PluginConstructor ) { | ||
/** | ||
* The plugin cannot be loaded by name. | ||
* | ||
* Plugin classes need to be provided to the editor before they can be loaded by name. | ||
* This is usually done by the builder. | ||
* | ||
* @error plugincollection-plugin-not-found | ||
* @param {String} pluginName The name of the plugin which could not be loaded. | ||
*/ | ||
throw new CKEditorError( | ||
'plugincollection-plugin-not-found: The plugin cannot be loaded by name.', | ||
{ plugin: PluginConstructorOrName } | ||
); | ||
|
||
// TODO update this error with links to docs because it will be a frequent problem. | ||
} | ||
|
||
return PluginConstructor; | ||
return that._availablePlugins.get( PluginConstructorOrName ); | ||
} | ||
|
||
function assertIsPlugin( PluginConstructor ) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is optional.