@anyblock/any-block-core 3.4.12 → 3.5.0

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/ABAlias.ts CHANGED
@@ -143,7 +143,7 @@ const ABAlias_json_mdit: ABAlias_json[] = [
143
143
  {regex: /\|:::_140lne\|(?:mdit2|2)?(puml)?(plantuml|mindmap|脑图|思维导图)\|/, replacement: "|mdit2list" + "|list2pumlMindmap|"},
144
144
  {regex: /\|:::_140lne\|(?:mdit2|2)?(markmap|mdMindmap|md脑图|md思维导图)\|/, replacement: "|mdit2list" + "|list2markmap|"},
145
145
  {regex: /\|:::_140lne\|(?:mdit2|2)?(wbs|(工作)?分解(图|结构))\|/, replacement: "|mdit2list" + "|list2pumlWBS|"},
146
- {regex: /\|:::_140lne\|(?:mdit2|2)?(table|multiWayTable|multiCrossTable|表格?|多叉表格?|跨行表格?)\|/, replacement: "|mdit2list" + "|list2table|"},
146
+ {regex: /\|:::_140lne\|(?:mdit2|2)?(table|multiWayTable|multiCrossTable|表格?|多叉表格?|跨行表格?)\|/, replacement: "|mdit2Listdata|listdata2strict|listdata2table|"},
147
147
 
148
148
  // list - lt树 (属于多层一叉树)
149
149
  {regex: /\|:::_140lne\|(?:mdit2|2)?(lt|listTable|treeTable|listGrid|treeGrid|列表格|树形表格?)\|/, replacement: "|mdit2list" + "|list2lt|"},
@@ -155,10 +155,15 @@ const ABAlias_json_mdit: ABAlias_json[] = [
155
155
 
156
156
  // 至后
157
157
  {regex: "|mdit2list|", replacement: "|mdit2listdata|listdata2strict|listdata2list|"},
158
+ {regex: "|mdit2List|", replacement: "|mdit2Listdata|listdata2strict|listdata2list|"},
158
159
  ]
159
160
 
160
161
  // 标题块
161
162
  const ABAlias_json_title: ABAlias_json[] = [
163
+ // 至前,特殊
164
+ {regex: "|heading2", replacement: "|title2"},
165
+ {regex: "|h2", replacement: "|title2"},
166
+
162
167
  // title - list&title
163
168
  {regex: /\|heading_140lne\|2?(timeline|时间线)\|/, replacement: "|title2timeline|"},
164
169
  {regex: /\|heading_140lne\|2?(tabs?|标签页?)\||\|title2tabs?\|/, replacement: "|title2c2listdata|c2listdata2tab|"},
@@ -172,7 +177,7 @@ const ABAlias_json_title: ABAlias_json[] = [
172
177
  {regex: /\|heading_140lne\|2?(puml)?(plantuml|mindmap|脑图|思维导图)\|/, replacement: "|title2list" + "|list2pumlMindmap|"},
173
178
  {regex: /\|heading_140lne\|2?(markmap|mdMindmap|md脑图|md思维导图)\|/, replacement: "|title2list" + "|list2markmap|"},
174
179
  {regex: /\|heading_140lne\|2?(wbs|(工作)?分解(图|结构))\|/, replacement: "|title2list" + "|list2pumlWBS|"},
175
- {regex: /\|heading_140lne\|2?(table|multiWayTable|multiCrossTable|表格?|多叉表格?|跨行表格?)\|/, replacement: "|title2list" + "|list2table|"},
180
+ {regex: /\|heading_140lne\|2?(table|multiWayTable|multiCrossTable|表格?|多叉表格?|跨行表格?)\|/, replacement: "|title2Listdata|listdata2strict|listdata2table|"},
176
181
 
177
182
  // list - lt树 (属于多层一叉树)
178
183
  {regex: /\|heading_140lne\|2?(lt|listTable|treeTable|listGrid|treeGrid|列表格|树形表格?)\|/, replacement: "|title2list" + "|list2lt|"},
@@ -277,77 +277,89 @@ export class ListProcess{
277
277
  * 3. 列表等级, = `(.*)-`个数+1, 取值[0]
278
278
  *
279
279
  * (比较旧版是正文+10,列表+11,后来允许标题等级为负数。这样方便很多)
280
+ *
281
+ * @fine_mode 精细拆分模式
282
+ * - true: 会将正文和列表拆分成多个节点
283
+ * - false: 会将标题+正文+列表合并成一个节点
280
284
  */
281
- static title2data(text: string): List_ListItem {
285
+ static title2data(text: string, fine_mode: boolean = true): List_ListItem {
282
286
  let list_itemInfo:List_ListItem = []
283
287
 
284
288
  const list_text = text.split("\n")
285
289
  let mul_mode:"heading"|"para"|"list"|"" = "" // 多行模式,标题/正文/列表/空
286
- let codeBlockFlag = '' // 代码块标志,避免在代码块内识别结束符号
290
+ let codeBlockFlag = '' // 代码块标志,避免在代码块内识别结束符号
287
291
  for (let line of list_text) {
292
+
288
293
  // heading和mdit类型都需要跳过代码块内的结束标志
289
294
  if (codeBlockFlag == '') {
290
295
  const match = line.match(ABReg.reg_code)
291
- if (match && match[3]) { // 进入代码块。则将内容添加添加到最后的列表项 (不能是标题列表项)
292
- if (mul_mode === "heading" || mul_mode === "") {
293
- list_itemInfo.push({
296
+ if (match && match[3]) {
297
+ codeBlockFlag = match[1]+match[3]
298
+ if (!fine_mode && list_itemInfo.length > 0) { // 1. 维持当前层级 (标题层级)
299
+ list_itemInfo[list_itemInfo.length - 1].content += "\n" + line
300
+ }
301
+ else if (mul_mode === "heading" || mul_mode === "") { // 2. 进入正文层级 (从标题层级进入)
302
+ removeTailBlank(); list_itemInfo.push({
294
303
  content: line,
295
304
  level: 0
296
305
  })
297
306
  mul_mode = "para"
298
- } else {
299
- codeBlockFlag = match[1]+match[3]
307
+ }
308
+ else { // 3. 维持当前层级 (一般是正文/列表层级)
300
309
  list_itemInfo[list_itemInfo.length-1].content += "\n" + line;
301
310
  }
302
311
  continue
303
312
  }
304
313
  }
305
- else { // 在代码块内,找代码块的结束标志
314
+ else { // 在代码块内,找代码块的结束标志 // 4. 维持当前层级 (Mdit/正文层级)
306
315
  if (line.indexOf(codeBlockFlag) == 0) codeBlockFlag = ''
307
- list_itemInfo[list_itemInfo.length-1].content += "\n" + line; continue
316
+ list_itemInfo[list_itemInfo.length-1].content += "\n" + line; continue;
308
317
  }
309
318
 
310
- //
319
+ // 非代码块内环境
311
320
  const match_heading = line.match(ABReg.reg_heading_noprefix)
312
321
  const match_list = line.match(ABReg.reg_list_noprefix)
313
- if (match_heading && !match_heading[1]){ // 1. 标题层级(只识别根处)
314
- removeTailBlank()
315
- list_itemInfo.push({
316
- content: match_heading[4],
322
+ if (match_heading && !match_heading[1]){ // 1. 进入标题层级
323
+ removeTailBlank(); list_itemInfo.push({
324
+ content: fine_mode ? match_heading[4] : line, // 可选是否把标题标志也放进去
317
325
  level: (match_heading[3].length-1) - 10
318
326
  })
319
327
  mul_mode = "heading"
320
328
  }
321
- else if (match_list){ // 2. 列表层级 ~~(只识别根处)~~
322
- removeTailBlank()
323
- list_itemInfo.push({
329
+ else if (!fine_mode && list_itemInfo.length > 0) { // 2. 维持当前层级 (标题层级)
330
+ list_itemInfo[list_itemInfo.length - 1].content += "\n" + line; continue;
331
+ }
332
+ else if (match_list){ // 3. 进入列表层级 (列表层级的带 `-` 行)
333
+ removeTailBlank(); list_itemInfo.push({
324
334
  content: match_list[4],
325
335
  level: match_list[1].length + 1
326
336
  })
327
337
  mul_mode = "list"
328
338
  }
329
- else if (/^\S/.test(line) && mul_mode=="list"){ // 3. 带缩进且在列表层级中
330
- list_itemInfo[list_itemInfo.length-1].content += "\n" + line
339
+ else if (mul_mode=="list" && /^\s/.test(line)){ // 4. 维持列表层级 (列表层级的不带 `-` 行)
340
+ list_itemInfo[list_itemInfo.length-1].content += "\n" + line.trimStart(); continue;
331
341
  }
332
- else { // 4. 正文层级
333
- if (mul_mode=="para") {
334
- list_itemInfo[list_itemInfo.length-1].content += "\n" + line
342
+ else {
343
+ if (mul_mode=="para") { // 维持正文层级
344
+ list_itemInfo[list_itemInfo.length-1].content += "\n" + line; continue;
335
345
  }
336
- else if(/^\s*$/.test(line)){
346
+ else if(/^\s*$/.test(line)){ // 跳过非正文内的空行
337
347
  continue
338
348
  }
339
- else{
340
- list_itemInfo.push({
349
+ else { // 进入正文层级
350
+ removeTailBlank(); list_itemInfo.push({
341
351
  content: line,
342
352
  level: 0
343
353
  })
344
354
  mul_mode = "para"
355
+ continue
345
356
  }
346
357
  }
347
358
  }
348
359
  removeTailBlank()
349
360
  return list_itemInfo
350
361
 
362
+ /// 清除最后一个节点的尾部空白
351
363
  function removeTailBlank(){
352
364
  if (mul_mode=="para"||mul_mode=="list"){
353
365
  list_itemInfo[list_itemInfo.length-1].content = list_itemInfo[list_itemInfo.length-1].content.replace(/\s*$/, "")
@@ -361,105 +373,90 @@ export class ListProcess{
361
373
  * @detail
362
374
  * 与 title2data 的逻辑基本相同
363
375
  *
364
- * 这里要将Mdit标识 (@xxx)、正文、列表 的等级合为一块,所以存在偏移值:
365
- *
366
- * 1. Mdit等级, = `@<数字>`-100,
367
- * 2. 正文等级, = 0, 取值[+1,+Infi]
368
- * 3. 列表等级, = `(.*)-`个数+1, 取值[0]
369
- *
370
- * 例如:
371
- *
372
- * :::
373
- *
374
- * @1 AAA
375
- *
376
- * aaa
377
- *
378
- * @2 BBB
379
- *
380
- * @2 B22
381
- *
382
- * ccc
383
- * ddd
376
+ * 有很多写法变型和语法糖,所以逻辑比较复杂。
377
+ * 具体设计详见 "docs/docs/dev docs/其他层级表示法.md"
384
378
  *
385
- * @1 A22
379
+ * 支持:
386
380
  *
387
- * :::
381
+ * - 单行标题模式
382
+ * - 多行标题模式
383
+ * - 缺少分割标题模式
388
384
  *
389
- * 会被转化为
390
- *
391
- * - AAA
392
- * - BBB
393
- * - B22
394
- * - ccc
395
- * ddd
396
- * - A22
385
+ * @fine_mode 精细拆分模式
386
+ * - true: 会将正文和列表拆分成多个节点
387
+ * - false: 会将标题+正文+列表合并成一个节点
397
388
  */
398
- static mdit2data(text: string): List_ListItem {
389
+ static mdit2data(text: string, fine_mode: boolean = true): List_ListItem {
399
390
  let list_itemInfo: List_ListItem = []
400
391
 
401
392
  const list_text = text.split("\n")
402
393
  let mul_mode: "mdit" | "para" | "list" | "" = "" // 多行模式,mdit/正文/列表/空
403
- let codeBlockFlag = '' // 代码块标志,避免在代码块内识别结束符号
394
+ let codeBlockFlag = '' // 代码块标志,避免在代码块内识别结束符号
404
395
  for (let line of list_text) {
396
+
405
397
  // heading和mdit类型都需要跳过代码块内的结束标志
406
398
  if (codeBlockFlag == '') {
407
399
  const match = line.match(ABReg.reg_code)
408
- if (match && match[3]) { // 进入代码块。则将内容添加到最后的列表项 (不能是mdit列表项)
409
- if (mul_mode === "mdit" || mul_mode === "") {
410
- list_itemInfo.push({
400
+ if (match && match[3]) {
401
+ codeBlockFlag = match[1] + match[3]
402
+ if (!fine_mode && list_itemInfo.length > 0) { // 1. 维持当前层级 (Mdit层级)
403
+ list_itemInfo[list_itemInfo.length - 1].content += "\n" + line
404
+ }
405
+ else if (mul_mode === "mdit" || mul_mode === "") { // 2. 进入正文层级 (从Mdit层级进入)
406
+ removeTailBlank(); list_itemInfo.push({
411
407
  content: line,
412
408
  level: 0
413
409
  })
414
410
  mul_mode = "para"
415
- } else {
416
- codeBlockFlag = match[1] + match[3]
411
+ }
412
+ else { // 3. 维持当前层级 (一般是正文/列表层级)
417
413
  list_itemInfo[list_itemInfo.length-1].content += "\n" + line
418
414
  }
419
415
  continue
420
416
  }
421
417
  }
422
- else { // 在代码块内,找代码块的结束标志
418
+ else { // 在代码块内,找代码块的结束标志 // 4. 维持当前层级 (Mdit/正文层级)
423
419
  if (line.indexOf(codeBlockFlag) == 0) codeBlockFlag = ''
424
- list_itemInfo[list_itemInfo.length-1].content += "\n" + line
425
- continue
420
+ list_itemInfo[list_itemInfo.length-1].content += "\n" + line; continue;
426
421
  }
427
422
 
428
- //
429
- const match_mdit = line.match(/^(\s*)@(\d+)\s+(.*)$/)
423
+ // 非代码块内环境
424
+ const match_mdit = line.match(/^(\s*)@(\d+)(?:\s+(.*))?$/)
430
425
  const match_list = line.match(ABReg.reg_list_noprefix)
431
- if (match_mdit && !match_mdit[1]) { // 1. Mdit层级(只识别根处)
432
- removeTailBlank()
433
- list_itemInfo.push({
434
- content: match_mdit[3],
426
+ if (match_mdit && !match_mdit[1]) { // 1. 进入Mdit@层级
427
+ removeTailBlank(); list_itemInfo.push({
428
+ content: match_mdit[3] ?? "",
435
429
  level: Number(match_mdit[2]) - 100
436
430
  })
437
431
  mul_mode = "mdit"
438
432
  }
439
- else if (match_list) { // 2. 列表层级 ~~(只识别根处)~~
440
- removeTailBlank()
441
- list_itemInfo.push({
433
+ else if (!fine_mode && list_itemInfo.length > 0) { // 2. 维持当前层级 (Mdit层级)
434
+ list_itemInfo[list_itemInfo.length - 1].content += "\n" + line; continue;
435
+ }
436
+ else if (match_list) { // 3. 进入列表层级 (列表层级的带 `-` 行)
437
+ removeTailBlank(); list_itemInfo.push({
442
438
  content: match_list[4],
443
439
  level: match_list[1].length + 1
444
440
  })
445
441
  mul_mode = "list"
446
442
  }
447
- else if (/^\S/.test(line) && mul_mode == "list") { // 3. 带缩进且在列表层级中
448
- list_itemInfo[list_itemInfo.length-1].content += "\n" + line
443
+ else if (mul_mode == "list" && /^\s/.test(line)) { // 4. 维持列表层级 (列表层级的不带 `-` 行)
444
+ list_itemInfo[list_itemInfo.length-1].content += "\n" + line.trimStart(); continue;
449
445
  }
450
- else { // 4. 正文层级
451
- if (mul_mode == "para") {
452
- list_itemInfo[list_itemInfo.length-1].content += "\n" + line
446
+ else {
447
+ if (mul_mode == "para") { // 维持正文层级
448
+ list_itemInfo[list_itemInfo.length-1].content += "\n" + line; continue;
453
449
  }
454
- else if (/^\s*$/.test(line)) {
450
+ else if (/^\s*$/.test(line)) { // 跳过非正文空行
455
451
  continue
456
452
  }
457
- else {
458
- list_itemInfo.push({
453
+ else { // 进入正文层级
454
+ removeTailBlank(); list_itemInfo.push({
459
455
  content: line,
460
456
  level: 0
461
457
  })
462
458
  mul_mode = "para"
459
+ continue
463
460
  }
464
461
  }
465
462
  }
@@ -467,6 +464,7 @@ export class ListProcess{
467
464
  removeTailBlank()
468
465
  return list_itemInfo
469
466
 
467
+ /// 清除最后一个节点的尾部空白
470
468
  function removeTailBlank(){
471
469
  if (mul_mode == "para" || mul_mode == "list") {
472
470
  list_itemInfo[list_itemInfo.length-1].content = list_itemInfo[list_itemInfo.length-1].content.replace(/\s*$/, "")
@@ -694,7 +692,7 @@ export const abc_list2listdata = ABConvert.factory({
694
692
  process_param: ABConvert_IOEnum.text,
695
693
  process_return: ABConvert_IOEnum.list_stream,
696
694
  detail: "列表到listdata",
697
- process: (el, header, content: string): List_ListItem=>{
695
+ process: (_el, _header, content: string): List_ListItem=>{
698
696
  return ListProcess.list2data(content) as List_ListItem
699
697
  }
700
698
  })
@@ -704,9 +702,20 @@ export const abc_title2listdata = ABConvert.factory({
704
702
  name: "标题到listdata",
705
703
  process_param: ABConvert_IOEnum.text,
706
704
  process_return: ABConvert_IOEnum.list_stream,
707
- detail: "标题到listdata",
708
- process: (el, header, content: string): List_ListItem=>{
709
- return ListProcess.title2data(content) as List_ListItem
705
+ detail: "标题到listdata。细粒度版本,列表会拆分成多个节点",
706
+ process: (_el, _header, content: string): List_ListItem=>{
707
+ return ListProcess.title2data(content, true) as List_ListItem
708
+ }
709
+ })
710
+
711
+ export const abc_title2Listdata = ABConvert.factory({
712
+ id: "title2Listdata",
713
+ name: "标题到Listdata",
714
+ process_param: ABConvert_IOEnum.text,
715
+ process_return: ABConvert_IOEnum.list_stream,
716
+ detail: "标题到Listdata。粗粒度版本,列表为一个节点,不会拆分",
717
+ process: (_el, _header, content: string): List_ListItem=>{
718
+ return ListProcess.title2data(content, false) as List_ListItem
710
719
  }
711
720
  })
712
721
 
@@ -715,9 +724,20 @@ export const abc_mdit2listdata = ABConvert.factory({
715
724
  name: "mdit到listdata",
716
725
  process_param: ABConvert_IOEnum.text,
717
726
  process_return: ABConvert_IOEnum.list_stream,
718
- detail: "mdit到listdata",
719
- process: (el, header, content: string): List_ListItem=>{
720
- return ListProcess.mdit2data(content) as List_ListItem
727
+ detail: "mdit到listdata。细粒度版本,列表会拆分成多个节点",
728
+ process: (_el, _header, content: string): List_ListItem=>{
729
+ return ListProcess.mdit2data(content, true) as List_ListItem
730
+ }
731
+ })
732
+
733
+ export const abc_mdit2Listdata = ABConvert.factory({
734
+ id: "mdit2Listdata",
735
+ name: "mdit到Listdata",
736
+ process_param: ABConvert_IOEnum.text,
737
+ process_return: ABConvert_IOEnum.list_stream,
738
+ detail: "mdit到Listdata。粗粒度版本,列表为一个节点,不会拆分",
739
+ process: (_el, _header, content: string): List_ListItem=>{
740
+ return ListProcess.mdit2data(content, false) as List_ListItem
721
741
  }
722
742
  })
723
743
 
@@ -727,7 +747,7 @@ const _abc_listdata2list = ABConvert.factory({
727
747
  process_param: ABConvert_IOEnum.list_stream,
728
748
  process_return: ABConvert_IOEnum.text,
729
749
  detail: "listdata到列表",
730
- process: (el, header, content: List_ListItem): string=>{
750
+ process: (_el, _header, content: List_ListItem): string=>{
731
751
  return ListProcess.data2list(content) as string
732
752
  }
733
753
  })
@@ -738,7 +758,7 @@ const _abc_listdata2nodes = ABConvert.factory({
738
758
  process_param: ABConvert_IOEnum.list_stream,
739
759
  process_return: ABConvert_IOEnum.el,
740
760
  detail: "listdata到节点图",
741
- process: (el, header, content: List_ListItem): HTMLElement=>{
761
+ process: (el, _header, content: List_ListItem): HTMLElement=>{
742
762
  return ListProcess.data2nodes(content, el) as HTMLElement
743
763
  }
744
764
  })
@@ -746,10 +766,11 @@ const _abc_listdata2nodes = ABConvert.factory({
746
766
  const _abc_listdata2strict = ABConvert.factory({
747
767
  id: "listdata2strict",
748
768
  name: "listdata严格化",
769
+ match: /listdata2strict|listdata2lint/,
749
770
  process_param: ABConvert_IOEnum.list_stream,
750
771
  process_return: ABConvert_IOEnum.list_stream,
751
772
  detail: "将列表数据转化为更规范的列表数据。统一缩进符(2空格 4空格 tab混用)为level 1、禁止跳等级(h1直接就到h3)",
752
- process: (el, header, content: List_ListItem): List_ListItem=>{
773
+ process: (_el, _header, content: List_ListItem): List_ListItem=>{
753
774
  return ListProcess.data2strict(content)
754
775
  }
755
776
  })
@@ -760,7 +781,7 @@ const _abc_listdata2task = ABConvert.factory({
760
781
  process_param: ABConvert_IOEnum.list_stream,
761
782
  process_return: ABConvert_IOEnum.list_stream,
762
783
  detail: "当列表中存在任务列表项时,令此列表项支持任务项",
763
- process: (el, header, content: List_ListItem): List_ListItem=>{
784
+ process: (_el, _header, content: List_ListItem): List_ListItem=>{
764
785
  return ListProcess.data2taskData(content)
765
786
  }
766
787
  })
@@ -771,7 +792,7 @@ export const abc_list2listnode = ABConvert.factory({
771
792
  process_param: ABConvert_IOEnum.text,
772
793
  process_return: ABConvert_IOEnum.json,
773
794
  detail: "列表到listnode",
774
- process: (el, header, content: string): string=>{
795
+ process: (_el, _header, content: string): string=>{
775
796
  const data: listNodes[] = ListProcess.list2listnode(content)
776
797
  return JSON.stringify(data, null, 2) // TMP
777
798
  }
@@ -783,7 +804,7 @@ export const abc_list2json = ABConvert.factory({
783
804
  process_param: ABConvert_IOEnum.text,
784
805
  process_return: ABConvert_IOEnum.json,
785
806
  detail: "列表到json",
786
- process: (el, header, content: string): string=>{
807
+ process: (_el, _header, content: string): string=>{
787
808
  const data: object = ListProcess.list2json(content)
788
809
  return JSON.stringify(data, null, 2) // TMP
789
810
  }
@@ -168,6 +168,8 @@ const _abc_title2table = ABConvert.factory({
168
168
  })
169
169
 
170
170
  // 纯组合,后续用别名模块替代
171
+ // 不过目前用得比较频繁,而且还有参数,先放着
172
+ // 不过尽量不直接用
171
173
  const _abc_list2table = ABConvert.factory({
172
174
  id: "list2table",
173
175
  name: "列表转表格",
@@ -183,6 +185,20 @@ const _abc_list2table = ABConvert.factory({
183
185
  }
184
186
  })
185
187
 
188
+ const _abc_listdata2table = ABConvert.factory({
189
+ id: "listdata2table",
190
+ name: "列表数据转表格",
191
+ match: /listdata2(md)?table(T)?/,
192
+ default: "listdata2table",
193
+ process_param: ABConvert_IOEnum.list_stream,
194
+ process_return: ABConvert_IOEnum.el,
195
+ process: (el, header, content: List_ListItem): HTMLElement=>{
196
+ const matchs = header.match(/listdata2(md)?table(T)?/)
197
+ if (!matchs) return el
198
+ return el = TableProcess.data2table(content, el, matchs[2]=="T") as HTMLDivElement
199
+ }
200
+ })
201
+
186
202
  const _abc_list2c2table = ABConvert.factory({
187
203
  id: "list2c2t",
188
204
  name: "列表转二列表格",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anyblock/any-block-core",
3
- "version": "3.4.12",
3
+ "version": "3.5.0",
4
4
  "description": "You can flexibility to create a 'Block' by many means. It also provides many useful features, like `list to table`. (obsidian/markdown-it/vuepress plugin/app)",
5
5
  "main": "index.js",
6
6
  "scripts": {