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.
- package/CHANGELOG.md +7 -0
- package/dist/cherry-markdown.core.js +1 -1
- package/dist/cherry-markdown.engine.core.js +1 -1
- package/dist/cherry-markdown.esm.js +1 -1
- package/dist/cherry-markdown.js +126 -59
- package/dist/cherry-markdown.js.map +1 -1
- package/dist/cherry-markdown.min.js +1 -1
- package/dist/fonts/ch-icon.eot +0 -0
- package/dist/fonts/ch-icon.ttf +0 -0
- package/dist/fonts/ch-icon.woff +0 -0
- package/dist/fonts/ch-icon.woff2 +0 -0
- package/dist/types/Engine.d.ts +2 -1
- package/dist/types/core/HookCenter.d.ts +29 -9
- package/package.json +1 -1
- package/src/core/HookCenter.js +97 -26
- package/types/cherry.d.ts +15 -12
- package/src/addons/cherry-suggester.js +0 -464
package/dist/fonts/ch-icon.eot
CHANGED
|
Binary file
|
package/dist/fonts/ch-icon.ttf
CHANGED
|
Binary file
|
package/dist/fonts/ch-icon.woff
CHANGED
|
Binary file
|
package/dist/fonts/ch-icon.woff2
CHANGED
|
Binary file
|
package/dist/types/Engine.d.ts
CHANGED
|
@@ -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
|
-
|
|
13
|
-
|
|
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 {
|
|
31
|
+
* @param {CherryEngineOptions['customSyntax']} customHooks 用户传入的配置
|
|
23
32
|
* @param {Partial<CherryOptions>} editorConfig 编辑器配置
|
|
24
33
|
*/
|
|
25
|
-
registerCustomHooks(customHooks:
|
|
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 {
|
|
43
|
+
* @param {Omit<CustomSyntaxRegConfig, 'syntaxClass'>} [customHookConfig]
|
|
33
44
|
* @returns
|
|
34
45
|
*/
|
|
35
|
-
register(HookClass: typeof SyntaxBase | ((...args: any[]) => any), editorConfig: Partial<CherryOptions>, customHookConfig?:
|
|
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
package/src/core/HookCenter.js
CHANGED
|
@@ -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
|
|
60
|
+
return isProtoOfSyntaxBase(HookClass) || isProtoOfParagraphBase(HookClass);
|
|
48
61
|
}
|
|
49
62
|
|
|
50
|
-
/**
|
|
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
|
-
|
|
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 {
|
|
148
|
+
* @param {CherryEngineOptions['customSyntax']} customHooks 用户传入的配置
|
|
91
149
|
* @param {Partial<CherryOptions>} editorConfig 编辑器配置
|
|
92
150
|
*/
|
|
93
151
|
registerCustomHooks(customHooks, editorConfig) {
|
|
94
|
-
if (!customHooks
|
|
152
|
+
if (!customHooks) {
|
|
95
153
|
return;
|
|
96
154
|
}
|
|
97
|
-
Object.keys(customHooks)
|
|
98
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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 {
|
|
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
|
|
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 =
|
|
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 =
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
//
|
|
171
|
-
|
|
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
|
-
|
|
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 (
|
|
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 =
|