Skip to content

Commit dc66438

Browse files
authored
feat(core): add context to extension builder (#22)
The key-value storage context has been added to the ExtensionBuilder, which allows you to transfer data between extensions.
1 parent 2088fe4 commit dc66438

File tree

3 files changed

+68
-3
lines changed

3 files changed

+68
-3
lines changed

src/core/ExtensionBuilder.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,24 @@ enum PluginPriority {
3838

3939
const DEFAULT_PRIORITY = PluginPriority.Medium;
4040

41+
type BuilderContext<T extends object> = {
42+
has(key: keyof T): boolean;
43+
get<K extends keyof T>(key: K): T[K] | undefined;
44+
set<K extends keyof T>(key: K, value: T[K]): BuilderContext<T>;
45+
};
46+
47+
declare global {
48+
namespace YfmEditor {
49+
interface Context {}
50+
}
51+
}
52+
4153
export class ExtensionBuilder {
54+
static createContext(): BuilderContext<YfmEditor.Context> {
55+
return new Map();
56+
}
57+
58+
// eslint-disable-next-line @typescript-eslint/member-ordering
4259
static readonly PluginPriority = PluginPriority;
4360
readonly PluginPriority = ExtensionBuilder.PluginPriority;
4461

@@ -48,6 +65,12 @@ export class ExtensionBuilder {
4865
#plugins: {cb: AddPmPluginCallback; priority: number}[] = [];
4966
#actions: [string, AddActionCallback][] = [];
5067

68+
readonly context: BuilderContext<YfmEditor.Context>;
69+
70+
constructor(context?: BuilderContext<YfmEditor.Context>) {
71+
this.context = context ?? ExtensionBuilder.createContext();
72+
}
73+
5174
use(extension: Extension): this;
5275
use<T>(extension: ExtensionWithOptions<T>, options: T): this;
5376
use(extension: ExtensionWithParams, ...params: any[]): this {

src/extensions/markdown/Breaks/index.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type {NodeType} from 'prosemirror-model';
22
import {chainCommands, exitCode} from 'prosemirror-commands';
3+
import {logger} from '../../../logger';
34
import type {ExtensionAuto, Keymap} from '../../../core';
45
import {isMac} from '../../../utils/platform';
56
import {nodeTypeFactory} from '../../../utils/schema';
@@ -10,12 +11,25 @@ export const hbType = nodeTypeFactory(hardBreak);
1011
export const sbType = nodeTypeFactory(softBreak);
1112

1213
export type BreaksOptions = {
13-
// TODO: [builder context] get this parameter from builder context
14-
/** @default 'hard' */
14+
/**
15+
* This option is used if the 'breaks' parameter is not specified via the context
16+
* @default 'hard'
17+
*/
18+
// TODO: [context] make this deprecated
1519
preferredBreak?: 'hard' | 'soft';
1620
};
1721

1822
export const Breaks: ExtensionAuto<BreaksOptions> = (builder, opts) => {
23+
let preferredBreak: 'hard' | 'soft';
24+
if (builder.context.has('breaks')) {
25+
preferredBreak = builder.context.get('breaks') ? 'soft' : 'hard';
26+
} else {
27+
preferredBreak = opts.preferredBreak ?? 'hard';
28+
logger.info(
29+
"[Breaks extension]: Parameter 'breaks' is not defined in context; value from options is used",
30+
);
31+
}
32+
1933
builder.addNode(hardBreak, () => ({
2034
spec: {
2135
inline: true,
@@ -62,7 +76,7 @@ export const Breaks: ExtensionAuto<BreaksOptions> = (builder, opts) => {
6276
}));
6377

6478
builder.addKeymap(({schema}) => {
65-
const cmd = addBr((opts?.preferredBreak === 'soft' ? sbType : hbType)(schema));
79+
const cmd = addBr((preferredBreak === 'soft' ? sbType : hbType)(schema));
6680
const keys: Keymap = {
6781
'Shift-Enter': cmd,
6882
};
@@ -80,3 +94,14 @@ const addBr = (br: NodeType) =>
8094
dispatch?.(state.tr.replaceSelectionWith(br.create()).scrollIntoView());
8195
return true;
8296
});
97+
98+
declare global {
99+
namespace YfmEditor {
100+
interface Context {
101+
/**
102+
* Same as @type {MarkdownIt.Options.breaks}
103+
*/
104+
breaks: boolean;
105+
}
106+
}
107+
}

src/extensions/markdown/Html/index.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
import {logger} from '../../../logger';
12
import {createExtension, ExtensionAuto} from '../../../core';
23
import {HtmlNode} from './const';
34
import {fromYfm} from './fromYfm';
45
import {spec} from './spec';
56
import {toYfm} from './toYfm';
67

78
export const Html: ExtensionAuto = (builder) => {
9+
if (builder.context.has('html') && builder.context.get('html') === false) {
10+
logger.info('[HTML extension]: Skip extension, because HTML disabled via context');
11+
return;
12+
}
13+
814
builder.addNode(HtmlNode.Block, () => ({
915
spec: spec[HtmlNode.Block],
1016
fromYfm: {tokenSpec: fromYfm[HtmlNode.Block]},
@@ -24,3 +30,14 @@ export const Html: ExtensionAuto = (builder) => {
2430
* Remove after WIKI-16660
2531
*/
2632
export const HtmlE = createExtension((b, o = {}) => b.use(Html, o));
33+
34+
declare global {
35+
namespace YfmEditor {
36+
interface Context {
37+
/**
38+
* Same as @type {MarkdownIt.Options.html}
39+
*/
40+
html: boolean;
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)