@blocklet/meta 1.8.38 → 1.8.40
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/lib/parse-navigation-from-blocklet.d.ts +53 -0
- package/lib/parse-navigation-from-blocklet.js +523 -0
- package/lib/parse-navigation.js +2 -0
- package/lib/schema.js +38 -11
- package/lib/types/schema.d.ts +21 -8
- package/package.json +18 -16
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
declare const checkLink: (value: any) => boolean;
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* @param {object} tree 需要深度遍历的数状结构
|
|
5
|
+
* @param {function} cb 每一个节点的回调函数,回调的参数:当前节点数据,父亲节点数据,{index:当前节点所属的数组中的序号,level: 当前节点所处的深度}
|
|
6
|
+
* @param {object} param 深度遍历的参数
|
|
7
|
+
* @param {string} param.key 孩子数组的 key 值
|
|
8
|
+
* @param {number} param.index 当前节点所属的数组中的序号
|
|
9
|
+
* @param {object} param.parent 当前节点的父节点
|
|
10
|
+
* @param {number} param.level 当前节点的深度
|
|
11
|
+
*/
|
|
12
|
+
declare function deepWalk(tree: any, cb?: () => void, { key, order }?: {
|
|
13
|
+
key?: string;
|
|
14
|
+
order?: string;
|
|
15
|
+
}): void;
|
|
16
|
+
/**
|
|
17
|
+
* 判断一个传入值是否属于一个 section
|
|
18
|
+
* @param {string | array} sections 需要判断的对象
|
|
19
|
+
* @param {string} section 目标 section
|
|
20
|
+
*/
|
|
21
|
+
declare function isMatchSection(sections: any, section: any): boolean;
|
|
22
|
+
declare function joinLink(navigation: any, components: any): any;
|
|
23
|
+
/**
|
|
24
|
+
* 将树状结构的导航列表进行扁平化处理
|
|
25
|
+
* @param {array} navigationList 树状结构的导航列表
|
|
26
|
+
* @param {object} params 配置参数
|
|
27
|
+
* @param {number} params.depth 扁平化的层级,默认为 1(全拍平)
|
|
28
|
+
* @param {function} params.transform 当发生拍平处理时
|
|
29
|
+
* @returns 扁平化后的导航列表
|
|
30
|
+
*/
|
|
31
|
+
declare function flatternNavigation(list?: any[], { depth, transform }?: {
|
|
32
|
+
depth?: number;
|
|
33
|
+
transform?: (v: any) => any;
|
|
34
|
+
}): any[];
|
|
35
|
+
/**
|
|
36
|
+
* 根据导航中每一个子菜单所属的 section,将原由的导航数据分离为多个导航数据(此时每一个导航 item 只会包含一个 section)
|
|
37
|
+
* @param {array} navigation 导航列表数据(树状结构,目前只适用于两层的树状结构)
|
|
38
|
+
* @returns
|
|
39
|
+
*/
|
|
40
|
+
declare function splitNavigationBySection(navigation: any): any[];
|
|
41
|
+
/**
|
|
42
|
+
* 将导航数据进行层叠处理
|
|
43
|
+
* @param {array} list 扁平化的导航数据
|
|
44
|
+
* @returns 处理后的导航
|
|
45
|
+
*/
|
|
46
|
+
declare function nestNavigationList(list?: any[]): any[];
|
|
47
|
+
declare function filterNavigation(navigationList: any, components?: any[]): any[];
|
|
48
|
+
declare function parseNavigation(blocklet?: {}, options?: {}): {
|
|
49
|
+
navigationList: any[];
|
|
50
|
+
components: any[];
|
|
51
|
+
builtinList: any[];
|
|
52
|
+
};
|
|
53
|
+
export { parseNavigation, deepWalk, isMatchSection, nestNavigationList, filterNavigation, joinLink, checkLink, flatternNavigation, splitNavigationBySection, };
|
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.splitNavigationBySection = exports.flatternNavigation = exports.checkLink = exports.joinLink = exports.filterNavigation = exports.nestNavigationList = exports.isMatchSection = exports.deepWalk = exports.parseNavigation = void 0;
|
|
8
|
+
const unionWith_1 = __importDefault(require("lodash/unionWith"));
|
|
9
|
+
const isEqual_1 = __importDefault(require("lodash/isEqual"));
|
|
10
|
+
const pick_1 = __importDefault(require("lodash/pick"));
|
|
11
|
+
const isNil_1 = __importDefault(require("lodash/isNil"));
|
|
12
|
+
const omit_1 = __importDefault(require("lodash/omit"));
|
|
13
|
+
const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
|
|
14
|
+
const url_join_1 = __importDefault(require("url-join"));
|
|
15
|
+
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const is_absolute_url_1 = __importDefault(require("is-absolute-url"));
|
|
17
|
+
const lodash_1 = require("lodash");
|
|
18
|
+
const DEFAULT_SECTION = 'header';
|
|
19
|
+
const BASE_PATH = '/';
|
|
20
|
+
const DEFAULT_LINK = '/';
|
|
21
|
+
const ID_SEPARATE = '/';
|
|
22
|
+
/**
|
|
23
|
+
* 判断一个 url 是否为合法的 url 拼接路径
|
|
24
|
+
* /abc, /abc/bcd valid
|
|
25
|
+
* /abc, /abc//bcd invalid
|
|
26
|
+
* @param value 需要检查的 url path
|
|
27
|
+
* @returns boolean
|
|
28
|
+
*/
|
|
29
|
+
const checkUrlPath = (value) => {
|
|
30
|
+
return /^\/(?:[^/]+\/)*$/.test(value) || /^\/(?:[^/]+\/)*[^/]+$/.test(value);
|
|
31
|
+
};
|
|
32
|
+
const checkLink = (value) => {
|
|
33
|
+
if ((0, is_absolute_url_1.default)(value) || checkUrlPath(value)) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
};
|
|
38
|
+
exports.checkLink = checkLink;
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
* @param {object} tree 需要深度遍历的数状结构
|
|
42
|
+
* @param {function} cb 每一个节点的回调函数,回调的参数:当前节点数据,父亲节点数据,{index:当前节点所属的数组中的序号,level: 当前节点所处的深度}
|
|
43
|
+
* @param {object} param 深度遍历的参数
|
|
44
|
+
* @param {string} param.key 孩子数组的 key 值
|
|
45
|
+
* @param {number} param.index 当前节点所属的数组中的序号
|
|
46
|
+
* @param {object} param.parent 当前节点的父节点
|
|
47
|
+
* @param {number} param.level 当前节点的深度
|
|
48
|
+
*/
|
|
49
|
+
function deepWalk(tree, cb = () => { }, { key = 'children', order = 'first' } = {}) {
|
|
50
|
+
function walk(current, { index = 0, parent = null, level = 0 } = {}) {
|
|
51
|
+
if (Array.isArray(current)) {
|
|
52
|
+
current.forEach((item, i) => {
|
|
53
|
+
walk(item, { index: i, parent, level: level + 1 });
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
else if (current) {
|
|
57
|
+
if (order === 'first') {
|
|
58
|
+
cb(current, parent, { index, level });
|
|
59
|
+
}
|
|
60
|
+
walk(current[key], { parent: current, level });
|
|
61
|
+
if (order === 'last') {
|
|
62
|
+
cb(current, parent, { index, level });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
walk(tree);
|
|
67
|
+
}
|
|
68
|
+
exports.deepWalk = deepWalk;
|
|
69
|
+
/**
|
|
70
|
+
* 判断一个传入值是否属于一个 section
|
|
71
|
+
* @param {string | array} sections 需要判断的对象
|
|
72
|
+
* @param {string} section 目标 section
|
|
73
|
+
*/
|
|
74
|
+
function isMatchSection(sections, section) {
|
|
75
|
+
if (section === DEFAULT_SECTION && (0, isNil_1.default)(sections)) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
if (Array.isArray(sections)) {
|
|
79
|
+
return sections.includes(section);
|
|
80
|
+
}
|
|
81
|
+
return sections === section;
|
|
82
|
+
}
|
|
83
|
+
exports.isMatchSection = isMatchSection;
|
|
84
|
+
function tryParseItem(item) {
|
|
85
|
+
try {
|
|
86
|
+
return JSON.parse(item);
|
|
87
|
+
}
|
|
88
|
+
catch (_a) {
|
|
89
|
+
return item;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function normalizeNavigationList(navigationList) {
|
|
93
|
+
return navigationList.map((item) => {
|
|
94
|
+
const tempData = Object.assign({}, item);
|
|
95
|
+
if (tempData.role) {
|
|
96
|
+
tempData.role = tryParseItem(tempData.role);
|
|
97
|
+
}
|
|
98
|
+
if (tempData.section) {
|
|
99
|
+
tempData.section = tryParseItem(tempData.section);
|
|
100
|
+
}
|
|
101
|
+
if (tempData.title) {
|
|
102
|
+
tempData.title = tryParseItem(tempData.title);
|
|
103
|
+
}
|
|
104
|
+
if (tempData.link) {
|
|
105
|
+
tempData.link = tryParseItem(tempData.link);
|
|
106
|
+
}
|
|
107
|
+
return tempData;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function optionalJoin(prefix = '/', url = '') {
|
|
111
|
+
if ((0, is_absolute_url_1.default)(url || '')) {
|
|
112
|
+
return url;
|
|
113
|
+
}
|
|
114
|
+
// remove last slash
|
|
115
|
+
const resultUrl = path_1.default.join(prefix, url || DEFAULT_LINK);
|
|
116
|
+
if (resultUrl.length > 1 && resultUrl.endsWith('/')) {
|
|
117
|
+
return resultUrl.slice(0, resultUrl.length - 1);
|
|
118
|
+
}
|
|
119
|
+
return resultUrl;
|
|
120
|
+
}
|
|
121
|
+
function smartJoinLink(_parentLink, _childLink, { strict = true } = {}) {
|
|
122
|
+
let parentLink = _parentLink;
|
|
123
|
+
let childLink = _childLink;
|
|
124
|
+
if (!strict) {
|
|
125
|
+
parentLink = parentLink || '/';
|
|
126
|
+
childLink = childLink || '/';
|
|
127
|
+
}
|
|
128
|
+
if ((0, lodash_1.isObject)(parentLink) && (0, lodash_1.isString)(childLink) && checkLink(childLink)) {
|
|
129
|
+
return Object.keys(parentLink).reduce((res, key) => {
|
|
130
|
+
res[key] = optionalJoin(parentLink[key], childLink);
|
|
131
|
+
return res;
|
|
132
|
+
}, {});
|
|
133
|
+
}
|
|
134
|
+
if ((0, lodash_1.isString)(parentLink) && checkLink(parentLink) && (0, lodash_1.isObject)(childLink)) {
|
|
135
|
+
return Object.keys(childLink).reduce((res, key) => {
|
|
136
|
+
res[key] = optionalJoin(parentLink, childLink[key]);
|
|
137
|
+
return res;
|
|
138
|
+
}, {});
|
|
139
|
+
}
|
|
140
|
+
if ((0, lodash_1.isString)(parentLink) && (0, lodash_1.isString)(childLink)) {
|
|
141
|
+
if (checkLink(parentLink) || checkLink(childLink)) {
|
|
142
|
+
return optionalJoin(parentLink, childLink);
|
|
143
|
+
}
|
|
144
|
+
return childLink;
|
|
145
|
+
}
|
|
146
|
+
if ((0, lodash_1.isObject)(parentLink) && (0, lodash_1.isObject)(childLink)) {
|
|
147
|
+
const keys = [...new Set([...Object.keys(parentLink), ...Object.keys(childLink)])];
|
|
148
|
+
return keys.reduce((res, key) => {
|
|
149
|
+
res[key] = optionalJoin(parentLink[key], childLink[key]);
|
|
150
|
+
return res;
|
|
151
|
+
}, {});
|
|
152
|
+
}
|
|
153
|
+
return childLink;
|
|
154
|
+
}
|
|
155
|
+
function joinLink(navigation, components) {
|
|
156
|
+
const copyNavigation = (0, cloneDeep_1.default)(navigation);
|
|
157
|
+
deepWalk(copyNavigation, (item, parent) => {
|
|
158
|
+
const component = item.component || item.child;
|
|
159
|
+
if (component) {
|
|
160
|
+
const findComponent = components.find((v) => v.name === component);
|
|
161
|
+
if (findComponent) {
|
|
162
|
+
item.link = smartJoinLink(findComponent.link, item.link, { strict: false });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else if (parent) {
|
|
166
|
+
item.link = smartJoinLink(parent.link, item.link);
|
|
167
|
+
}
|
|
168
|
+
}, { key: 'items' });
|
|
169
|
+
return copyNavigation;
|
|
170
|
+
}
|
|
171
|
+
exports.joinLink = joinLink;
|
|
172
|
+
/**
|
|
173
|
+
* 将树状结构的导航列表进行扁平化处理
|
|
174
|
+
* @param {array} navigationList 树状结构的导航列表
|
|
175
|
+
* @param {object} params 配置参数
|
|
176
|
+
* @param {number} params.depth 扁平化的层级,默认为 1(全拍平)
|
|
177
|
+
* @param {function} params.transform 当发生拍平处理时
|
|
178
|
+
* @returns 扁平化后的导航列表
|
|
179
|
+
*/
|
|
180
|
+
function flatternNavigation(list = [], { depth = 1, transform = (v) => v } = {}) {
|
|
181
|
+
const copyList = (0, cloneDeep_1.default)(list);
|
|
182
|
+
const finalList = [];
|
|
183
|
+
deepWalk(copyList, (item, parent, { level }) => {
|
|
184
|
+
if (level >= depth) {
|
|
185
|
+
const { items = [] } = item;
|
|
186
|
+
if (items && Array.isArray(items) && items.length > 0) {
|
|
187
|
+
delete item.items;
|
|
188
|
+
const transformedItems = items.map((v) => transform(v, item));
|
|
189
|
+
if (parent) {
|
|
190
|
+
parent.items.push(...transformedItems);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
const tmpItem = transform((0, omit_1.default)(item, ['items']), parent);
|
|
194
|
+
finalList.push(tmpItem, ...transformedItems);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else if (level === 1) {
|
|
198
|
+
const tmpItem = transform((0, omit_1.default)(item, ['items']), parent);
|
|
199
|
+
finalList.push(tmpItem);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
else if (level === 1) {
|
|
203
|
+
finalList.push(item);
|
|
204
|
+
}
|
|
205
|
+
}, { key: 'items', order: 'last' });
|
|
206
|
+
return finalList;
|
|
207
|
+
}
|
|
208
|
+
exports.flatternNavigation = flatternNavigation;
|
|
209
|
+
/**
|
|
210
|
+
* 将 blocklet 中的数据进行处理,获得当前应用的导航数据及组件数据
|
|
211
|
+
* @param {object} blocklet blocklet 应用实例对象
|
|
212
|
+
* @returns 导航数据及组件数据
|
|
213
|
+
*/
|
|
214
|
+
function parseBlockletNavigationList(blocklet = {}) {
|
|
215
|
+
const components = [];
|
|
216
|
+
/**
|
|
217
|
+
*
|
|
218
|
+
* @param {object} current 当前 blocklet 的数据
|
|
219
|
+
* @param {object} parent 当前 blocklet 的父组件数据
|
|
220
|
+
* @returns
|
|
221
|
+
*/
|
|
222
|
+
function genNavigationListByBlocklet(current, parent = {}) {
|
|
223
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
224
|
+
const targetList = [];
|
|
225
|
+
const { children = [], meta = {} } = current;
|
|
226
|
+
const navigation = (0, cloneDeep_1.default)((meta === null || meta === void 0 ? void 0 : meta.navigation) || []);
|
|
227
|
+
if (((_b = (_a = current.meta) === null || _a === void 0 ? void 0 : _a.capabilities) === null || _b === void 0 ? void 0 : _b.navigation) !== false) {
|
|
228
|
+
targetList.push(...navigation);
|
|
229
|
+
}
|
|
230
|
+
const parentName = parent.name || '';
|
|
231
|
+
const parentBase = parent.mountPoint || BASE_PATH;
|
|
232
|
+
const currentName = current === blocklet ? '' : meta.name || '';
|
|
233
|
+
const currentBase = current === blocklet ? '' : current.mountPoint || BASE_PATH;
|
|
234
|
+
for (const child of children) {
|
|
235
|
+
const childName = child.meta.name;
|
|
236
|
+
const childBase = child.mountPoint;
|
|
237
|
+
const mergeName = [parentName, currentName, childName].filter(Boolean).join('.');
|
|
238
|
+
const childNavigation = child.meta.navigation || [];
|
|
239
|
+
const mergeBase = (0, url_join_1.default)(parentBase, currentBase, childBase);
|
|
240
|
+
if (((_d = (_c = child.meta) === null || _c === void 0 ? void 0 : _c.capabilities) === null || _d === void 0 ? void 0 : _d.navigation) !== false) {
|
|
241
|
+
components.push({
|
|
242
|
+
did: child.meta.did,
|
|
243
|
+
name: mergeName,
|
|
244
|
+
link: mergeBase,
|
|
245
|
+
title: child.meta.title || '',
|
|
246
|
+
navigation: childNavigation.map((item) => (Object.assign({
|
|
247
|
+
// 给每个 navigation 赋予一个 setion,用于在 autocomplete 提供依据 section 筛选的基础
|
|
248
|
+
section: DEFAULT_SECTION }, item))),
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
// 在现有的 navigation 中判断是否存在 children
|
|
252
|
+
const matchNavigation = navigation.find((item) => {
|
|
253
|
+
if (item.component) {
|
|
254
|
+
return item.component === childName;
|
|
255
|
+
}
|
|
256
|
+
return false;
|
|
257
|
+
});
|
|
258
|
+
// 如果存在,并且当前 navigation 未配置任何 link,则将 child mountpoint 给它
|
|
259
|
+
if (matchNavigation) {
|
|
260
|
+
if (!matchNavigation.link) {
|
|
261
|
+
if (child.meta.navigation && child.meta.navigation.length > 0) {
|
|
262
|
+
const items = genNavigationListByBlocklet(child, { mountPoint: currentBase, name: currentName });
|
|
263
|
+
if (items.length > 0) {
|
|
264
|
+
matchNavigation.items = (_e = matchNavigation.items) !== null && _e !== void 0 ? _e : [];
|
|
265
|
+
matchNavigation.items.push(...items);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
matchNavigation.link = DEFAULT_LINK;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
else if (((_g = (_f = child.meta) === null || _f === void 0 ? void 0 : _f.capabilities) === null || _g === void 0 ? void 0 : _g.navigation) !== false) {
|
|
274
|
+
const childItems = genNavigationListByBlocklet(child, { mountPoint: currentBase, name: currentName });
|
|
275
|
+
// 否则动态注入一个 navigation
|
|
276
|
+
const tmpData = {
|
|
277
|
+
title: child.meta.title,
|
|
278
|
+
component: childName,
|
|
279
|
+
// 动态注入的 navigation 需要一个默认的 id,blocklet.meta.id 是唯一的,可以用上这个值
|
|
280
|
+
id: child.meta.did,
|
|
281
|
+
};
|
|
282
|
+
if (childItems.length > 0) {
|
|
283
|
+
tmpData.items = childItems;
|
|
284
|
+
tmpData.link = undefined;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
tmpData.link = DEFAULT_LINK;
|
|
288
|
+
}
|
|
289
|
+
targetList.push(tmpData);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return targetList;
|
|
293
|
+
}
|
|
294
|
+
const navigationList = genNavigationListByBlocklet(blocklet);
|
|
295
|
+
return {
|
|
296
|
+
navigationList,
|
|
297
|
+
components,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
function patchBuiltinNavigation(navigation) {
|
|
301
|
+
const copyNavigation = (0, cloneDeep_1.default)(navigation).filter((item) => item.id);
|
|
302
|
+
deepWalk(copyNavigation, (item, parent) => {
|
|
303
|
+
var _a;
|
|
304
|
+
// item.id = item.component || JSON.stringify(item.title) || nanoid();
|
|
305
|
+
if (item.items && item.items.length) {
|
|
306
|
+
for (let i = item.items.length - 1; i >= 0; i--) {
|
|
307
|
+
if (!item.items[i].id) {
|
|
308
|
+
item.items.splice(i, 1);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// 如果 items 全都不符合规范,保留 item 本身,为其增加一个默认的链接
|
|
312
|
+
if (item.items.length === 0) {
|
|
313
|
+
if (item.component) {
|
|
314
|
+
item.link = item.link || DEFAULT_LINK;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (parent) {
|
|
319
|
+
item.parent = parent.id;
|
|
320
|
+
// 由于默认设置的 id(在 blocklet.yml 中手动赋予的存在重复的可能性比较大,所以通过 `/` 拼接父节点的 id,可以大大降低重复的概率)
|
|
321
|
+
item.id = [parent.id, item.id].join(ID_SEPARATE);
|
|
322
|
+
}
|
|
323
|
+
item.from = item.from || 'yaml';
|
|
324
|
+
item.visible = (_a = item.visible) !== null && _a !== void 0 ? _a : true;
|
|
325
|
+
}, { key: 'items' });
|
|
326
|
+
return copyNavigation;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* 将多层结构的导航列表压缩至指定最大深度的树状结构
|
|
330
|
+
* @param {array} navigation 树状结构的导航列表数据
|
|
331
|
+
* @param {number} depth 压缩的层级
|
|
332
|
+
* @returns 压缩后的树状结构导航列表数据
|
|
333
|
+
*/
|
|
334
|
+
function compactNavigation(navigation, depth = 2) {
|
|
335
|
+
const copyNavigation = (0, cloneDeep_1.default)(navigation);
|
|
336
|
+
const resData = flatternNavigation(copyNavigation, {
|
|
337
|
+
depth,
|
|
338
|
+
transform: (item, parent) => {
|
|
339
|
+
var _a;
|
|
340
|
+
if (parent) {
|
|
341
|
+
if (!item._parent) {
|
|
342
|
+
item._parent = parent.id;
|
|
343
|
+
if (!parent.component) {
|
|
344
|
+
item.link = smartJoinLink(parent.link, item.link);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
item.section = item.section || parent.section || [DEFAULT_SECTION];
|
|
348
|
+
item.visible = (_a = item.visible) !== null && _a !== void 0 ? _a : parent.visible;
|
|
349
|
+
}
|
|
350
|
+
item.component = [parent.component, item.component].filter(Boolean).join('.');
|
|
351
|
+
return item;
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
deepWalk(resData, (item) => {
|
|
355
|
+
if (item.items && item.items.length > 0) {
|
|
356
|
+
item.items.reduceRight((all, cur) => {
|
|
357
|
+
if (cur._parent) {
|
|
358
|
+
const index = item.items.findIndex((v) => v.id === cur._parent);
|
|
359
|
+
if (index >= 0) {
|
|
360
|
+
item.items.splice(index, 1);
|
|
361
|
+
}
|
|
362
|
+
delete cur._parent;
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}, null);
|
|
366
|
+
}
|
|
367
|
+
}, { key: 'items' });
|
|
368
|
+
return resData;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* 返回指定的导航中的子菜单(属于指定 section)
|
|
372
|
+
* @param {object} navigationItem 指定的某一个导航数据
|
|
373
|
+
* @param {string} section 指定的 section 区域
|
|
374
|
+
* @returns
|
|
375
|
+
*/
|
|
376
|
+
function getNavigationListBySection(navigationItem, section) {
|
|
377
|
+
if (section && Array.isArray(navigationItem.items)) {
|
|
378
|
+
return navigationItem.items
|
|
379
|
+
.filter((item) => {
|
|
380
|
+
// 如果当前子菜单没有 section,它的 section 应该跟随父菜单的 section
|
|
381
|
+
if ((0, isNil_1.default)(item.section)) {
|
|
382
|
+
return isMatchSection(navigationItem.section, section);
|
|
383
|
+
}
|
|
384
|
+
if (isMatchSection(item.section, section)) {
|
|
385
|
+
return true;
|
|
386
|
+
}
|
|
387
|
+
return false;
|
|
388
|
+
})
|
|
389
|
+
.map((item) => (Object.assign(Object.assign({}, item), { section })));
|
|
390
|
+
}
|
|
391
|
+
return [];
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* 根据导航中每一个子菜单所属的 section,将原由的导航数据分离为多个导航数据(此时每一个导航 item 只会包含一个 section)
|
|
395
|
+
* @param {array} navigation 导航列表数据(树状结构,目前只适用于两层的树状结构)
|
|
396
|
+
* @returns
|
|
397
|
+
*/
|
|
398
|
+
function splitNavigationBySection(navigation) {
|
|
399
|
+
const copyNavigation = (0, cloneDeep_1.default)(navigation);
|
|
400
|
+
const allNavigationList = [];
|
|
401
|
+
for (const navigationItem of copyNavigation) {
|
|
402
|
+
const baseNavigation = (0, cloneDeep_1.default)((0, omit_1.default)(navigationItem, ['items']));
|
|
403
|
+
const itemNavigationList = [];
|
|
404
|
+
// eslint-disable-next-line no-inner-declarations
|
|
405
|
+
function patchNavigationItem(item, section) {
|
|
406
|
+
const sectionNavigationList = getNavigationListBySection(item, section);
|
|
407
|
+
itemNavigationList.push(Object.assign(Object.assign({}, baseNavigation), { section, items: sectionNavigationList }));
|
|
408
|
+
}
|
|
409
|
+
if (Array.isArray(navigationItem.section)) {
|
|
410
|
+
for (const section of navigationItem.section) {
|
|
411
|
+
patchNavigationItem(navigationItem, section);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
else if (navigationItem.section) {
|
|
415
|
+
const { section } = navigationItem;
|
|
416
|
+
patchNavigationItem(navigationItem, section);
|
|
417
|
+
}
|
|
418
|
+
else if (navigationItem.items && navigationItem.items.length > 0) {
|
|
419
|
+
const allSectionList = navigationItem.items.reduce((list, currentValue) => {
|
|
420
|
+
const { section = [DEFAULT_SECTION] } = currentValue || {};
|
|
421
|
+
list.push(...section);
|
|
422
|
+
return list;
|
|
423
|
+
}, []);
|
|
424
|
+
const sectionList = [...new Set(allSectionList)];
|
|
425
|
+
for (const section of sectionList) {
|
|
426
|
+
patchNavigationItem(navigationItem, section);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
itemNavigationList.push(Object.assign(Object.assign({}, navigationItem), { section: DEFAULT_SECTION }));
|
|
431
|
+
}
|
|
432
|
+
allNavigationList.push(...itemNavigationList);
|
|
433
|
+
}
|
|
434
|
+
return allNavigationList;
|
|
435
|
+
}
|
|
436
|
+
exports.splitNavigationBySection = splitNavigationBySection;
|
|
437
|
+
/**
|
|
438
|
+
* 将导航数据进行层叠处理
|
|
439
|
+
* @param {array} list 扁平化的导航数据
|
|
440
|
+
* @returns 处理后的导航
|
|
441
|
+
*/
|
|
442
|
+
function nestNavigationList(list = []) {
|
|
443
|
+
const cloneList = (0, cloneDeep_1.default)(list);
|
|
444
|
+
cloneList.reduceRight((res, item, index) => {
|
|
445
|
+
if (item.parent) {
|
|
446
|
+
const parent = cloneList.find((i) => {
|
|
447
|
+
if (item.section && i.section) {
|
|
448
|
+
return i.section === item.section && i.id === item.parent;
|
|
449
|
+
}
|
|
450
|
+
return i.id === item.parent;
|
|
451
|
+
});
|
|
452
|
+
if (parent) {
|
|
453
|
+
if (!parent.items)
|
|
454
|
+
parent.items = [];
|
|
455
|
+
// 由于 reduceRight 是从后向前遍历,所以后遍历到的其实顺序在前面
|
|
456
|
+
parent.items = [item, ...parent.items];
|
|
457
|
+
}
|
|
458
|
+
cloneList.splice(index, 1);
|
|
459
|
+
}
|
|
460
|
+
return null;
|
|
461
|
+
}, null);
|
|
462
|
+
return cloneList;
|
|
463
|
+
}
|
|
464
|
+
exports.nestNavigationList = nestNavigationList;
|
|
465
|
+
function filterNavigation(navigationList, components = []) {
|
|
466
|
+
const fullNavigation = nestNavigationList(navigationList);
|
|
467
|
+
deepWalk(fullNavigation, (item) => {
|
|
468
|
+
if (item === null || item === void 0 ? void 0 : item.component) {
|
|
469
|
+
if (!components.some((x) => x.name === item.component)) {
|
|
470
|
+
item.visible = false;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
if (item.items && item.items.length) {
|
|
474
|
+
for (let i = item.items.length - 1; i >= 0; i--) {
|
|
475
|
+
if (item.items[i].visible === false) {
|
|
476
|
+
item.items.splice(i, 1);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}, { key: 'items' });
|
|
481
|
+
return fullNavigation.filter((item) => item.visible !== false);
|
|
482
|
+
}
|
|
483
|
+
exports.filterNavigation = filterNavigation;
|
|
484
|
+
function parseNavigation(blocklet = {}, options = {}) {
|
|
485
|
+
var _a;
|
|
486
|
+
const { beforeProcess = (v) => v } = options;
|
|
487
|
+
const { navigationList: builtinNavigation, components } = parseBlockletNavigationList(blocklet);
|
|
488
|
+
const customNavigationList = ((_a = blocklet === null || blocklet === void 0 ? void 0 : blocklet.settings) === null || _a === void 0 ? void 0 : _a.navigations) || [];
|
|
489
|
+
const compactedNavigation = compactNavigation(beforeProcess(builtinNavigation));
|
|
490
|
+
const patchedNavigation = patchBuiltinNavigation(compactedNavigation);
|
|
491
|
+
const splitNavigation = splitNavigationBySection(patchedNavigation);
|
|
492
|
+
// 将 footer-social, footer-bottom, sessionManager 的二级菜单提升为一级菜单
|
|
493
|
+
const levelUpNavigation = splitNavigation.reduce((all, cur) => {
|
|
494
|
+
if (['bottom', 'social', 'sessionManager'].includes(cur.section)) {
|
|
495
|
+
if (cur.items && cur.items.length > 0) {
|
|
496
|
+
all.push(...cur.items.map((x) => {
|
|
497
|
+
const { section } = cur;
|
|
498
|
+
const link = smartJoinLink(cur.link, x.link);
|
|
499
|
+
const component = [cur.component, x.component].filter(Boolean).join('.');
|
|
500
|
+
return Object.assign(Object.assign({}, x), { section, link, component, parent: '' });
|
|
501
|
+
}));
|
|
502
|
+
return all;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
all.push(cur);
|
|
506
|
+
return all;
|
|
507
|
+
}, []);
|
|
508
|
+
const flatNavigation = flatternNavigation(levelUpNavigation, {
|
|
509
|
+
transform(item, parent) {
|
|
510
|
+
let { component } = item;
|
|
511
|
+
if (parent === null || parent === void 0 ? void 0 : parent.component) {
|
|
512
|
+
component = [parent.component, item.component].filter(Boolean).join('.');
|
|
513
|
+
}
|
|
514
|
+
return Object.assign(Object.assign({}, item), { component });
|
|
515
|
+
},
|
|
516
|
+
});
|
|
517
|
+
const rawNavigation = (0, unionWith_1.default)(normalizeNavigationList(customNavigationList), flatNavigation, (prev, next) => {
|
|
518
|
+
const keys = ['id', 'section'];
|
|
519
|
+
return (0, isEqual_1.default)((0, pick_1.default)(prev, keys), (0, pick_1.default)(next, keys));
|
|
520
|
+
});
|
|
521
|
+
return { navigationList: rawNavigation, components, builtinList: flatNavigation };
|
|
522
|
+
}
|
|
523
|
+
exports.parseNavigation = parseNavigation;
|
package/lib/parse-navigation.js
CHANGED
|
@@ -46,6 +46,7 @@ const doParseNavigation = (navigation, blocklet, prefix = '/', _level = 1) => {
|
|
|
46
46
|
}
|
|
47
47
|
const item = {
|
|
48
48
|
title: nav.title,
|
|
49
|
+
id: undefined,
|
|
49
50
|
};
|
|
50
51
|
if (nav.section) {
|
|
51
52
|
item.section = nav.section;
|
|
@@ -82,6 +83,7 @@ const doParseNavigation = (navigation, blocklet, prefix = '/', _level = 1) => {
|
|
|
82
83
|
const childTitle = child.meta.title || child.meta.name;
|
|
83
84
|
const itemProto = {
|
|
84
85
|
title: nav.title || childTitle,
|
|
86
|
+
id: undefined,
|
|
85
87
|
};
|
|
86
88
|
if (nav.section) {
|
|
87
89
|
itemProto.section = nav.section;
|
package/lib/schema.js
CHANGED
|
@@ -21,10 +21,12 @@ const joi_1 = __importDefault(require("joi"));
|
|
|
21
21
|
const cjk_length_1 = __importDefault(require("cjk-length"));
|
|
22
22
|
const is_glob_1 = __importDefault(require("is-glob"));
|
|
23
23
|
const joi_extension_semver_1 = require("joi-extension-semver");
|
|
24
|
+
const is_var_name_1 = __importDefault(require("is-var-name"));
|
|
24
25
|
const did_1 = __importDefault(require("./did"));
|
|
25
26
|
const extension_1 = require("./extension");
|
|
26
27
|
const name_1 = require("./name");
|
|
27
28
|
const constants_1 = __importDefault(require("./constants"));
|
|
29
|
+
const parse_navigation_from_blocklet_1 = require("./parse-navigation-from-blocklet");
|
|
28
30
|
const cjkLength = cjk_length_1.default.default;
|
|
29
31
|
const { BLOCKLET_GROUPS, BLOCKLET_PLATFORMS, BLOCKLET_ARCHITECTURES, BLOCKLET_INTERFACE_TYPES, BLOCKLET_INTERFACE_PROTOCOLS, BLOCKLET_ENTRY_FILE, BLOCKLET_BUNDLE_FILE, BLOCKLET_DEFAULT_PORT_NAME, BLOCKLET_DYNAMIC_PATH_PREFIX, BlockletGroup, BLOCKLET_LATEST_REQUIREMENT_SERVER, BLOCKLET_INTERFACE_TYPE_WEB, BLOCKLET_INTERFACE_TYPE_WELLKNOWN, BLOCKLET_APP_SPACE_ENDPOINTS, BLOCKLET_CONFIGURABLE_KEY, } = constants_1.default;
|
|
30
32
|
const WELLKNOWN_PATH_PREFIX = '/.well-known';
|
|
@@ -34,6 +36,20 @@ const Joi = joi_1.default.extend(joi_extension_semver_1.semver)
|
|
|
34
36
|
.extend(joi_extension_semver_1.semverRange)
|
|
35
37
|
.extend(extension_1.fileExtension)
|
|
36
38
|
.extend(extension_1.didExtension);
|
|
39
|
+
const checkLinkHelper = (value, helper) => {
|
|
40
|
+
if ((0, parse_navigation_from_blocklet_1.checkLink)(value)) {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
// @ts-expect-error
|
|
44
|
+
return helper.message('Invalid navigation link');
|
|
45
|
+
};
|
|
46
|
+
const checkId = (value, helper) => {
|
|
47
|
+
if (!value || (0, is_var_name_1.default)(value)) {
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
// @ts-expect-error
|
|
51
|
+
return helper.message('Invalid navigation id');
|
|
52
|
+
};
|
|
37
53
|
const titleSchema = Joi.string()
|
|
38
54
|
.trim()
|
|
39
55
|
.min(1)
|
|
@@ -297,21 +313,22 @@ const signatureSchema = Joi.object({
|
|
|
297
313
|
unknownType: 'any',
|
|
298
314
|
});
|
|
299
315
|
exports.signatureSchema = signatureSchema;
|
|
316
|
+
const localeList = ['en', 'zh', 'fr', 'ru', 'ar', 'es', 'de', 'pt', 'ja', 'hi'];
|
|
300
317
|
const navigationItemProps = {
|
|
318
|
+
id: Joi.string().custom(checkId),
|
|
301
319
|
title: Joi.alternatives()
|
|
302
|
-
.try(Joi.string(), Joi.object(
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
}).min(1))
|
|
320
|
+
.try(Joi.string().min(1).max(MAX_TITLE_LENGTH), Joi.object()
|
|
321
|
+
.min(1)
|
|
322
|
+
.pattern(Joi.string().valid(...localeList), Joi.string().min(1).max(MAX_TITLE_LENGTH)))
|
|
306
323
|
.required(),
|
|
307
|
-
link: Joi.alternatives().try(Joi.string(), Joi.object(
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
}).min(1)),
|
|
324
|
+
link: Joi.alternatives().try(Joi.string().custom(checkLinkHelper), Joi.object()
|
|
325
|
+
.min(1)
|
|
326
|
+
.pattern(Joi.string().valid(...localeList), Joi.string().custom(checkLinkHelper))),
|
|
311
327
|
component: Joi.string().min(1),
|
|
312
328
|
section: Joi.array().items(Joi.string().min(1)).single(),
|
|
313
329
|
role: Joi.array().items(Joi.string().min(1)).single(),
|
|
314
330
|
icon: Joi.string().min(1),
|
|
331
|
+
visible: Joi.boolean(),
|
|
315
332
|
};
|
|
316
333
|
const navigationItemSchema = Joi.object(Object.assign(Object.assign({}, navigationItemProps), { items: Joi.array().items(Joi.object(Object.assign({}, navigationItemProps)).rename('child', 'component')) }))
|
|
317
334
|
.rename('child', 'component')
|
|
@@ -320,7 +337,15 @@ const navigationItemSchema = Joi.object(Object.assign(Object.assign({}, navigati
|
|
|
320
337
|
unknownType: 'any',
|
|
321
338
|
});
|
|
322
339
|
exports.navigationItemSchema = navigationItemSchema;
|
|
323
|
-
const navigationSchema = Joi.array()
|
|
340
|
+
const navigationSchema = Joi.array()
|
|
341
|
+
.items(navigationItemSchema)
|
|
342
|
+
.unique((a, b) => {
|
|
343
|
+
if (a.id && b.id) {
|
|
344
|
+
return a.id === b.id;
|
|
345
|
+
}
|
|
346
|
+
return false;
|
|
347
|
+
})
|
|
348
|
+
.meta({
|
|
324
349
|
className: 'TNavigation',
|
|
325
350
|
unknownType: 'any',
|
|
326
351
|
});
|
|
@@ -516,6 +541,7 @@ const blockletMetaProps = {
|
|
|
516
541
|
didSpace: Joi.string()
|
|
517
542
|
.valid(...Object.values(BLOCKLET_APP_SPACE_ENDPOINTS))
|
|
518
543
|
.optional(),
|
|
544
|
+
navigation: Joi.boolean().default(true), // Should blocklet join navigation auto-merge process
|
|
519
545
|
}).default({
|
|
520
546
|
clusterMode: false,
|
|
521
547
|
component: true,
|
|
@@ -574,9 +600,10 @@ const createBlockletSchema = (baseDir, _a = {}) => {
|
|
|
574
600
|
.rename('children', 'components')
|
|
575
601
|
.custom((data, helper) => {
|
|
576
602
|
const { did, name } = data;
|
|
577
|
-
|
|
603
|
+
const expectDid = (0, did_1.default)(name);
|
|
604
|
+
if (expectDid !== did) {
|
|
578
605
|
// @ts-expect-error
|
|
579
|
-
return helper.message(`name "${name}"
|
|
606
|
+
return helper.message(`the did of name "${name}" should be "${expectDid}"`);
|
|
580
607
|
}
|
|
581
608
|
return data;
|
|
582
609
|
});
|
package/lib/types/schema.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface TBlockletMeta {
|
|
|
14
14
|
clusterMode?: boolean;
|
|
15
15
|
component?: boolean;
|
|
16
16
|
didSpace?: 'required' | 'optional';
|
|
17
|
+
navigation?: boolean;
|
|
17
18
|
};
|
|
18
19
|
community?: string;
|
|
19
20
|
components?: TComponent[];
|
|
@@ -173,30 +174,42 @@ export declare type TNavigation = TNavigationItem[];
|
|
|
173
174
|
export interface TNavigationItem {
|
|
174
175
|
component?: string;
|
|
175
176
|
icon?: string;
|
|
177
|
+
id?: string;
|
|
176
178
|
items?: {
|
|
177
179
|
component?: string;
|
|
178
180
|
icon?: string;
|
|
181
|
+
id?: string;
|
|
179
182
|
link?: string | {
|
|
180
|
-
|
|
181
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Unknown Property
|
|
185
|
+
*/
|
|
186
|
+
[x: string]: string;
|
|
182
187
|
};
|
|
183
188
|
role?: string[];
|
|
184
189
|
section?: string[];
|
|
185
190
|
title: string | {
|
|
186
|
-
|
|
187
|
-
|
|
191
|
+
/**
|
|
192
|
+
* Unknown Property
|
|
193
|
+
*/
|
|
194
|
+
[x: string]: string;
|
|
188
195
|
};
|
|
196
|
+
visible?: boolean;
|
|
189
197
|
}[];
|
|
190
198
|
link?: string | {
|
|
191
|
-
|
|
192
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Unknown Property
|
|
201
|
+
*/
|
|
202
|
+
[x: string]: string;
|
|
193
203
|
};
|
|
194
204
|
role?: string[];
|
|
195
205
|
section?: string[];
|
|
196
206
|
title: string | {
|
|
197
|
-
|
|
198
|
-
|
|
207
|
+
/**
|
|
208
|
+
* Unknown Property
|
|
209
|
+
*/
|
|
210
|
+
[x: string]: string;
|
|
199
211
|
};
|
|
212
|
+
visible?: boolean;
|
|
200
213
|
}
|
|
201
214
|
export interface TPerson {
|
|
202
215
|
email?: string;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.8.
|
|
6
|
+
"version": "1.8.40",
|
|
7
7
|
"description": "Library to parse/validate/fix blocklet meta",
|
|
8
8
|
"main": "./lib/index.js",
|
|
9
9
|
"typings": "./lib/index.d.ts",
|
|
@@ -24,26 +24,28 @@
|
|
|
24
24
|
"author": "wangshijun <wangshijun2020@gmail.com> (http://github.com/wangshijun)",
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@abtnode/client": "1.8.
|
|
28
|
-
"@abtnode/constant": "1.8.
|
|
29
|
-
"@abtnode/util": "1.8.
|
|
30
|
-
"@arcblock/did": "1.18.
|
|
31
|
-
"@arcblock/did-ext": "1.18.
|
|
32
|
-
"@arcblock/did-util": "1.18.
|
|
33
|
-
"@arcblock/jwt": "1.18.
|
|
34
|
-
"@blocklet/constant": "1.8.
|
|
35
|
-
"@ocap/asset": "1.18.
|
|
36
|
-
"@ocap/mcrypto": "1.18.
|
|
37
|
-
"@ocap/types": "1.18.
|
|
38
|
-
"@ocap/util": "1.18.
|
|
39
|
-
"@ocap/wallet": "1.18.
|
|
27
|
+
"@abtnode/client": "1.8.40",
|
|
28
|
+
"@abtnode/constant": "1.8.40",
|
|
29
|
+
"@abtnode/util": "1.8.40",
|
|
30
|
+
"@arcblock/did": "1.18.26",
|
|
31
|
+
"@arcblock/did-ext": "1.18.26",
|
|
32
|
+
"@arcblock/did-util": "1.18.26",
|
|
33
|
+
"@arcblock/jwt": "1.18.26",
|
|
34
|
+
"@blocklet/constant": "1.8.40",
|
|
35
|
+
"@ocap/asset": "1.18.26",
|
|
36
|
+
"@ocap/mcrypto": "1.18.26",
|
|
37
|
+
"@ocap/types": "1.18.26",
|
|
38
|
+
"@ocap/util": "1.18.26",
|
|
39
|
+
"@ocap/wallet": "1.18.26",
|
|
40
40
|
"ajv": "^8.11.0",
|
|
41
41
|
"axios": "^0.27.2",
|
|
42
42
|
"cjk-length": "^1.0.0",
|
|
43
43
|
"debug": "^4.3.4",
|
|
44
44
|
"fs-extra": "^10.1.0",
|
|
45
45
|
"hosted-git-info": "3.0.8",
|
|
46
|
+
"is-absolute-url": "^3.0.3",
|
|
46
47
|
"is-glob": "^4.0.3",
|
|
48
|
+
"is-var-name": "^2.0.0",
|
|
47
49
|
"joi": "17.6.3",
|
|
48
50
|
"joi-extension-semver": "^5.0.0",
|
|
49
51
|
"js-yaml": "^4.1.0",
|
|
@@ -56,7 +58,7 @@
|
|
|
56
58
|
"validate-npm-package-name": "^3.0.0"
|
|
57
59
|
},
|
|
58
60
|
"devDependencies": {
|
|
59
|
-
"@abtnode/client": "^1.8.
|
|
61
|
+
"@abtnode/client": "^1.8.39",
|
|
60
62
|
"@arcblock/eslint-config-ts": "^0.2.3",
|
|
61
63
|
"@types/express": "^4.17.14",
|
|
62
64
|
"@types/jest": "^29.2.2",
|
|
@@ -77,5 +79,5 @@
|
|
|
77
79
|
"ts-node": "^10.9.1",
|
|
78
80
|
"typescript": "^4.8.4"
|
|
79
81
|
},
|
|
80
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "336dbe0ad2cf512a322358899e56aab3668b1715"
|
|
81
83
|
}
|