Skip to content

Commit

Permalink
Merge pull request #24 from yandex-cloud/shared-builder
Browse files Browse the repository at this point in the history
* feat(core)!: use one builder for all plug-in extensions
* feat(core): move plugins sorting to the extension builder
  • Loading branch information
d3m1d0v authored Oct 14, 2022
2 parents dc66438 + fcc4d35 commit 048ea1c
Show file tree
Hide file tree
Showing 63 changed files with 196 additions and 375 deletions.
54 changes: 26 additions & 28 deletions demo/Playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import {RadioButton, TextInput} from '@gravity-ui/uikit';
import {
BasePreset,
BehaviorPreset,
createExtension,
MarkdownBlocksPreset,
MarkdownMarksPreset,
MarkupString,
YfmEditorComponent,
useYfmEditor,
YfmPreset,
Extension,
} from '../src';
import {PlaygroundHtmlPreview} from './HtmlPreview';
import {logger} from '../src/index';
Expand Down Expand Up @@ -43,33 +43,31 @@ export const Playground = React.memo<PlaygroundProps>((props) => {
const [previewType, setPreviewType] = React.useState<string>(PreviewType.Markup);
const [yfmRaw, setYfmRaw] = React.useState<MarkupString>(initial || '');

const extensions = React.useMemo(() => {
return [
createExtension((builder) =>
builder
.use(BasePreset, {})
.use(BehaviorPreset, {
history: {
undoKey: keys.undo,
redoKey: keys.redo,
},
})
.use(MarkdownBlocksPreset, {
image: false,
heading: false,
breaks: {preferredBreak: breaks ? 'soft' : 'hard'},
})
.use(MarkdownMarksPreset, {
bold: {boldKey: keys.bold},
italic: {italicKey: keys.italic},
strike: {strikeKey: keys.strike},
underline: {underlineKey: keys.underline},
code: {codeKey: keys.code},
})
.use(YfmPreset, {}),
)(),
];
}, [breaks]);
const extensions = React.useMemo<Extension>(
() => (builder) =>
builder
.use(BasePreset, {})
.use(BehaviorPreset, {
history: {
undoKey: keys.undo,
redoKey: keys.redo,
},
})
.use(MarkdownBlocksPreset, {
image: false,
heading: false,
breaks: {preferredBreak: breaks ? 'soft' : 'hard'},
})
.use(MarkdownMarksPreset, {
bold: {boldKey: keys.bold},
italic: {italicKey: keys.italic},
strike: {strikeKey: keys.strike},
underline: {underlineKey: keys.underline},
code: {codeKey: keys.code},
})
.use(YfmPreset, {}),
[breaks],
);

const editor = useYfmEditor({
linkify,
Expand Down
6 changes: 3 additions & 3 deletions src/core/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {EditorView} from 'prosemirror-view';
import {EditorState} from 'prosemirror-state';

import type {CommonEditor, ContentHandler, MarkupString} from '../common';
import type {ExtensionSpec} from './types/extension';
import type {Extension} from './types/extension';
import {bindActions} from './utils/actions';
import type {Serializer} from './types/serializer';
import {ExtensionsManager} from './ExtensionsManager';
Expand All @@ -17,7 +17,7 @@ export type YfmEditorOptions = {
domElem?: Element;
/** yfm markup */
initialContent?: string;
extensions?: ExtensionSpec[];
extensions?: Extension;
allowHTML?: boolean;
linkify?: boolean;
/** markdown-it-attrs options */
Expand Down Expand Up @@ -48,7 +48,7 @@ export class YfmEditor implements CommonEditor, ActionStorage {
constructor({
domElem,
initialContent = '',
extensions = [],
extensions = () => {},
attrs: attrsOpts,
allowHTML,
linkify,
Expand Down
19 changes: 19 additions & 0 deletions src/core/ExtensionBuilder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,25 @@ describe('ExtensionBuilder', () => {
expect(plugins.length).toBe(2);
});

it('should sort plugins by priority', () => {
const plugin0 = new Plugin({});
const plugin1 = new Plugin({});
const plugin2 = new Plugin({});
const plugin3 = new Plugin({});
const plugins = new ExtensionBuilder()
.addPlugin(() => plugin3, ExtensionBuilder.PluginPriority.VeryLow)
.addPlugin(() => plugin1)
.addPlugin(() => plugin0, ExtensionBuilder.PluginPriority.VeryHigh)
.addPlugin(() => plugin2)
.build()
.plugins({} as ExtensionDeps);

expect(plugins.indexOf(plugin0)).toBe(0);
expect(plugins.indexOf(plugin1)).toBe(1);
expect(plugins.indexOf(plugin2)).toBe(2);
expect(plugins.indexOf(plugin3)).toBe(3);
});

it('should add actions', () => {
const actions = new ExtensionBuilder()
.addAction('action1', () => ({
Expand Down
15 changes: 6 additions & 9 deletions src/core/ExtensionBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,14 @@ export class ExtensionBuilder {
return map;
},
plugins: (deps) => {
// TODO: sort plugins here after WIKI-16660
return plugins.reduce<{plugin: Plugin; priority: number}[]>(
(acc, {cb, priority}) => {
return plugins
.sort((a, b) => b.priority - a.priority)
.reduce<Plugin[]>((acc, {cb}) => {
const res = cb(deps);
if (Array.isArray(res))
acc.push(...res.map((plugin) => ({plugin, priority})));
else acc.push({plugin: res, priority});
if (Array.isArray(res)) acc.push(...res);
else acc.push(res);
return acc;
},
[],
);
}, []);
},
actions: (deps) =>
actions.reduce((obj, [name, cb]) => {
Expand Down
41 changes: 23 additions & 18 deletions src/core/ExtensionsManager.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import MarkdownIt from 'markdown-it';
import type {Plugin} from 'prosemirror-state';
import {ActionsManager} from './ActionsManager';
import {ExtensionBuilder} from './ExtensionBuilder';
import {ParserTokensRegistry} from './ParserTokensRegistry';
import {SchemaSpecRegistry} from './SchemaSpecRegistry';
import {SerializerTokensRegistry} from './SerializerTokensRegistry';
import type {ActionSpec} from './types/actions';
import type {ExtensionDeps, ExtensionSpec, YEMarkSpec, YENodeSpec} from './types/extension';
import type {
Extension,
ExtensionDeps,
ExtensionSpec,
YEMarkSpec,
YENodeSpec,
} from './types/extension';
import type {MarkViewConstructor, NodeViewConstructor} from './types/node-views';

const attrs = require('markdown-it-attrs');

type ExtensionsManagerParams = {
extensions: ExtensionSpec[];
extensions: Extension;
options?: ExtensionsManagerOptions;
};

Expand All @@ -25,7 +32,7 @@ type ExtensionsManagerOptions = {
};

export class ExtensionsManager {
static process(extensions: ExtensionSpec[], options: ExtensionsManagerOptions) {
static process(extensions: Extension, options: ExtensionsManagerOptions) {
return new this({extensions, options}).build();
}

Expand All @@ -38,8 +45,10 @@ export class ExtensionsManager {

#md: MarkdownIt;
#mdWithoutAttrs: MarkdownIt;
#extensions: ExtensionSpec[];
#extensions: Extension;
#builder: ExtensionBuilder;

#spec!: ExtensionSpec;
#deps!: ExtensionDeps;
#plugins: Plugin[] = [];
#actions: Record<string, ActionSpec> = {};
Expand All @@ -51,6 +60,9 @@ export class ExtensionsManager {

this.#md = new MarkdownIt(options.mdOpts ?? {}).use(attrs, options.attrsOpts ?? {});
this.#mdWithoutAttrs = new MarkdownIt(options.mdOpts ?? {});

// TODO: add prefilled context
this.#builder = new ExtensionBuilder();
}

build() {
Expand All @@ -75,12 +87,11 @@ export class ExtensionsManager {
}

private processExtensions() {
for (const ext of this.#extensions) {
this.#md = ext.configureMd(this.#md);
this.#mdWithoutAttrs = ext.configureMd(this.#mdWithoutAttrs);
ext.nodes().forEach(this.processNode);
ext.marks().forEach(this.processMark);
}
this.#spec = this.#builder.use(this.#extensions).build();
this.#md = this.#spec.configureMd(this.#md);
this.#mdWithoutAttrs = this.#spec.configureMd(this.#mdWithoutAttrs);
this.#spec.nodes().forEach(this.processNode);
this.#spec.marks().forEach(this.processMark);
}

private processNode = (name: string, {spec, fromYfm, toYfm, view}: YENodeSpec) => {
Expand Down Expand Up @@ -113,14 +124,8 @@ export class ExtensionsManager {
}

private createDerived() {
const plugins: {plugin: Plugin; priority: number}[] = [];
for (const ext of this.#extensions) {
plugins.push(...ext.plugins(this.#deps));
Object.assign(this.#actions, ext.actions(this.#deps));
}

// TODO: move sorting to ExtensionBuilder after WIKI-16660
this.#plugins = plugins.sort((a, b) => b.priority - a.priority).map((item) => item.plugin);
this.#plugins = this.#spec.plugins(this.#deps);
Object.assign(this.#actions, this.#spec.actions(this.#deps));

for (const [name, view] of this.#nodeViewCreators) {
this.#nodeViews[name] = view(this.#deps);
Expand Down
11 changes: 0 additions & 11 deletions src/core/createExtension.ts

This file was deleted.

2 changes: 0 additions & 2 deletions src/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export * from './Editor';
export * from './ExtensionBuilder';
export * from './ExtensionsManager';
export * from './createExtension';
export {bindActions} from './utils/actions';
export {trackTransactionMetrics} from './utils/metrics';
export type {Keymap} from './types/keymap';
Expand All @@ -10,7 +9,6 @@ export type {
Extension,
ExtensionAuto,
ExtensionWithOptions,
ExtensionSpec,
ExtensionDeps,
YENodeSpec,
YEMarkSpec,
Expand Down
2 changes: 1 addition & 1 deletion src/core/types/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type ExtensionSpec = {
configureMd(md: MarkdownIt): MarkdownIt;
nodes(): OrderedMap<YENodeSpec>;
marks(): OrderedMap<YEMarkSpec>;
plugins(deps: ExtensionDeps): {plugin: Plugin; priority: number}[];
plugins(deps: ExtensionDeps): Plugin[];
actions(deps: ExtensionDeps): Record<string, ActionSpec>;
};

Expand Down
4 changes: 2 additions & 2 deletions src/extensions/base/BaseSchema/BaseSchema.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {builders} from 'prosemirror-test-builder';
import {createMarkupChecker} from '../../../../tests/sameMarkup';
import {ExtensionsManager} from '../../../core';
import {BaseNode, BaseSchemaE} from './index';
import {BaseNode, BaseSchema} from './index';

const {schema, parser, serializer} = new ExtensionsManager({
extensions: [BaseSchemaE()],
extensions: (builder) => builder.use(BaseSchema, {}),
}).buildDeps();

const {doc, p} = builders(schema, {
Expand Down
9 changes: 1 addition & 8 deletions src/extensions/base/BaseSchema/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {NodeSpec} from 'prosemirror-model';
import type {Command} from 'prosemirror-state';
import {setBlockType} from 'prosemirror-commands';
import {hasParentNodeOfType} from 'prosemirror-utils';
import {Action, createExtension, ExtensionAuto} from '../../../core';
import type {Action, ExtensionAuto} from '../../../core';
import {nodeTypeFactory} from '../../../utils/schema';

export enum BaseNode {
Expand Down Expand Up @@ -82,13 +82,6 @@ export const BaseSchema: ExtensionAuto<BaseSchemaOptions> = (builder, opts) => {
});
};

/**
* @deprecated
* For tests only.
* Remove after WIKI-16660
*/
export const BaseSchemaE = createExtension<BaseSchemaOptions>((b, o) => b.use(BaseSchema, o ?? {}));

declare global {
namespace YfmEditor {
interface Actions {
Expand Down
5 changes: 1 addition & 4 deletions src/extensions/base/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {createExtension, ExtensionAuto} from '../../core';
import type {ExtensionAuto} from '../../core';

import {BaseSchema, BaseSchemaOptions} from './BaseSchema';
import {BaseInputRules} from './BaseInputRules';
Expand All @@ -21,6 +21,3 @@ export const BasePreset: ExtensionAuto<BasePresetOptions> = (builder, opts) => {
.use(BaseInputRules)
.use(BaseStyles);
};

/** @deprecated */
export const BasePresetE = createExtension<BasePresetOptions>((b, o = {}) => b.use(BasePreset, o));
6 changes: 3 additions & 3 deletions src/extensions/markdown/Blockquote/Blockquote.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {builders} from 'prosemirror-test-builder';
import {createMarkupChecker} from '../../../../tests/sameMarkup';
import {ExtensionsManager} from '../../../core';
import {BaseNode, BaseSchemaE} from '../../base/BaseSchema';
import {blockquote, BlockquoteE} from './index';
import {BaseNode, BaseSchema} from '../../base/BaseSchema';
import {blockquote, Blockquote} from './index';

const {schema, parser, serializer} = new ExtensionsManager({
extensions: [BaseSchemaE(), BlockquoteE()],
extensions: (builder) => builder.use(BaseSchema, {}).use(Blockquote, {}),
}).buildDeps();

const {doc, p, q} = builders(schema, {
Expand Down
9 changes: 1 addition & 8 deletions src/extensions/markdown/Blockquote/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {chainCommands, wrapIn} from 'prosemirror-commands';
import type {NodeType} from 'prosemirror-model';
import {wrappingInputRule} from 'prosemirror-inputrules';
import {hasParentNodeOfType} from 'prosemirror-utils';
import {Action, createExtension, ExtensionAuto} from '../../../core';
import type {Action, ExtensionAuto} from '../../../core';
import {selectQuoteBeforeCursor, liftFromQuote, toggleQuote} from './commands';
import {blockquote, bqType} from './const';

Expand Down Expand Up @@ -51,13 +51,6 @@ export const Blockquote: ExtensionAuto<BlockquoteOptions> = (builder, opts) => {
});
};

/**
* @deprecated
* For tests only.
* Remove after WIKI-16660
*/
export const BlockquoteE = createExtension<BlockquoteOptions>((b, o = {}) => b.use(Blockquote, o));

declare global {
namespace YfmEditor {
interface Actions {
Expand Down
6 changes: 3 additions & 3 deletions src/extensions/markdown/Bold/Bold.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {builders} from 'prosemirror-test-builder';
import {createMarkupChecker} from '../../../../tests/sameMarkup';
import {ExtensionsManager} from '../../../core';
import {BaseNode, BaseSchemaE} from '../../base/BaseSchema';
import {bold, BoldE} from './index';
import {BaseNode, BaseSchema} from '../../base/BaseSchema';
import {bold, Bold} from './index';

const {schema, parser, serializer} = new ExtensionsManager({
extensions: [BaseSchemaE(), BoldE()],
extensions: (builder) => builder.use(BaseSchema, {}).use(Bold, {}),
}).buildDeps();

const {doc, p, b} = builders(schema, {
Expand Down
Loading

0 comments on commit 048ea1c

Please sign in to comment.