cherry-markdown 0.5.15 → 0.5.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
Binary file
Binary file
Binary file
@@ -7,7 +7,7 @@ export default class Engine {
7
7
  constructor(markdownParams: Partial<import('./Cherry').CherryOptions>, cherry: import('./Cherry').default);
8
8
  $cherry: import("./Cherry").default;
9
9
  hookCenter: HookCenter;
10
- hooks: {};
10
+ hooks: Record<import("../types/syntax").HookType, SyntaxBase[]>;
11
11
  md5Cache: {};
12
12
  md5StrMap: {};
13
13
  markdownParams: Partial<import("../types/cherry").CherryOptions>;
@@ -34,3 +34,4 @@ export default class Engine {
34
34
  makeMarkdown(html: any): string;
35
35
  }
36
36
  import HookCenter from "./core/HookCenter";
37
+ import SyntaxBase from "./core/SyntaxBase";
@@ -1,4 +1,3 @@
1
- /** @typedef {import('~types/cherry').CherryOptions} CherryOptions */
2
1
  /**
3
2
  * 语法注册中心
4
3
  */
@@ -9,8 +8,18 @@ export default class HookCenter {
9
8
  * @param {Partial<CherryOptions>} editorConfig
10
9
  */
11
10
  constructor(hooksConfig: (typeof SyntaxBase)[], editorConfig: Partial<CherryOptions>);
12
- hookList: {};
13
- hookNameList: {};
11
+ /**
12
+ * @property
13
+ * @type {Record<import('./SyntaxBase').HookType, SyntaxBase[]>} hookList hook 名称 -> hook 类型的映射
14
+ */
15
+ hookList: Record<import('./SyntaxBase').HookType, SyntaxBase[]>;
16
+ /**
17
+ * @property
18
+ * @type {Record<string, { type: import('./SyntaxBase').HookType }>} hookNameList hook 名称 -> hook 类型的映射
19
+ */
20
+ hookNameList: Record<string, {
21
+ type: import('./SyntaxBase').HookType;
22
+ }>;
14
23
  /**
15
24
  * 注册系统默认的语法hook
16
25
  * @param {any[]} hooksConfig 在hookconfig.js里定义的配置
@@ -19,20 +28,31 @@ export default class HookCenter {
19
28
  registerInternalHooks(hooksConfig: any[], editorConfig: Partial<CherryOptions>): void;
20
29
  /**
21
30
  * 注册第三方的语法hook
22
- * @param {CherryOptions['engine']['customSyntax']} customHooks 用户传入的配置
31
+ * @param {CherryEngineOptions['customSyntax']} customHooks 用户传入的配置
23
32
  * @param {Partial<CherryOptions>} editorConfig 编辑器配置
24
33
  */
25
- registerCustomHooks(customHooks: CherryOptions['engine']['customSyntax'], editorConfig: Partial<CherryOptions>): void;
26
- getHookList(): {};
27
- getHookNameList(): {};
34
+ registerCustomHooks(customHooks: CherryEngineOptions['customSyntax'], editorConfig: Partial<CherryOptions>): void;
35
+ getHookList(): Record<import("../../types/syntax").HookType, SyntaxBase[]>;
36
+ getHookNameList(): Record<string, {
37
+ type: import('./SyntaxBase').HookType;
38
+ }>;
28
39
  /**
29
40
  *
30
41
  * @param {((...args: any[]) => any) | typeof SyntaxBase} HookClass
31
42
  * @param {Partial<CherryOptions>} editorConfig
32
- * @param {Record<string, any>} [customHookConfig]
43
+ * @param {Omit<CustomSyntaxRegConfig, 'syntaxClass'>} [customHookConfig]
33
44
  * @returns
34
45
  */
35
- register(HookClass: typeof SyntaxBase | ((...args: any[]) => any), editorConfig: Partial<CherryOptions>, customHookConfig?: Record<string, any>): -1 | -2;
46
+ register(HookClass: typeof SyntaxBase | ((...args: any[]) => any), editorConfig: Partial<CherryOptions>, customHookConfig?: Omit<CustomSyntaxRegConfig, 'syntaxClass'>): -1 | -2;
36
47
  }
37
48
  export type CherryOptions = import('~types/cherry').CherryOptions;
49
+ export type CherryEngineOptions = import('~types/cherry').CherryEngineOptions;
50
+ export type CustomSyntaxRegConfig = import('~types/cherry').CustomSyntaxRegConfig;
51
+ export type CustomSyntax = (SyntaxBase | ParagraphBase) & {
52
+ Cherry$$CUSTOM: true;
53
+ };
54
+ export type CustomSyntaxClass = (typeof SyntaxBase | typeof ParagraphBase) & {
55
+ Cherry$$CUSTOM: true;
56
+ };
38
57
  import SyntaxBase from "./SyntaxBase";
58
+ import ParagraphBase from "./ParagraphBase";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cherry-markdown",
3
3
  "license": "Apache-2.0",
4
- "version": "0.5.15",
4
+ "version": "0.5.16",
5
5
  "description": "a new markdown editor",
6
6
  "repository": {
7
7
  "type": "git",
@@ -18,6 +18,14 @@ import ParagraphBase from './ParagraphBase';
18
18
  import { $expectTarget } from '@/utils/error';
19
19
  import Logger from '@/Logger';
20
20
 
21
+ /**
22
+ * @typedef {import('~types/cherry').CherryOptions} CherryOptions
23
+ * @typedef {import('~types/cherry').CherryEngineOptions} CherryEngineOptions
24
+ * @typedef {import('~types/cherry').CustomSyntaxRegConfig} CustomSyntaxRegConfig
25
+ * @typedef { (SyntaxBase | ParagraphBase) & { Cherry$$CUSTOM: true } } CustomSyntax
26
+ * @typedef { (typeof SyntaxBase | typeof ParagraphBase) & { Cherry$$CUSTOM: true } } CustomSyntaxClass
27
+ */
28
+
21
29
  const WARN_DUPLICATED = -1;
22
30
  const WARN_NOT_A_VALID_HOOK = -2;
23
31
 
@@ -43,11 +51,51 @@ function processWarning(type, objClass, index) {
43
51
  }
44
52
  }
45
53
 
54
+ /**
55
+ * 是否一个合法的 HookClass
56
+ * @param {any} HookClass
57
+ * @returns { HookClass is (typeof SyntaxBase | typeof ParagraphBase) }
58
+ */
46
59
  function isHookValid(HookClass) {
47
- return Object.getPrototypeOf(HookClass) === SyntaxBase || Object.getPrototypeOf(HookClass) === ParagraphBase;
60
+ return isProtoOfSyntaxBase(HookClass) || isProtoOfParagraphBase(HookClass);
48
61
  }
49
62
 
50
- /** @typedef {import('~types/cherry').CherryOptions} CherryOptions */
63
+ /**
64
+ * 传入的类是否 SyntaxBase 的子类
65
+ * @param {any} value
66
+ * @returns { value is typeof SyntaxBase }
67
+ */
68
+ function isProtoOfSyntaxBase(value) {
69
+ return Object.prototype.isPrototypeOf.call(SyntaxBase, value);
70
+ }
71
+
72
+ /**
73
+ * 传入的类是否 ParagraphBase 的子类
74
+ * @param {any} value
75
+ * @returns { value is typeof ParagraphBase }
76
+ */
77
+ function isProtoOfParagraphBase(value) {
78
+ return Object.prototype.isPrototypeOf.call(ParagraphBase, value);
79
+ }
80
+
81
+ /**
82
+ * 是否一个配置型的自定义语法
83
+ * @param {any} value
84
+ * @returns { value is CustomSyntaxRegConfig }
85
+ */
86
+ function isCustomSyntaxConfig(value) {
87
+ const syntaxClass = /** @type {any} */ (/** @type {CustomSyntaxRegConfig} */ (value)?.syntaxClass);
88
+ return isProtoOfSyntaxBase(syntaxClass) || isProtoOfParagraphBase(syntaxClass);
89
+ }
90
+
91
+ /**
92
+ * 是否一个已注册的自定义语法hook类
93
+ * @param {any} value
94
+ * @returns { value is CustomSyntaxClass }
95
+ */
96
+ function isRegisteredCustomSyntaxClass(value) {
97
+ return isHookValid(value) && /** @type {CustomSyntaxClass} */ (value)?.Cherry$$CUSTOM === true;
98
+ }
51
99
 
52
100
  /**
53
101
  * 语法注册中心
@@ -59,8 +107,18 @@ export default class HookCenter {
59
107
  * @param {Partial<CherryOptions>} editorConfig
60
108
  */
61
109
  constructor(hooksConfig, editorConfig) {
62
- this.hookList = {};
110
+ /**
111
+ * @property
112
+ * @type {Record<import('./SyntaxBase').HookType, SyntaxBase[]>} hookList hook 名称 -> hook 类型的映射
113
+ */
114
+ this.hookList = /** @type {any} */ ({});
115
+
116
+ /**
117
+ * @property
118
+ * @type {Record<string, { type: import('./SyntaxBase').HookType }>} hookNameList hook 名称 -> hook 类型的映射
119
+ */
63
120
  this.hookNameList = {};
121
+
64
122
  $expectTarget(hooksConfig, Array);
65
123
  this.registerInternalHooks(hooksConfig, editorConfig);
66
124
  this.registerCustomHooks(editorConfig.engine.customSyntax, editorConfig);
@@ -87,27 +145,30 @@ export default class HookCenter {
87
145
 
88
146
  /**
89
147
  * 注册第三方的语法hook
90
- * @param {CherryOptions['engine']['customSyntax']} customHooks 用户传入的配置
148
+ * @param {CherryEngineOptions['customSyntax']} customHooks 用户传入的配置
91
149
  * @param {Partial<CherryOptions>} editorConfig 编辑器配置
92
150
  */
93
151
  registerCustomHooks(customHooks, editorConfig) {
94
- if (!customHooks || !Object.keys(customHooks)) {
152
+ if (!customHooks) {
95
153
  return;
96
154
  }
97
- Object.keys(customHooks).forEach((CustomHook) => {
98
- const paramType = typeof customHooks[CustomHook];
155
+ const hookNames = Object.keys(customHooks);
156
+ hookNames.forEach((hookName) => {
157
+ /** @type {number} */
99
158
  let result;
159
+ /** @type {typeof SyntaxBase} */
100
160
  let HookClass;
101
161
  const customHookConfig = {};
102
- if (paramType === 'function') {
103
- HookClass = customHooks[CustomHook];
104
- } else if (paramType === 'object') {
105
- HookClass = customHooks[CustomHook].syntaxClass;
106
- customHookConfig.force = !!customHooks[CustomHook].force;
107
- if (customHooks[CustomHook].before) {
108
- customHookConfig.before = customHooks[CustomHook].before;
109
- } else if (customHooks[CustomHook].after) {
110
- customHookConfig.after = customHooks[CustomHook].after;
162
+ const hookClassOrConfig = customHooks[hookName];
163
+ if (isProtoOfSyntaxBase(hookClassOrConfig)) {
164
+ HookClass = hookClassOrConfig;
165
+ } else if (isCustomSyntaxConfig(hookClassOrConfig)) {
166
+ HookClass = hookClassOrConfig.syntaxClass;
167
+ customHookConfig.force = Boolean(hookClassOrConfig.force);
168
+ if (hookClassOrConfig.before) {
169
+ customHookConfig.before = hookClassOrConfig.before;
170
+ } else if (hookClassOrConfig.after) {
171
+ customHookConfig.after = hookClassOrConfig.after;
111
172
  }
112
173
  } else {
113
174
  return;
@@ -140,20 +201,25 @@ export default class HookCenter {
140
201
  *
141
202
  * @param {((...args: any[]) => any) | typeof SyntaxBase} HookClass
142
203
  * @param {Partial<CherryOptions>} editorConfig
143
- * @param {Record<string, any>} [customHookConfig]
204
+ * @param {Omit<CustomSyntaxRegConfig, 'syntaxClass'>} [customHookConfig]
144
205
  * @returns
145
206
  */
146
207
  register(HookClass, editorConfig, customHookConfig) {
147
208
  // filter Configs Here
148
209
  const { externals, engine } = editorConfig;
149
- const { syntax, customSyntax } = engine;
210
+ const { syntax } = engine;
211
+
212
+ /** @type {SyntaxBase | CustomSyntax} */
150
213
  let instance;
214
+
215
+ /** @type {string} */
151
216
  let hookName;
217
+
152
218
  // 首先校验Hook是否合法
153
219
  if (!isHookValid(HookClass)) {
154
220
  // 可能是一个function hook
155
221
  if (typeof HookClass === 'function') {
156
- const funcHook = /** @type {((...args: any[]) => any)}*/ (HookClass);
222
+ const funcHook = HookClass;
157
223
  instance = funcHook(editorConfig);
158
224
  if (!instance || !isHookValid(instance.constructor)) {
159
225
  return WARN_NOT_A_VALID_HOOK;
@@ -163,19 +229,24 @@ export default class HookCenter {
163
229
  return WARN_NOT_A_VALID_HOOK;
164
230
  }
165
231
  } else {
166
- hookName = /** @type {typeof SyntaxBase}*/ (HookClass).HOOK_NAME;
167
- const config = syntax[hookName] ? syntax[hookName] : customSyntax[hookName] ? customSyntax[hookName] : {};
168
- instance = new /** @type {typeof SyntaxBase}*/ (HookClass)({ externals, config, globalConfig: engine.global });
232
+ hookName = HookClass.HOOK_NAME;
233
+ // TODO: 需要考虑自定义 hook 配置的传入方式
234
+ const config = syntax?.[hookName] || {};
235
+ instance = new HookClass({ externals, config, globalConfig: engine.global });
169
236
  }
170
- // Skip Internal Hook
171
- if (syntax[hookName] === false && /** @type {any}*/ (HookClass).Cherry$$CUSTOM !== true) {
237
+ // TODO: 待校验是否需要跳过禁用的自定义 hook
238
+ // Skip Disabled Internal Hooks
239
+ if (syntax[hookName] === false && !isRegisteredCustomSyntaxClass(HookClass)) {
172
240
  return;
173
241
  }
242
+ // 下面处理的都是 CustomSyntax
174
243
  const hookType = instance.getType();
175
244
  if (this.hookNameList[hookName]) {
176
- if (!(/** @type {any}*/ (HookClass).Cherry$$CUSTOM)) {
245
+ // 内置 hook 重名
246
+ if (!isRegisteredCustomSyntaxClass(HookClass)) {
177
247
  return WARN_DUPLICATED;
178
248
  }
249
+ // 自定义 hook 重名且没有开启覆盖的选项
179
250
  if (!customHookConfig.force) {
180
251
  return WARN_DUPLICATED;
181
252
  }
@@ -186,7 +257,7 @@ export default class HookCenter {
186
257
  this.hookNameList[hookName] = { type: hookType };
187
258
  this.hookList[hookType] = this.hookList[hookType] || [];
188
259
  // 内置Hook直接push到结尾
189
- if (/** @type {any}*/ (HookClass).Cherry$$CUSTOM !== true) {
260
+ if (!isRegisteredCustomSyntaxClass(HookClass)) {
190
261
  this.hookList[hookType].push(instance);
191
262
  return;
192
263
  }
package/types/cherry.d.ts CHANGED
@@ -37,6 +37,20 @@ export interface CherryExternalsOptions {
37
37
  [key: string]: any;
38
38
  }
39
39
 
40
+ /**
41
+ * 自定义语法注册配置
42
+ */
43
+ export interface CustomSyntaxRegConfig {
44
+ /** 语法class */
45
+ syntaxClass: typeof SyntaxBase;
46
+ /** 在某个hook前执行,填入hookName */
47
+ before?: string;
48
+ /** 在某个hook后执行,填入hookName */
49
+ after?: string;
50
+ /** 强制覆盖同名hook */
51
+ force?: boolean;
52
+ }
53
+
40
54
  export interface CherryEngineOptions {
41
55
  /** 引擎的全局配置 */
42
56
  global?: {
@@ -65,18 +79,7 @@ export interface CherryEngineOptions {
65
79
  /** 内置语法配置 */
66
80
  syntax?: Record<string, Record<string, any> | false>;
67
81
  /** 自定义语法 */
68
- customSyntax?:
69
- | typeof SyntaxBase
70
- | {
71
- /** 语法class */
72
- syntaxClass: typeof SyntaxBase;
73
- /** 在某个hook前执行,填入hookName */
74
- before?: string;
75
- /** 在某个hook后执行,填入hookName */
76
- after?: string;
77
- /** 强制覆盖同名hook */
78
- force?: boolean;
79
- };
82
+ customSyntax?: Record<string, CustomSyntaxRegConfig['syntaxClass'] | CustomSyntaxRegConfig>;
80
83
  }
81
84
 
82
85
  export type EditorMode =