@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 +67 -76
- package/dist/remark-any-block.cjs +2558 -1020
- package/dist/remark-any-block.js +2558 -1020
- package/index.ts +1 -1
- package/package.json +1 -1
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
|
|
61
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
239
|
+
remark_anyblock_to_codeblock,
|
|
249
240
|
remark_anyblock_render_codeblock, // last
|
|
250
241
|
]
|
|
251
242
|
},
|