Skip to content

Commit

Permalink
refactor: simplify lifecycle methods
Browse files Browse the repository at this point in the history
  • Loading branch information
ifiokjr committed May 26, 2020
1 parent cf128f8 commit e0bd75c
Show file tree
Hide file tree
Showing 25 changed files with 389 additions and 619 deletions.
6 changes: 0 additions & 6 deletions @remirror/core-constants/src/core-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,12 +344,6 @@ export enum ManagerPhase {
*/
Create,

/**
* When the extension manager is being initialized. This is when the
* onInitialize methods are being called.
*/
Initialize,

/**
* When the view is being added and all onViewAdded methods are being called.
*/
Expand Down
57 changes: 26 additions & 31 deletions @remirror/core/src/builtins/attributes-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ExtensionPriority } from '@remirror/core-constants';
import { bool, object } from '@remirror/core-helpers';
import { AttributesWithClass, Shape } from '@remirror/core-types';

import { AnyExtension, InitializeLifecycleMethod, PlainExtension } from '../extension';
import { AnyExtension, CreateLifecycleMethod, PlainExtension } from '../extension';
import { AnyPreset } from '../preset';

/**
Expand All @@ -18,7 +18,7 @@ import { AnyPreset } from '../preset';
* @builtin
*/
export class AttributesExtension extends PlainExtension {
public static readonly defaultPriority = ExtensionPriority.High;
public static readonly defaultPriority = ExtensionPriority.Default;

get name() {
return 'attributes' as const;
Expand All @@ -29,41 +29,36 @@ export class AttributesExtension extends PlainExtension {
*
* @internal
*/
public onInitialize: InitializeLifecycleMethod = () => {
public onCreate: CreateLifecycleMethod = (extensions) => {
const attributeList: AttributesWithClass[] = [];
let attributeObject: AttributesWithClass = object();

return {
forEachExtension: (extension) => {
if (
!extension.createAttributes ||
this.store.managerSettings.exclude?.attributes ||
extension.options.exclude?.attributes
) {
return;
}
for (const extension of extensions) {
if (
!extension.createAttributes ||
this.store.managerSettings.exclude?.attributes ||
extension.options.exclude?.attributes
) {
break;
}

// Inserted at the start of the list so that when combining the full
// attribute object the higher priority extension attributes are
// preferred to the lower priority since they merge with the object
// later.
attributeList.unshift(extension.createAttributes());
},
// Inserted at the start of the list so that when combining the full
// attribute object the higher priority extension attributes are
// preferred to the lower priority since they merge with the object
// later.
attributeList.unshift(extension.createAttributes());
}

afterExtensionLoop: () => {
for (const attributes of attributeList) {
attributeObject = {
...attributeObject,
...attributes,
class:
(attributeObject.class ?? '') + (bool(attributes.class) ? attributes.class : '') ||
'',
};
}
for (const attributes of attributeList) {
attributeObject = {
...attributeObject,
...attributes,
class:
(attributeObject.class ?? '') + (bool(attributes.class) ? attributes.class : '') || '',
};
}

this.store.setStoreKey('attributes', attributeObject);
},
};
this.store.setStoreKey('attributes', attributeObject);
};
}

Expand Down
8 changes: 4 additions & 4 deletions @remirror/core/src/builtins/builtin-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ import { TagsExtension } from './tags-extension';
export const builtInExtensions = [
SchemaExtension,
PluginsExtension,
AttributesExtension,
CommandsExtension,
HelpersExtension,
InputRulesExtension,
KeymapExtension,
NodeViewsExtension,
PasteRulesExtension,
SuggestionsExtension,
TagsExtension,
KeymapExtension,
AttributesExtension,
CommandsExtension,
HelpersExtension,
] as const;

/**
Expand Down
102 changes: 49 additions & 53 deletions @remirror/core/src/builtins/commands-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,77 +41,73 @@ export class CommandsExtension extends PlainExtension {
return 'commands' as const;
}

public onCreate: CreateLifecycleMethod = () => {
return {
afterExtensionLoop: () => {
const { setExtensionStore, getStoreKey } = this.store;
public onCreate: CreateLifecycleMethod = (extensions) => {
const { setExtensionStore, getStoreKey } = this.store;

setExtensionStore('getCommands', () => {
const commands = getStoreKey('commands');
invariant(commands, { code: ErrorConstant.COMMANDS_CALLED_IN_OUTER_SCOPE });
setExtensionStore('getCommands', () => {
const commands = getStoreKey('commands');
invariant(commands, { code: ErrorConstant.COMMANDS_CALLED_IN_OUTER_SCOPE });

return commands as any;
});
return commands as any;
});

setExtensionStore('getChain', () => {
const chain = getStoreKey('chain');
invariant(chain, { code: ErrorConstant.COMMANDS_CALLED_IN_OUTER_SCOPE });
setExtensionStore('getChain', () => {
const chain = getStoreKey('chain');
invariant(chain, { code: ErrorConstant.COMMANDS_CALLED_IN_OUTER_SCOPE });

return chain as any;
});
},
};
return chain as any;
});
};

public onView: ViewLifecycleMethod = () => {
const commands: any = object();
public onView: ViewLifecycleMethod = (extensions, view) => {
const commands: Record<string, CommandShape> = object();
const names = new Set<string>();
const chained: Record<string, any> & ChainedCommandRunParameter = object();
const unchained: Record<
string,
{ command: AnyFunction; isEnabled: AnyFunction; name: string }
> = object();

return {
forEachExtension: (extension) => {
if (!extension.createCommands) {
return;
}

const extensionCommands = extension.createCommands();

for (const [name, command] of entries(extensionCommands)) {
throwIfNameNotUnique({ name, set: names, code: ErrorConstant.DUPLICATE_COMMAND_NAMES });
invariant(!forbiddenNames.has(name), {
code: ErrorConstant.DUPLICATE_COMMAND_NAMES,
message: 'The command name you chose is forbidden.',
});

unchained[name] = {
name: extension.name,
command: this.unchainedFactory({ command }),
isEnabled: this.unchainedFactory({ command, shouldDispatch: false }),
};

chained[name] = this.chainedFactory({ command, chained });
}
},
afterExtensionLoop: (view) => {
const { setStoreKey } = this.store;
for (const extension of extensions) {
if (!extension.createCommands) {
break;
}

for (const [commandName, { command, isEnabled }] of entries(unchained)) {
commands[commandName] = command as CommandShape;
commands[commandName].isEnabled = isEnabled;
}
const extensionCommands = extension.createCommands();

chained.run = () => view.dispatch(view.state.tr);
for (const [name, command] of entries(extensionCommands)) {
throwIfNameNotUnique({ name, set: names, code: ErrorConstant.DUPLICATE_COMMAND_NAMES });
invariant(!forbiddenNames.has(name), {
code: ErrorConstant.DUPLICATE_COMMAND_NAMES,
message: 'The command name you chose is forbidden.',
});

setStoreKey('commands', commands);
setStoreKey('chain', chained as never);
},
};
unchained[name] = {
name: extension.name,
command: this.unchainedFactory({ command }),
isEnabled: this.unchainedFactory({ command, shouldDispatch: false }),
};

chained[name] = this.chainedFactory({ command, chained });
}
}

const { setStoreKey } = this.store;

for (const [commandName, { command, isEnabled }] of entries(unchained)) {
commands[commandName] = command as CommandShape;
commands[commandName].isEnabled = isEnabled;
}

chained.run = () => view.dispatch(view.state.tr);

setStoreKey('commands', commands);
setStoreKey('chain', chained as any);
};

/**
* Create the default commands available to all extensions.
*/
public createCommands = () => {
return {
/**
Expand Down
31 changes: 13 additions & 18 deletions @remirror/core/src/builtins/helpers-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,34 +44,29 @@ export class HelpersExtension extends PlainExtension {

return helpers as any;
});

return {};
};

/**
* Helpers are only available once the view has been added to `EditorManager`.
*/
public onView: ViewLifecycleMethod = () => {
public onView: ViewLifecycleMethod = (extensions) => {
const helpers: Record<string, AnyFunction> = object();
const names = new Set<string>();

return {
forEachExtension(extension) {
if (!extension.createHelpers) {
return;
}
for (const extension of extensions) {
if (!extension.createHelpers) {
break;
}

const extensionHelpers = extension.createHelpers();

const extensionHelpers = extension.createHelpers();
for (const [name, helper] of entries(extensionHelpers)) {
throwIfNameNotUnique({ name, set: names, code: ErrorConstant.DUPLICATE_HELPER_NAMES });
helpers[name] = helper;
}
}

for (const [name, helper] of entries(extensionHelpers)) {
throwIfNameNotUnique({ name, set: names, code: ErrorConstant.DUPLICATE_HELPER_NAMES });
helpers[name] = helper;
}
},
afterExtensionLoop: () => {
this.store.setStoreKey('helpers', helpers);
},
};
this.store.setStoreKey('helpers', helpers);
};
}

Expand Down
36 changes: 16 additions & 20 deletions @remirror/core/src/builtins/input-rules-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ExtensionPriority } from '@remirror/core-constants';
import { Shape } from '@remirror/core-types';
import { InputRule, inputRules } from '@remirror/pm/inputrules';

import { InitializeLifecycleMethod, PlainExtension } from '../extension';
import { CreateLifecycleMethod, PlainExtension } from '../extension';

/**
* This extension allows others extension to add the `createInputRules` method
Expand All @@ -25,29 +25,25 @@ export class InputRulesExtension extends PlainExtension {
/**
* Ensure that all ssr transformers are run.
*/
public onInitialize: InitializeLifecycleMethod = () => {
public onCreate: CreateLifecycleMethod = (extensions) => {
const rules: InputRule[] = [];

return {
forEachExtension: (extension) => {
if (
// managerSettings excluded this from running
this.store.managerSettings.exclude?.inputRules ||
// Method doesn't exist
!extension.createInputRules ||
// Extension settings exclude it
extension.options.exclude?.inputRules
) {
return;
}
for (const extension of extensions) {
if (
// managerSettings excluded this from running
this.store.managerSettings.exclude?.inputRules ||
// Method doesn't exist
!extension.createInputRules ||
// Extension settings exclude it
extension.options.exclude?.inputRules
) {
break;
}

rules.push(...extension.createInputRules());
},
rules.push(...extension.createInputRules());
}

afterExtensionLoop: () => {
this.store.addPlugins(inputRules({ rules }));
},
};
this.store.addPlugins(inputRules({ rules }));
};
}

Expand Down
28 changes: 10 additions & 18 deletions @remirror/core/src/builtins/keymap-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { KeyBindings, ProsemirrorPlugin, Shape } from '@remirror/core-types';
import { mergeProsemirrorKeyBindings } from '@remirror/core-utils';
import { keymap } from '@remirror/pm/keymap';

import { AnyExtension, InitializeLifecycleMethod, PlainExtension } from '../extension';
import { AnyExtension, CreateLifecycleMethod, PlainExtension } from '../extension';

/**
* This extension allows others extension to use the `createKeymaps` method.
Expand All @@ -16,7 +16,7 @@ import { AnyExtension, InitializeLifecycleMethod, PlainExtension } from '../exte
* @builtin
*/
export class KeymapExtension extends PlainExtension {
public static readonly defaultPriority = ExtensionPriority.High;
public static readonly defaultPriority = ExtensionPriority.Low;

get name() {
return 'keymap' as const;
Expand All @@ -25,27 +25,19 @@ export class KeymapExtension extends PlainExtension {
private keymap!: ProsemirrorPlugin;
private readonly extensions: AnyExtension[] = [];

public onCreate = () => {
this.store.setExtensionStore('rebuildKeymap', this.rebuildKeymap);

return {};
};

/**
* This adds the `createKeymap` method functionality to all extensions.
*/
public onInitialize: InitializeLifecycleMethod = () => {
public onCreate: CreateLifecycleMethod = (extensions) => {
const extensionKeymaps: KeyBindings[] = [];
this.store.setExtensionStore('rebuildKeymap', this.rebuildKeymap);

return {
forEachExtension: (extension) => {
this.forEachExtension({ extension, extensionKeymaps });
},
afterExtensionLoop: () => {
this.afterExtensionLoop(extensionKeymaps);
this.store.addPlugins(this.keymap);
},
};
for (const extension of extensions) {
this.forEachExtension({ extension, extensionKeymaps });
}

this.afterExtensionLoop(extensionKeymaps);
this.store.addPlugins(this.keymap);
};

/**
Expand Down

0 comments on commit e0bd75c

Please sign in to comment.