@anyblock/remark-any-block 1.0.0-beta1 → 1.0.0-beta11

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/README.md CHANGED
@@ -30,7 +30,7 @@ $ npm publish --tag beta # 如果使用测试或beta版本 (包含 `-tagname`)
30
30
  ```
31
31
 
32
32
  > [!warning]
33
- > 补丁: 2025-12-09 开始不再能使用长期验证方式,得用 `npm login`
33
+ > 补丁: 2025-12-09 开始不再能使用长期验证方式,得每次都要 `npm login` 一下
34
34
  >
35
35
  > 否则报错:
36
36
  > ```bash
package/anyblock.ts CHANGED
@@ -1,9 +1,3 @@
1
- // import { unified } from 'unified';
2
- // import remarkParse from 'remark-parse';
3
- // import remarkRehype from 'remark-rehype';
4
- // import rehypeStringify from 'rehype-stringify';
5
-
6
- // import { remove } from "unist-util-remove"
7
1
  import { Plugin } from "unified"
8
2
  import { Root, RootContent, Paragraph, Text, Code, Html } from "mdast"
9
3
  import type { VFile } from "vfile"
@@ -60,15 +54,18 @@ export interface AnyBlockOptions {
60
54
  */
61
55
  function matchAbHeader(node: RootContent): string | null {
62
56
  if (node.type !== "paragraph") return null;
57
+
63
58
  const text = (node.children as RootContent[])
64
59
  .map((c) => (c.type === "text" ? (c as Text).value : ""))
65
60
  .join("");
66
- const m = text.match(ABReg.reg_header);
67
- return m && m[1] ? m[1] : null;
61
+ const match = text.match(ABReg.reg_header_noprefix);
62
+ if (!match || !match.length) return null
63
+
64
+ return match[5]
68
65
  }
69
66
 
70
67
  /**
71
- * 检测 `:::container` 段落
68
+ * 检测 `:::container` 首段落
72
69
  * 匹配时返回 `{flag, type}`
73
70
  */
74
71
  function matchContainerStart(node: RootContent):
@@ -85,9 +82,9 @@ function matchContainerStart(node: RootContent):
85
82
  }
86
83
 
87
84
  /**
88
- * 检测到一个 `:::` 结尾的段落
85
+ * 检测 `:::container` 尾段落
89
86
  */
90
- function isContainerEnd(node: RootContent, flag: string): boolean {
87
+ function matchContainerEnd(node: RootContent, flag: string): boolean {
91
88
  if (node.type !== "paragraph") return false;
92
89
  const text = (node.children as RootContent[])
93
90
  .map((c) => (c.type === "text" ? (c as Text).value : ""))
@@ -97,7 +94,7 @@ function isContainerEnd(node: RootContent, flag: string): boolean {
97
94
  }
98
95
 
99
96
  /**
100
- * 将一组 mdast 节点序列化为 markdown 格式
97
+ * 将一组 mdast 节点反序列化为 markdown 格式
101
98
  */
102
99
  function nodesToMarkdown(nodes: RootContent[]): string {
103
100
  return toMarkdown(
@@ -113,85 +110,73 @@ function nodesToMarkdown(nodes: RootContent[]): string {
113
110
  * - `:::type ... :::`
114
111
  */
115
112
  export const remark_anyblock_to_codeblock: Plugin<[Partial<AnyBlockOptions>?], Root> =
116
- (_options = {}) =>
117
- (tree) => {
118
- const out: RootContent[] = [];
119
- const children = [...tree.children] as RootContent[];
120
-
121
- for (let i = 0; i < children.length; i++) {
122
- const node = children[i];
113
+ (_options = {}) => (tree) =>
114
+ {
115
+ const children = [...tree.children] as RootContent[];
116
+
117
+ const out: RootContent[] = [];
118
+ for (let i = 0; i < children.length; i++) {
119
+ const node = children[i];
120
+
121
+ // step1. 检测 `[]` 语法
122
+ const header = matchAbHeader(node);
123
+ if (header) {
124
+ const node_next = children[i+1];
125
+ if (
126
+ node_next.type === "list" ||
127
+ node_next.type === "heading" ||
128
+ node_next.type === "code" ||
129
+ node_next.type === "blockquote" ||
130
+ node_next.type === "table"
131
+ ) {
132
+ const codeValue = `[${header}]\n${nodesToMarkdown([node_next])}`;
133
+ out.push({
134
+ type: "code",
135
+ lang: "anyblock",
136
+ value: codeValue,
137
+ data: { markup: "[]" },
138
+ } as Code);
139
+ i++; continue;
140
+ } else {}
141
+ }
123
142
 
124
- // --- square-inline header flow ---
125
- const header = matchAbHeader(node);
126
- if (header) {
127
- const body: RootContent[] = [];
128
- let j = i + 1;
129
- for (; j < children.length; j++) {
130
- const n = children[j];
131
- if (
132
- n.type === "list" ||
133
- n.type === "heading" ||
134
- n.type === "code" ||
135
- n.type === "blockquote" ||
136
- n.type === "table"
137
- ) {
138
- body.push(n);
139
- continue;
140
- }
141
- // stop when first non-matching block is hit
143
+ // step2. 检测 `:::` 语法
144
+ const container = matchContainerStart(node);
145
+ if (container) {
146
+ const body: RootContent[] = [];
147
+ let j = i + 1;
148
+ for (; j < children.length; j++) {
149
+ const n = children[j];
150
+ if (matchContainerEnd(n, container.flag)) {
142
151
  break;
143
152
  }
144
- if (body.length > 0) {
145
- const codeValue = `[${header}]\n${nodesToMarkdown(body)}`;
146
- out.push({
147
- type: "code",
148
- lang: "AnyBlock",
149
- value: codeValue,
150
- data: { markup: "[]" },
151
- } as Code);
152
- i = j - 1;
153
- continue;
154
- }
153
+ body.push(n);
155
154
  }
156
-
157
- // --- ::: container flow ---
158
- const container = matchContainerStart(node);
159
- if (container) {
160
- const body: RootContent[] = [];
161
- let j = i + 1;
162
- for (; j < children.length; j++) {
163
- const n = children[j];
164
- if (isContainerEnd(n, container.flag)) {
165
- break;
166
- }
167
- body.push(n);
168
- }
169
- if (j < children.length) {
170
- const codeValue = `[${container.type}]\n${nodesToMarkdown(body)}`;
171
- out.push({
172
- type: "code",
173
- lang: "AnyBlock",
174
- value: codeValue,
175
- data: { markup: container.flag },
176
- } as Code);
177
- i = j; // skip closing line
178
- continue;
179
- }
155
+ if (j < children.length) {
156
+ const codeValue = `[${container.type}]\n${nodesToMarkdown(body)}`;
157
+ out.push({
158
+ type: "code",
159
+ lang: "anyblock",
160
+ value: codeValue,
161
+ data: { markup: container.flag },
162
+ } as Code);
163
+ i = j; continue;
180
164
  }
181
-
182
- // default passthrough
183
- out.push(node);
184
165
  }
185
166
 
186
- (tree as Root).children = out;
167
+ // step3. 不处理的节点,保持不变
168
+ out.push(node)
187
169
  }
188
170
 
171
+ (tree as Root).children = out;
172
+ }
173
+
189
174
  // 渲染 anyblock 代码块
190
- const remark_anyblock_render_codeblock = () => {
175
+ export const remark_anyblock_render_codeblock = () => {
176
+ if (typeof document == "undefined") return
191
177
  return (tree: Root, _file: VFile) => {
192
178
  visit(tree, "code", (node: Code, index: number|undefined, parent: any|undefined) => { // 遍历所有的 code 类型节点
193
- console.log("\nanyblock codeblock transformer visit:", node)
194
- if (node.lang != "anyblock") return
179
+ if (node.lang.toLowerCase() != "anyblock") return
195
180
  if (!parent || !index) return
196
181
 
197
182
  const lines = node.value.split("\n")
@@ -208,8 +193,6 @@ const remark_anyblock_render_codeblock = () => {
208
193
  ABConvertManager.autoABConvert(el, header, content, markup.startsWith(":::") ? "mdit" : "");
209
194
 
210
195
  // new node
211
- console.log("\nanyblock codeblock transformer visit2:", header, 'c==', content)
212
- console.log("\nanyblock codeblock transformer visit3:", el.outerHTML, el)
213
196
  const new_node: Html = {
214
197
  type: 'html',
215
198
  value: el.outerHTML,
@@ -222,7 +205,7 @@ const remark_anyblock_render_codeblock = () => {
222
205
 
223
206
  {
224
207
  // 定义环境条件
225
- ABCSetting.env = "markdown-it"; // remark
208
+ ABCSetting.env = "remark";
226
209
 
227
210
  // 定义默认渲染行为 // [!code hl] risk 同步适配异步,可能会存在问题
228
211
  ABConvertManager.getInstance().redefine_renderMarkdown((markdown: string, el: HTMLElement):void => {
@@ -250,7 +233,7 @@ export const transformer_anyblock: QuartzTransformerPlugin = (/*options: any*/)
250
233
  name: "AnyBlock",
251
234
  markdownPlugins(_ctx: BuildCtx) {
252
235
  return [
253
- // remark_anyblock_to_codeblock,
236
+ remark_anyblock_to_codeblock,
254
237
  remark_anyblock_render_codeblock, // last
255
238
  ]
256
239
  },