@anyblock/remark-any-block 1.0.0-beta10 → 1.0.0-beta12

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/anyblock.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import { Plugin } from "unified"
2
2
  import { Root, RootContent, Paragraph, Text, Code, Html } from "mdast"
3
3
  import type { VFile } from "vfile"
4
- import { toMarkdown } from "mdast-util-to-markdown"
5
4
  import { visit } from "unist-util-visit"
5
+ import { toMarkdown } from "mdast-util-to-markdown" // TODO 这里好像会有 document 依赖
6
+ // 而且不一定能反序列化成功 (有私有节点类型,甚至table类型都不能识别)
7
+ // 后期需要去除此 "修改树" 的 `transformer` / `mdast-util` 插件
8
+ // 修改成 `micromarkExtensions` 形式的插件
6
9
 
7
10
  // 这里不想去依赖 Quartz 项目,所以用any。但是你可以去看具体的类型定义
8
11
  // import { type QuartzTransformerPlugin } from "../types"
@@ -54,15 +57,18 @@ export interface AnyBlockOptions {
54
57
  */
55
58
  function matchAbHeader(node: RootContent): string | null {
56
59
  if (node.type !== "paragraph") return null;
60
+
57
61
  const text = (node.children as RootContent[])
58
62
  .map((c) => (c.type === "text" ? (c as Text).value : ""))
59
63
  .join("");
60
- const m = text.match(ABReg.reg_header);
61
- return m && m[1] ? m[1] : null;
64
+ const match = text.match(ABReg.reg_header_noprefix);
65
+ if (!match || !match.length) return null
66
+
67
+ return match[5]
62
68
  }
63
69
 
64
70
  /**
65
- * 检测 `:::container` 段落
71
+ * 检测 `:::container` 首段落
66
72
  * 匹配时返回 `{flag, type}`
67
73
  */
68
74
  function matchContainerStart(node: RootContent):
@@ -79,9 +85,9 @@ function matchContainerStart(node: RootContent):
79
85
  }
80
86
 
81
87
  /**
82
- * 检测到一个 `:::` 结尾的段落
88
+ * 检测 `:::container` 尾段落
83
89
  */
84
- function isContainerEnd(node: RootContent, flag: string): boolean {
90
+ function matchContainerEnd(node: RootContent, flag: string): boolean {
85
91
  if (node.type !== "paragraph") return false;
86
92
  const text = (node.children as RootContent[])
87
93
  .map((c) => (c.type === "text" ? (c as Text).value : ""))
@@ -91,7 +97,7 @@ function isContainerEnd(node: RootContent, flag: string): boolean {
91
97
  }
92
98
 
93
99
  /**
94
- * 将一组 mdast 节点序列化为 markdown 格式
100
+ * 将一组 mdast 节点反序列化为 markdown 格式
95
101
  */
96
102
  function nodesToMarkdown(nodes: RootContent[]): string {
97
103
  return toMarkdown(
@@ -107,86 +113,73 @@ function nodesToMarkdown(nodes: RootContent[]): string {
107
113
  * - `:::type ... :::`
108
114
  */
109
115
  export const remark_anyblock_to_codeblock: Plugin<[Partial<AnyBlockOptions>?], Root> =
110
- (_options = {}) =>
111
- (tree) => {
112
- const out: RootContent[] = [];
113
- const children = [...tree.children] as RootContent[];
114
-
115
- for (let i = 0; i < children.length; i++) {
116
- const node = children[i];
116
+ (_options = {}) => (tree) =>
117
+ {
118
+ const children = [...tree.children] as RootContent[];
119
+
120
+ const out: RootContent[] = [];
121
+ for (let i = 0; i < children.length; i++) {
122
+ const node = children[i];
123
+
124
+ // step1. 检测 `[]` 语法
125
+ const header = matchAbHeader(node);
126
+ if (header) {
127
+ const node_next = children[i+1];
128
+ if (
129
+ node_next.type === "list" ||
130
+ node_next.type === "heading" ||
131
+ node_next.type === "code" ||
132
+ node_next.type === "blockquote"
133
+ // node_next.type === "table"
134
+ ) {
135
+ const codeValue = `[${header}]\n${nodesToMarkdown([node_next])}`;
136
+ out.push({
137
+ type: "code",
138
+ lang: "anyblock",
139
+ value: codeValue,
140
+ data: { markup: "[]" },
141
+ } as Code);
142
+ i++; continue;
143
+ } else {}
144
+ }
117
145
 
118
- // --- square-inline header flow ---
119
- const header = matchAbHeader(node);
120
- if (header) {
121
- const body: RootContent[] = [];
122
- let j = i + 1;
123
- for (; j < children.length; j++) {
124
- const n = children[j];
125
- if (
126
- n.type === "list" ||
127
- n.type === "heading" ||
128
- n.type === "code" ||
129
- n.type === "blockquote" ||
130
- n.type === "table"
131
- ) {
132
- body.push(n);
133
- continue;
134
- }
135
- // stop when first non-matching block is hit
146
+ // step2. 检测 `:::` 语法
147
+ const container = matchContainerStart(node);
148
+ if (container) {
149
+ const body: RootContent[] = [];
150
+ let j = i + 1;
151
+ for (; j < children.length; j++) {
152
+ const n = children[j];
153
+ if (matchContainerEnd(n, container.flag)) {
136
154
  break;
137
155
  }
138
- if (body.length > 0) {
139
- const codeValue = `[${header}]\n${nodesToMarkdown(body)}`;
140
- out.push({
141
- type: "code",
142
- lang: "AnyBlock",
143
- value: codeValue,
144
- data: { markup: "[]" },
145
- } as Code);
146
- i = j - 1;
147
- continue;
148
- }
156
+ body.push(n);
149
157
  }
150
-
151
- // --- ::: container flow ---
152
- const container = matchContainerStart(node);
153
- if (container) {
154
- const body: RootContent[] = [];
155
- let j = i + 1;
156
- for (; j < children.length; j++) {
157
- const n = children[j];
158
- if (isContainerEnd(n, container.flag)) {
159
- break;
160
- }
161
- body.push(n);
162
- }
163
- if (j < children.length) {
164
- const codeValue = `[${container.type}]\n${nodesToMarkdown(body)}`;
165
- out.push({
166
- type: "code",
167
- lang: "AnyBlock",
168
- value: codeValue,
169
- data: { markup: container.flag },
170
- } as Code);
171
- i = j; // skip closing line
172
- continue;
173
- }
158
+ if (j < children.length) {
159
+ const codeValue = `[${container.type}]\n${nodesToMarkdown(body)}`;
160
+ out.push({
161
+ type: "code",
162
+ lang: "anyblock",
163
+ value: codeValue,
164
+ data: { markup: container.flag },
165
+ } as Code);
166
+ i = j; continue;
174
167
  }
175
-
176
- // default passthrough
177
- out.push(node);
178
168
  }
179
169
 
180
- (tree as Root).children = out;
170
+ // step3. 不处理的节点,保持不变
171
+ out.push(node)
181
172
  }
182
173
 
174
+ (tree as Root).children = out;
175
+ }
176
+
183
177
  // 渲染 anyblock 代码块
184
178
  export const remark_anyblock_render_codeblock = () => {
185
179
  if (typeof document == "undefined") return
186
180
  return (tree: Root, _file: VFile) => {
187
181
  visit(tree, "code", (node: Code, index: number|undefined, parent: any|undefined) => { // 遍历所有的 code 类型节点
188
- console.log("\nanyblock codeblock transformer visit:", node)
189
- if (node.lang != "anyblock") return
182
+ if (node.lang.toLowerCase() != "anyblock") return
190
183
  if (!parent || !index) return
191
184
 
192
185
  const lines = node.value.split("\n")
@@ -203,8 +196,6 @@ export const remark_anyblock_render_codeblock = () => {
203
196
  ABConvertManager.autoABConvert(el, header, content, markup.startsWith(":::") ? "mdit" : "");
204
197
 
205
198
  // new node
206
- console.log("\nanyblock codeblock transformer visit2:", header, 'c==', content)
207
- console.log("\nanyblock codeblock transformer visit3:", el.outerHTML, el)
208
199
  const new_node: Html = {
209
200
  type: 'html',
210
201
  value: el.outerHTML,
@@ -245,7 +236,7 @@ export const transformer_anyblock: QuartzTransformerPlugin = (/*options: any*/)
245
236
  name: "AnyBlock",
246
237
  markdownPlugins(_ctx: BuildCtx) {
247
238
  return [
248
- // remark_anyblock_to_codeblock,
239
+ remark_anyblock_to_codeblock,
249
240
  remark_anyblock_render_codeblock, // last
250
241
  ]
251
242
  },