bobe-dom 0.0.60 → 0.0.62

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.
@@ -0,0 +1,272 @@
1
+ 'use strict';
2
+
3
+ var marked = require('marked');
4
+ var path = require('path');
5
+ var fs = require('fs');
6
+ var hljs = require('highlight.js');
7
+
8
+ function highlight(code, lang) {
9
+ try {
10
+ return hljs.highlight(code, {
11
+ language: lang
12
+ }).value;
13
+ } catch {
14
+ return code.replace(/</g, '&lt;').replace(/>/g, '&gt;');
15
+ }
16
+ }
17
+ async function resolveImportTree(importPath, currentPath, vResolve, walked = new Set()) {
18
+ const resolved = await vResolve(importPath, currentPath);
19
+ const absPath = resolved?.id;
20
+ if (!absPath || absPath.includes('node_modules') || absPath.startsWith('\0') || walked.has(absPath)) {
21
+ return [];
22
+ }
23
+ walked.add(absPath);
24
+ let content = '';
25
+ try {
26
+ content = await fs.promises.readFile(absPath, 'utf-8');
27
+ } catch (error) {
28
+ console.warn(`Failed to read file: ${absPath}`);
29
+ }
30
+ if (!content) {
31
+ return [];
32
+ }
33
+ const langMap = {
34
+ ts: 'typescript',
35
+ tsx: 'typescript',
36
+ mts: 'typescript',
37
+ js: 'javascript',
38
+ jsx: 'javascript',
39
+ mjs: 'javascript',
40
+ css: 'css',
41
+ html: 'xml',
42
+ json: 'json'
43
+ };
44
+ const ext = path.extname(absPath).slice(1);
45
+ const lang = langMap[ext];
46
+ const item = {
47
+ path: absPath,
48
+ name: path.basename(absPath),
49
+ lang: lang,
50
+ html: lang ? highlight(content, lang) : content
51
+ };
52
+ const importRegex = /import\s+(?:[\w*\s{},]*\s+from\s+)?['"]([^'"]+)['"]/g;
53
+ let match;
54
+ const dependencies = [];
55
+ while ((match = importRegex.exec(content)) !== null) {
56
+ const importPath = match[1];
57
+ if (!importPath.startsWith('http')) {
58
+ dependencies.push(resolveImportTree(importPath, absPath, vResolve, walked));
59
+ }
60
+ }
61
+ if (!dependencies.length) {
62
+ return [item];
63
+ }
64
+ const deps = await Promise.all(dependencies);
65
+ return [item, ...deps.flat()];
66
+ }
67
+
68
+ function registerBobeLang() {
69
+ hljs.registerLanguage('bobe', hljs => {
70
+ const ATTRS = ['class', 'id', 'text', 'html', 'style', 'href', 'src', 'alt', 'title', 'ref', 'type', 'placeholder', 'value', 'name', 'foo', 'disabled', 'readonly', 'checked', 'selected', 'hidden', 'role', 'target', 'rel', 'width', 'height', 'tabindex', 'data-[\\w-]+', 'aria-[\\w-]+', 'onclick', 'oninput', 'onchange', 'onsubmit', 'onreset', 'onkeydown', 'onkeyup', 'onkeypress', 'onfocus', 'onblur', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseover', 'onmouseout', 'onload', 'onerror', 'onscroll', 'onresize', 'ondrag', 'ondragstart', 'ondragend', 'ondragover', 'ondrop', 'ontouchstart', 'ontouchend', 'ontouchmove'].join('|');
71
+ return {
72
+ name: 'bobe',
73
+ keywords: ['if', 'else', 'for', 'tp', 'context'],
74
+ contains: [hljs.COMMENT('#', '$', {
75
+ relevance: 0
76
+ }), {
77
+ className: 'template-substitution',
78
+ begin: /\$\{/,
79
+ end: /\}/,
80
+ contains: [{
81
+ begin: /\$\{/,
82
+ end: /\}/,
83
+ skip: true
84
+ }],
85
+ subLanguage: 'javascript'
86
+ }, {
87
+ className: 'template-substitution',
88
+ begin: /(?<==)\{/,
89
+ end: /\}/,
90
+ contains: [{
91
+ begin: /\{/,
92
+ end: /\}/,
93
+ skip: true
94
+ }],
95
+ subLanguage: 'javascript'
96
+ }, {
97
+ className: 'string',
98
+ begin: /"/,
99
+ end: /"/,
100
+ contains: [{
101
+ begin: /\$\{/,
102
+ end: /\}/,
103
+ subLanguage: 'javascript'
104
+ }]
105
+ }, {
106
+ className: 'selector-tag',
107
+ begin: /^[ \t]*(?!(?:if|else|for|tp)\b)[a-z][\w-]*(?:-[a-z][\w-]*)*\b/m,
108
+ relevance: 2
109
+ }, {
110
+ className: 'attr',
111
+ begin: new RegExp(`\\b(?:${ATTRS})\\b(?=\\s*=)`),
112
+ relevance: 1
113
+ }, {
114
+ className: 'attr',
115
+ begin: /\b(?:disabled|readonly|checked|selected|hidden)\b(?!\s*=)/,
116
+ relevance: 0
117
+ }, {
118
+ className: 'variable',
119
+ begin: /(?<=for\s+)\w+(?=\s*;)/,
120
+ relevance: 0
121
+ }, {
122
+ className: 'params',
123
+ begin: /(?<=for\s+\S+\s*;\s*)\w+/,
124
+ relevance: 0
125
+ }, {
126
+ className: 'params',
127
+ begin: /(?<=for\s+\S+\s*;\s*\w+\s+)\w+/,
128
+ relevance: 0
129
+ }, hljs.NUMBER_MODE]
130
+ };
131
+ });
132
+ function patchJsFamily(name) {
133
+ const fn = hljs.getLanguage(name)?.rawDefinition;
134
+ if (!fn) return;
135
+ const def = fn(hljs);
136
+ if (def.contains.some(c => c.begin?.toString?.().includes('bobe'))) return;
137
+ const SUBST = {
138
+ className: 'subst',
139
+ begin: /\$\{/,
140
+ end: /\}/,
141
+ keywords: def.keywords
142
+ };
143
+ def.contains.push({
144
+ begin: /\.?bobe`/,
145
+ end: '',
146
+ starts: {
147
+ end: '`',
148
+ returnEnd: false,
149
+ contains: [hljs.BACKSLASH_ESCAPE, SUBST],
150
+ subLanguage: 'bobe'
151
+ }
152
+ });
153
+ hljs.registerLanguage(name, () => def);
154
+ }
155
+ patchJsFamily('javascript');
156
+ patchJsFamily('typescript');
157
+ }
158
+
159
+ function esc(s) {
160
+ return s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$');
161
+ }
162
+ function gen(html, headers, previewEntries, codeTrees = []) {
163
+ const hasCode = codeTrees.length > 0;
164
+ const lines = [`import { bobe, Store } from 'bobe';`];
165
+ if (hasCode) {
166
+ lines.push(`import Code from 'bobe-dom/plugin-markdown/code';`);
167
+ previewEntries.forEach((src, i) => {
168
+ lines.push(`import $Bobe_Comp_${i} from '${src}';`);
169
+ });
170
+ }
171
+ lines.push(`const mdHtml = \`${esc(html)}\`;`);
172
+ if (hasCode) {
173
+ for (let i = 0; i < codeTrees.length; i++) {
174
+ lines.push(`const codeTree${i} = ${JSON.stringify(codeTrees[i])};`);
175
+ }
176
+ }
177
+ lines.push(`class Markdown extends Store {`);
178
+ lines.push(` mdRef = null;`);
179
+ lines.push(` ui = bobe\``);
180
+ if (hasCode) {
181
+ for (let i = 0; i < codeTrees.length; i++) {
182
+ lines.push(` tp node={mdRef?.querySelector?.('#code-${i}')}`);
183
+ const previewProp = previewEntries[i] ? ` preview=\${() => $Bobe_Comp_${i}}` : '';
184
+ lines.push(` \${Code} files=\${codeTree${i}} ${previewProp}`);
185
+ }
186
+ }
187
+ lines.push(` div class="markdown" style="display: flex;"`);
188
+ lines.push(` main ref={mdRef} class="markdown-body" style="overflow-y: auto;" html=\${mdHtml}`);
189
+ lines.push(` if showAside`);
190
+ lines.push(` div class="markdown-aside" style="flex: none; display: flex; flex-direction: column; overflow-y: auto;"`);
191
+ for (const _ref of headers) {
192
+ const depth = _ref.depth;
193
+ const id = _ref.id;
194
+ const text = _ref.text;
195
+ lines.push(` a href="#${id}" text="${esc(text)}" class="markdown-aside-item markdown-aside-depth-${depth}"`);
196
+ }
197
+ lines.push(` \`;`);
198
+ lines.push(`}`);
199
+ lines.push(`export default Markdown;`);
200
+ return lines.join('\n');
201
+ }
202
+ const CODE_TAG_RE = /<code\s+src="([^"]+)"(\s+preview)?\s*\/>/g;
203
+ function markdownPlugin(opt = {}) {
204
+ let headers = [];
205
+ const headClassMap = {
206
+ '1': 'cyber-title'
207
+ };
208
+ return {
209
+ name: 'bobe-markdown',
210
+ enforce: 'pre',
211
+ configResolved() {
212
+ registerBobeLang();
213
+ marked.marked.use({
214
+ gfm: true,
215
+ renderer: {
216
+ heading({
217
+ tokens,
218
+ depth
219
+ }) {
220
+ const text = this.parser.parseInline(tokens);
221
+ const id = text.toLowerCase().replace(/[^\w一-鿿]+/g, '-');
222
+ if (depth <= (opt.asideDeep || 3)) {
223
+ headers.push({
224
+ depth,
225
+ id,
226
+ text
227
+ });
228
+ }
229
+ return `<h${depth} class="${headClassMap[depth]}" data-text="${text}" id="${id}">${text}</h${depth}>`;
230
+ },
231
+ code({
232
+ text,
233
+ lang
234
+ }) {
235
+ return `<pre><code class="hljs">${hljs.highlight(text, {
236
+ language: lang
237
+ }).value}</code></pre>`;
238
+ }
239
+ }
240
+ });
241
+ if (opt.marked) marked.marked.use(opt.marked);
242
+ },
243
+ async transform(code, id) {
244
+ if (!id.match(/\.mdx?$/)) return;
245
+ headers = [];
246
+ try {
247
+ const html = marked.marked.parse(code);
248
+ const codeTags = [];
249
+ const previewEntries = [];
250
+ let idx = 0;
251
+ const finalHtml = html.replace(CODE_TAG_RE, (_, src, preview) => {
252
+ codeTags.push(src);
253
+ if (preview) {
254
+ previewEntries[idx] = src;
255
+ }
256
+ return `<div id="code-${idx++}"></div>`;
257
+ });
258
+ const fileDir = path.dirname(id);
259
+ const codeTrees = await Promise.all(codeTags.map(tag => resolveImportTree(path.resolve(fileDir, tag), id, this.resolve.bind(this))));
260
+ return {
261
+ code: gen(finalHtml, headers, previewEntries, codeTrees),
262
+ moduleSideEffects: false
263
+ };
264
+ } catch (e) {
265
+ this.error(`[bobe-markdown] 解析失败: ${id}\n${e.message}`);
266
+ }
267
+ }
268
+ };
269
+ }
270
+
271
+ module.exports = markdownPlugin;
272
+ //# sourceMappingURL=markdown.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.cjs.js","sources":["../src/plugins/markdown/my-resolve.ts","../src/plugins/markdown/components/bobe-lang.ts","../src/plugins/markdown/index.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport hljs from 'highlight.js';\nfunction highlight(code: string, lang: string): string {\n try {\n return hljs.highlight(code, { language: lang }).value;\n } catch {\n return code.replace(/</g, '&lt;').replace(/>/g, '&gt;');\n }\n}\n\ntype ResolveFn = (id: string, importer?: string) => Promise<{ id: string } | null>;\nexport type FileItem = {\n path: string;\n name: string;\n lang: string;\n html: string;\n};\nexport async function resolveImportTree(\n importPath: string,\n currentPath: string,\n vResolve: ResolveFn,\n walked = new Set<string>()\n): Promise<FileItem[]> {\n const resolved = await vResolve(importPath, currentPath);\n const absPath = resolved?.id;\n\n if (!absPath || absPath.includes('node_modules') || absPath.startsWith('\\0') || walked.has(absPath)) {\n return [];\n }\n\n walked.add(absPath);\n\n let content = '';\n try {\n content = await fs.promises.readFile(absPath, 'utf-8');\n } catch (error) {\n console.warn(`Failed to read file: ${absPath}`);\n }\n if (!content) {\n return [];\n }\n\n const langMap: Record<string, string> = {\n ts: 'typescript',\n tsx: 'typescript',\n mts: 'typescript',\n js: 'javascript',\n jsx: 'javascript',\n mjs: 'javascript',\n css: 'css',\n html: 'xml',\n json: 'json'\n };\n const ext = path.extname(absPath).slice(1);\n const lang = langMap[ext];\n\n const item: FileItem = {\n path: absPath,\n name: path.basename(absPath),\n lang: lang,\n // html: highlight(content, lang)\n html: lang ? highlight(content, lang) : content\n };\n\n // 4. 正则匹配出文件中的静态 import 语句\n const importRegex = /import\\s+(?:[\\w*\\s{},]*\\s+from\\s+)?['\"]([^'\"]+)['\"]/g;\n let match: RegExpExecArray | null;\n const dependencies: Promise<FileItem[]>[] = [];\n\n while ((match = importRegex.exec(content)) !== null) {\n const importPath = match[1];\n // 排除绝对路径网络请求(如 https://)\n if (!importPath.startsWith('http')) {\n dependencies.push(resolveImportTree(importPath, absPath, vResolve, walked));\n }\n }\n if (!dependencies.length) {\n return [item];\n }\n const deps = await Promise.all(dependencies);\n return [item, ...deps.flat()];\n}\n","import hljs, { Language } from 'highlight.js';\n\n/**\n * 注册 bobe DSL 语法高亮。\n *\n * 1. 注册 `bobe` 独立语言(用于 markdown 中 ```bobe 代码块)\n * 2. 给 JavaScript grammar 打补丁,让 `bobe`...`` 标签模板被 TS/JS 代码块自动识别\n *\n * bobe 采用类似 Pug 的缩进风格,语法要素:\n * - 元素标签:div, span, h1-h6, a, p, ul, li, button, input ...\n * - 属性:class=\"...\", id=\"...\", text=\"...\", onclick={...}, ref={...}\n * - 控制流:if, else, for, tp\n * - 响应式绑定:{expr}\n * - 模板插值:${expr}\n * - 字符串:\"hello\"\n * - 注释:# comment\n */\nexport function registerBobeLang() {\n // ================================================================\n // Part 1: 注册 bobe 独立语言\n // ================================================================\n hljs.registerLanguage('bobe', (hljs) => {\n // 属性名列表(含事件处理器和布尔属性)\n const ATTRS = [\n 'class', 'id', 'text', 'html', 'style', 'href', 'src', 'alt', 'title',\n 'ref', 'type', 'placeholder', 'value', 'name', 'foo',\n 'disabled', 'readonly', 'checked', 'selected', 'hidden',\n 'role', 'target', 'rel', 'width', 'height', 'tabindex',\n 'data-[\\\\w-]+', 'aria-[\\\\w-]+',\n 'onclick', 'oninput', 'onchange', 'onsubmit', 'onreset',\n 'onkeydown', 'onkeyup', 'onkeypress',\n 'onfocus', 'onblur', 'onmouseenter', 'onmouseleave',\n 'onmousemove', 'onmouseover', 'onmouseout',\n 'onload', 'onerror', 'onscroll', 'onresize',\n 'ondrag', 'ondragstart', 'ondragend', 'ondragover', 'ondrop',\n 'ontouchstart', 'ontouchend', 'ontouchmove',\n ].join('|');\n\n return {\n name: 'bobe',\n // keywords: {\n // $pattern: /\\b(if|else|for|tp)\\b/,\n // keyword: 'if else for tp'\n // },\n keywords: ['if','else','for','tp','context'],\n contains: [\n // ----------------------------------------------------------\n // 1. 行注释 — # 到行尾\n // ----------------------------------------------------------\n hljs.COMMENT('#', '$', { relevance: 0 }),\n\n // ----------------------------------------------------------\n // 2. 模板插值 ${expr} — bobe 组件/表达式嵌入\n // ----------------------------------------------------------\n {\n className: 'template-substitution',\n begin: /\\$\\{/,\n end: /\\}/,\n contains: [\n { begin: /\\$\\{/, end: /\\}/, skip: true },\n ],\n subLanguage: 'javascript',\n },\n\n // ----------------------------------------------------------\n // 3. 响应式绑定 {expr} — 跟在 = 后面(不含 $)\n // ----------------------------------------------------------\n {\n className: 'template-substitution',\n begin: /(?<==)\\{/,\n end: /\\}/,\n contains: [\n { begin: /\\{/, end: /\\}/, skip: true },\n ],\n subLanguage: 'javascript',\n },\n\n // ----------------------------------------------------------\n // 4. 双引号字符串 — 内部可含 ${} 插值\n // ----------------------------------------------------------\n {\n className: 'string',\n begin: /\"/,\n end: /\"/,\n contains: [\n {\n begin: /\\$\\{/,\n end: /\\}/,\n subLanguage: 'javascript',\n }\n ]\n },\n\n // ----------------------------------------------------------\n // 5. 元素标签 — 行首缩进后的第一个标识符(排除关键字)\n // 泛化匹配:bobe 缩进语法中每行首个标识符必是标签或关键字\n // ----------------------------------------------------------\n {\n className: 'selector-tag',\n begin: /^[ \\t]*(?!(?:if|else|for|tp)\\b)[a-z][\\w-]*(?:-[a-z][\\w-]*)*\\b/m,\n relevance: 2,\n },\n\n // ----------------------------------------------------------\n // 6. 属性名 — key=value 形式\n // ----------------------------------------------------------\n {\n className: 'attr',\n begin: new RegExp(`\\\\b(?:${ATTRS})\\\\b(?=\\\\s*=)`),\n relevance: 1,\n },\n\n // ----------------------------------------------------------\n // 7. 布尔属性 — 独立出现,不跟 =\n // ----------------------------------------------------------\n {\n className: 'attr',\n begin: /\\b(?:disabled|readonly|checked|selected|hidden)\\b(?!\\s*=)/,\n relevance: 0,\n },\n\n // ----------------------------------------------------------\n // 8. for 循环变量 — for items; item i\n // ----------------------------------------------------------\n {\n className: 'variable',\n begin: /(?<=for\\s+)\\w+(?=\\s*;)/,\n relevance: 0,\n },\n {\n className: 'params',\n begin: /(?<=for\\s+\\S+\\s*;\\s*)\\w+/,\n relevance: 0,\n },\n {\n className: 'params',\n begin: /(?<=for\\s+\\S+\\s*;\\s*\\w+\\s+)\\w+/,\n relevance: 0,\n },\n\n // ----------------------------------------------------------\n // 9. 数字字面量\n // ----------------------------------------------------------\n hljs.NUMBER_MODE,\n ]\n } as Language;\n });\n\n // ================================================================\n // Part 2: 给 JS-family grammars 打补丁,让 `bobe`...`` 标签模板被识别\n // ================================================================\n function patchJsFamily(name: string) {\n const fn = (hljs.getLanguage(name) as any)?.rawDefinition as\n | ((hljs: any) => any)\n | undefined;\n if (!fn) return;\n\n const def = fn(hljs);\n\n // 避免重复注册\n if (def.contains.some((c: any) =>\n c.begin?.toString?.().includes('bobe')\n )) return;\n\n // 复刻该 grammar 的 keywords(用于 SUBST 中的 JS 表达式高亮)\n const SUBST = {\n className: 'subst',\n begin: /\\$\\{/,\n end: /\\}/,\n keywords: def.keywords,\n };\n\n def.contains.push({\n begin: /\\.?bobe`/, // 匹配 bobe` 或 .bobe`\n end: '',\n starts: {\n end: '`',\n returnEnd: false,\n contains: [hljs.BACKSLASH_ESCAPE, SUBST],\n subLanguage: 'bobe',\n },\n });\n\n hljs.registerLanguage(name, () => def);\n }\n\n patchJsFamily('javascript');\n patchJsFamily('typescript');\n}\n","import type { Plugin } from 'vite';\nimport type { MarkedExtension } from 'marked';\nimport { marked } from 'marked';\nimport { resolve, dirname } from 'path';\nimport { FileItem, resolveImportTree } from './my-resolve';\nimport hljs from 'highlight.js';\nimport { registerBobeLang } from './components/bobe-lang';\n\nexport interface MarkdownPluginOptions {\n /** 传递给 marked.use() 的扩展配置 */\n marked?: MarkedExtension;\n /** 侧边栏的深度,默认为 3,表示提取 h1 - h3 到侧边栏做导航 */\n asideDeep?: number;\n}\n\n/** 对要嵌入模板字面量的字符串进行转义(` $ \\) */\nfunction esc(s: string): string {\n return s.replace(/\\\\/g, '\\\\\\\\').replace(/`/g, '\\\\`').replace(/\\$/g, '\\\\$');\n}\n\n/** 将 HTML 字符串编译为 bobe 组件模块源码 */\nfunction gen(html: string, headers: HeadItem[], previewEntries: string[], codeTrees: FileItem[][] = []): string {\n const hasCode = codeTrees.length > 0;\n const lines = [`import { bobe, Store } from 'bobe';`];\n\n if (hasCode) {\n lines.push(`import Code from 'bobe-dom/plugin-markdown/code';`);\n previewEntries.forEach((src, i) => {\n lines.push(`import $Bobe_Comp_${i} from '${src}';`);\n });\n }\n\n lines.push(`const mdHtml = \\`${esc(html)}\\`;`);\n\n // 代码树数据\n if (hasCode) {\n for (let i = 0; i < codeTrees.length; i++) {\n lines.push(`const codeTree${i} = ${JSON.stringify(codeTrees[i])};`);\n }\n }\n\n // Markdown Store 组件\n lines.push(`class Markdown extends Store {`);\n lines.push(` mdRef = null;`);\n lines.push(` ui = bobe\\``);\n // tp + Code 组件\n if (hasCode) {\n for (let i = 0; i < codeTrees.length; i++) {\n lines.push(` tp node={mdRef?.querySelector?.('#code-${i}')}`);\n const previewProp = previewEntries[i] ? ` preview=\\${() => $Bobe_Comp_${i}}` : '';\n lines.push(` \\${Code} files=\\${codeTree${i}} ${previewProp}`);\n }\n }\n lines.push(` div class=\"markdown\" style=\"display: flex;\"`);\n lines.push(` main ref={mdRef} class=\"markdown-body\" style=\"overflow-y: auto;\" html=\\${mdHtml}`);\n lines.push(` if showAside`);\n lines.push(\n ` div class=\"markdown-aside\" style=\"flex: none; display: flex; flex-direction: column; overflow-y: auto;\"`\n );\n for (const { depth, id, text } of headers) {\n lines.push(\n ` a href=\"#${id}\" text=\"${esc(text)}\" class=\"markdown-aside-item markdown-aside-depth-${depth}\"`\n );\n }\n\n lines.push(` \\`;`);\n lines.push(`}`);\n lines.push(`export default Markdown;`);\n return lines.join('\\n');\n}\n\n/**\n * bobe-markdown Vite 插件。\n *\n * 将 .md / .mdx 文件编译为 bobe 组件:\n * import Readme from './README.md';\n *\n * 支持 <code src=\"xxx.ts\" /> 引入代码文件及 import 树(非 node_modules),\n * 以 Code 组件 + tp 传送方式渲染。\n */\n\nexport type HeadItem = {\n depth: number;\n id: string;\n text: string;\n};\n\nconst CODE_TAG_RE = /<code\\s+src=\"([^\"]+)\"(\\s+preview)?\\s*\\/>/g;\n\nexport default function markdownPlugin(opt: MarkdownPluginOptions = {}): Plugin {\n let headers: HeadItem[] = [];\n const headClassMap = {\n '1': 'cyber-title'\n }\n return {\n name: 'bobe-markdown',\n enforce: 'pre',\n\n configResolved() {\n registerBobeLang(); // 注册 bobe DSL 语法高亮(支持 markdown 中的 ```bobe 代码块)\n marked.use({\n gfm: true, // GitHub Flavored Markdown\n renderer: {\n heading({ tokens, depth }) {\n const text = this.parser.parseInline(tokens);\n const id = text.toLowerCase().replace(/[^\\w一-鿿]+/g, '-');\n if (depth <= (opt.asideDeep || 3)) {\n headers.push({ depth, id, text });\n }\n return `<h${depth} class=\"${headClassMap[depth]}\" data-text=\"${text}\" id=\"${id}\">${text}</h${depth}>`;\n },\n code({ text, lang }) {\n return `<pre><code class=\"hljs\">${hljs.highlight(text, { language: lang }).value}</code></pre>`;\n }\n }\n });\n if (opt.marked) marked.use(opt.marked);\n },\n\n async transform(code, id) {\n if (!id.match(/\\.mdx?$/)) return;\n headers = [];\n try {\n const html = marked.parse(code) as string;\n\n // 匹配 <code src=\"xxx.ts\"> → <div id=\"code-N\">\n const codeTags: string[] = [];\n const previewEntries: string[] = [];\n let idx = 0;\n const finalHtml = html.replace(CODE_TAG_RE, (_, src, preview) => {\n codeTags.push(src);\n if (preview) {\n previewEntries[idx] = src;\n }\n return `<div id=\"code-${idx++}\"></div>`;\n });\n\n // 解析每个 code block 的 import 树\n const fileDir = dirname(id);\n const codeTrees = await Promise.all(\n codeTags.map(tag => resolveImportTree(resolve(fileDir, tag), id, this.resolve.bind(this)))\n );\n\n return { code: gen(finalHtml, headers, previewEntries, codeTrees), moduleSideEffects: false };\n } catch (e: any) {\n this.error(`[bobe-markdown] 解析失败: ${id}\\n${e.message}`);\n }\n }\n };\n}\n"],"names":["highlight","code","lang","hljs","language","value","replace","resolveImportTree","importPath","currentPath","vResolve","walked","Set","resolved","absPath","id","includes","startsWith","has","add","content","fs","promises","readFile","error","console","warn","langMap","ts","tsx","mts","js","jsx","mjs","css","html","json","ext","path","extname","slice","item","name","basename","importRegex","match","dependencies","exec","push","length","deps","Promise","all","flat","registerBobeLang","registerLanguage","ATTRS","join","keywords","contains","COMMENT","relevance","className","begin","end","skip","subLanguage","RegExp","NUMBER_MODE","patchJsFamily","fn","getLanguage","rawDefinition","def","some","c","toString","SUBST","starts","returnEnd","BACKSLASH_ESCAPE","esc","s","gen","headers","previewEntries","codeTrees","hasCode","lines","forEach","src","i","JSON","stringify","previewProp","_ref","depth","text","CODE_TAG_RE","markdownPlugin","opt","headClassMap","enforce","configResolved","marked","use","gfm","renderer","heading","tokens","parser","parseInline","toLowerCase","asideDeep","transform","parse","codeTags","idx","finalHtml","_","preview","fileDir","dirname","map","tag","resolve","bind","moduleSideEffects","e","message"],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { Plugin } from 'vite';
2
+ import { MarkedExtension } from 'marked';
3
+
4
+ interface MarkdownPluginOptions {
5
+ /** 传递给 marked.use() 的扩展配置 */
6
+ marked?: MarkedExtension;
7
+ /** 侧边栏的深度,默认为 3,表示提取 h1 - h3 到侧边栏做导航 */
8
+ asideDeep?: number;
9
+ }
10
+ /**
11
+ * bobe-markdown Vite 插件。
12
+ *
13
+ * 将 .md / .mdx 文件编译为 bobe 组件:
14
+ * import Readme from './README.md';
15
+ *
16
+ * 支持 <code src="xxx.ts" /> 引入代码文件及 import 树(非 node_modules),
17
+ * 以 Code 组件 + tp 传送方式渲染。
18
+ */
19
+ type HeadItem = {
20
+ depth: number;
21
+ id: string;
22
+ text: string;
23
+ };
24
+ declare function markdownPlugin(opt?: MarkdownPluginOptions): Plugin;
25
+
26
+ export { markdownPlugin as default };
27
+ export type { HeadItem, MarkdownPluginOptions };
@@ -0,0 +1,270 @@
1
+ import { marked } from 'marked';
2
+ import path, { dirname, resolve } from 'path';
3
+ import fs from 'fs';
4
+ import hljs from 'highlight.js';
5
+
6
+ function highlight(code, lang) {
7
+ try {
8
+ return hljs.highlight(code, {
9
+ language: lang
10
+ }).value;
11
+ } catch {
12
+ return code.replace(/</g, '&lt;').replace(/>/g, '&gt;');
13
+ }
14
+ }
15
+ async function resolveImportTree(importPath, currentPath, vResolve, walked = new Set()) {
16
+ const resolved = await vResolve(importPath, currentPath);
17
+ const absPath = resolved?.id;
18
+ if (!absPath || absPath.includes('node_modules') || absPath.startsWith('\0') || walked.has(absPath)) {
19
+ return [];
20
+ }
21
+ walked.add(absPath);
22
+ let content = '';
23
+ try {
24
+ content = await fs.promises.readFile(absPath, 'utf-8');
25
+ } catch (error) {
26
+ console.warn(`Failed to read file: ${absPath}`);
27
+ }
28
+ if (!content) {
29
+ return [];
30
+ }
31
+ const langMap = {
32
+ ts: 'typescript',
33
+ tsx: 'typescript',
34
+ mts: 'typescript',
35
+ js: 'javascript',
36
+ jsx: 'javascript',
37
+ mjs: 'javascript',
38
+ css: 'css',
39
+ html: 'xml',
40
+ json: 'json'
41
+ };
42
+ const ext = path.extname(absPath).slice(1);
43
+ const lang = langMap[ext];
44
+ const item = {
45
+ path: absPath,
46
+ name: path.basename(absPath),
47
+ lang: lang,
48
+ html: lang ? highlight(content, lang) : content
49
+ };
50
+ const importRegex = /import\s+(?:[\w*\s{},]*\s+from\s+)?['"]([^'"]+)['"]/g;
51
+ let match;
52
+ const dependencies = [];
53
+ while ((match = importRegex.exec(content)) !== null) {
54
+ const importPath = match[1];
55
+ if (!importPath.startsWith('http')) {
56
+ dependencies.push(resolveImportTree(importPath, absPath, vResolve, walked));
57
+ }
58
+ }
59
+ if (!dependencies.length) {
60
+ return [item];
61
+ }
62
+ const deps = await Promise.all(dependencies);
63
+ return [item, ...deps.flat()];
64
+ }
65
+
66
+ function registerBobeLang() {
67
+ hljs.registerLanguage('bobe', hljs => {
68
+ const ATTRS = ['class', 'id', 'text', 'html', 'style', 'href', 'src', 'alt', 'title', 'ref', 'type', 'placeholder', 'value', 'name', 'foo', 'disabled', 'readonly', 'checked', 'selected', 'hidden', 'role', 'target', 'rel', 'width', 'height', 'tabindex', 'data-[\\w-]+', 'aria-[\\w-]+', 'onclick', 'oninput', 'onchange', 'onsubmit', 'onreset', 'onkeydown', 'onkeyup', 'onkeypress', 'onfocus', 'onblur', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseover', 'onmouseout', 'onload', 'onerror', 'onscroll', 'onresize', 'ondrag', 'ondragstart', 'ondragend', 'ondragover', 'ondrop', 'ontouchstart', 'ontouchend', 'ontouchmove'].join('|');
69
+ return {
70
+ name: 'bobe',
71
+ keywords: ['if', 'else', 'for', 'tp', 'context'],
72
+ contains: [hljs.COMMENT('#', '$', {
73
+ relevance: 0
74
+ }), {
75
+ className: 'template-substitution',
76
+ begin: /\$\{/,
77
+ end: /\}/,
78
+ contains: [{
79
+ begin: /\$\{/,
80
+ end: /\}/,
81
+ skip: true
82
+ }],
83
+ subLanguage: 'javascript'
84
+ }, {
85
+ className: 'template-substitution',
86
+ begin: /(?<==)\{/,
87
+ end: /\}/,
88
+ contains: [{
89
+ begin: /\{/,
90
+ end: /\}/,
91
+ skip: true
92
+ }],
93
+ subLanguage: 'javascript'
94
+ }, {
95
+ className: 'string',
96
+ begin: /"/,
97
+ end: /"/,
98
+ contains: [{
99
+ begin: /\$\{/,
100
+ end: /\}/,
101
+ subLanguage: 'javascript'
102
+ }]
103
+ }, {
104
+ className: 'selector-tag',
105
+ begin: /^[ \t]*(?!(?:if|else|for|tp)\b)[a-z][\w-]*(?:-[a-z][\w-]*)*\b/m,
106
+ relevance: 2
107
+ }, {
108
+ className: 'attr',
109
+ begin: new RegExp(`\\b(?:${ATTRS})\\b(?=\\s*=)`),
110
+ relevance: 1
111
+ }, {
112
+ className: 'attr',
113
+ begin: /\b(?:disabled|readonly|checked|selected|hidden)\b(?!\s*=)/,
114
+ relevance: 0
115
+ }, {
116
+ className: 'variable',
117
+ begin: /(?<=for\s+)\w+(?=\s*;)/,
118
+ relevance: 0
119
+ }, {
120
+ className: 'params',
121
+ begin: /(?<=for\s+\S+\s*;\s*)\w+/,
122
+ relevance: 0
123
+ }, {
124
+ className: 'params',
125
+ begin: /(?<=for\s+\S+\s*;\s*\w+\s+)\w+/,
126
+ relevance: 0
127
+ }, hljs.NUMBER_MODE]
128
+ };
129
+ });
130
+ function patchJsFamily(name) {
131
+ const fn = hljs.getLanguage(name)?.rawDefinition;
132
+ if (!fn) return;
133
+ const def = fn(hljs);
134
+ if (def.contains.some(c => c.begin?.toString?.().includes('bobe'))) return;
135
+ const SUBST = {
136
+ className: 'subst',
137
+ begin: /\$\{/,
138
+ end: /\}/,
139
+ keywords: def.keywords
140
+ };
141
+ def.contains.push({
142
+ begin: /\.?bobe`/,
143
+ end: '',
144
+ starts: {
145
+ end: '`',
146
+ returnEnd: false,
147
+ contains: [hljs.BACKSLASH_ESCAPE, SUBST],
148
+ subLanguage: 'bobe'
149
+ }
150
+ });
151
+ hljs.registerLanguage(name, () => def);
152
+ }
153
+ patchJsFamily('javascript');
154
+ patchJsFamily('typescript');
155
+ }
156
+
157
+ function esc(s) {
158
+ return s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$');
159
+ }
160
+ function gen(html, headers, previewEntries, codeTrees = []) {
161
+ const hasCode = codeTrees.length > 0;
162
+ const lines = [`import { bobe, Store } from 'bobe';`];
163
+ if (hasCode) {
164
+ lines.push(`import Code from 'bobe-dom/plugin-markdown/code';`);
165
+ previewEntries.forEach((src, i) => {
166
+ lines.push(`import $Bobe_Comp_${i} from '${src}';`);
167
+ });
168
+ }
169
+ lines.push(`const mdHtml = \`${esc(html)}\`;`);
170
+ if (hasCode) {
171
+ for (let i = 0; i < codeTrees.length; i++) {
172
+ lines.push(`const codeTree${i} = ${JSON.stringify(codeTrees[i])};`);
173
+ }
174
+ }
175
+ lines.push(`class Markdown extends Store {`);
176
+ lines.push(` mdRef = null;`);
177
+ lines.push(` ui = bobe\``);
178
+ if (hasCode) {
179
+ for (let i = 0; i < codeTrees.length; i++) {
180
+ lines.push(` tp node={mdRef?.querySelector?.('#code-${i}')}`);
181
+ const previewProp = previewEntries[i] ? ` preview=\${() => $Bobe_Comp_${i}}` : '';
182
+ lines.push(` \${Code} files=\${codeTree${i}} ${previewProp}`);
183
+ }
184
+ }
185
+ lines.push(` div class="markdown" style="display: flex;"`);
186
+ lines.push(` main ref={mdRef} class="markdown-body" style="overflow-y: auto;" html=\${mdHtml}`);
187
+ lines.push(` if showAside`);
188
+ lines.push(` div class="markdown-aside" style="flex: none; display: flex; flex-direction: column; overflow-y: auto;"`);
189
+ for (const _ref of headers) {
190
+ const depth = _ref.depth;
191
+ const id = _ref.id;
192
+ const text = _ref.text;
193
+ lines.push(` a href="#${id}" text="${esc(text)}" class="markdown-aside-item markdown-aside-depth-${depth}"`);
194
+ }
195
+ lines.push(` \`;`);
196
+ lines.push(`}`);
197
+ lines.push(`export default Markdown;`);
198
+ return lines.join('\n');
199
+ }
200
+ const CODE_TAG_RE = /<code\s+src="([^"]+)"(\s+preview)?\s*\/>/g;
201
+ function markdownPlugin(opt = {}) {
202
+ let headers = [];
203
+ const headClassMap = {
204
+ '1': 'cyber-title'
205
+ };
206
+ return {
207
+ name: 'bobe-markdown',
208
+ enforce: 'pre',
209
+ configResolved() {
210
+ registerBobeLang();
211
+ marked.use({
212
+ gfm: true,
213
+ renderer: {
214
+ heading({
215
+ tokens,
216
+ depth
217
+ }) {
218
+ const text = this.parser.parseInline(tokens);
219
+ const id = text.toLowerCase().replace(/[^\w一-鿿]+/g, '-');
220
+ if (depth <= (opt.asideDeep || 3)) {
221
+ headers.push({
222
+ depth,
223
+ id,
224
+ text
225
+ });
226
+ }
227
+ return `<h${depth} class="${headClassMap[depth]}" data-text="${text}" id="${id}">${text}</h${depth}>`;
228
+ },
229
+ code({
230
+ text,
231
+ lang
232
+ }) {
233
+ return `<pre><code class="hljs">${hljs.highlight(text, {
234
+ language: lang
235
+ }).value}</code></pre>`;
236
+ }
237
+ }
238
+ });
239
+ if (opt.marked) marked.use(opt.marked);
240
+ },
241
+ async transform(code, id) {
242
+ if (!id.match(/\.mdx?$/)) return;
243
+ headers = [];
244
+ try {
245
+ const html = marked.parse(code);
246
+ const codeTags = [];
247
+ const previewEntries = [];
248
+ let idx = 0;
249
+ const finalHtml = html.replace(CODE_TAG_RE, (_, src, preview) => {
250
+ codeTags.push(src);
251
+ if (preview) {
252
+ previewEntries[idx] = src;
253
+ }
254
+ return `<div id="code-${idx++}"></div>`;
255
+ });
256
+ const fileDir = dirname(id);
257
+ const codeTrees = await Promise.all(codeTags.map(tag => resolveImportTree(resolve(fileDir, tag), id, this.resolve.bind(this))));
258
+ return {
259
+ code: gen(finalHtml, headers, previewEntries, codeTrees),
260
+ moduleSideEffects: false
261
+ };
262
+ } catch (e) {
263
+ this.error(`[bobe-markdown] 解析失败: ${id}\n${e.message}`);
264
+ }
265
+ }
266
+ };
267
+ }
268
+
269
+ export { markdownPlugin as default };
270
+ //# sourceMappingURL=markdown.esm.js.map