bobe-dom 0.0.61 → 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,43 @@
1
+ 'use strict';
2
+
3
+ var bobe = require('bobe');
4
+
5
+ class Code extends bobe.Store {
6
+ activeIndex = 0;
7
+ files = [];
8
+ switchTab(i) {
9
+ this.activeIndex = i;
10
+ }
11
+ get activeFile() {
12
+ return this.files[this.activeIndex];
13
+ }
14
+ preview = null;
15
+ normalBlock = null;
16
+ fullBlock = null;
17
+ isFull = false;
18
+ toggleFull = () => {
19
+ this.isFull = !this.isFull;
20
+ console.log('isFull', this.isFull);
21
+ };
22
+ get blockTarget() {
23
+ return this.isFull ? this.fullBlock : this.normalBlock;
24
+ }
25
+ ui = bobe.bobe`
26
+ tp node={blockTarget}
27
+ div class="code-tabs"
28
+ button class="full-button" onclick={toggleFull} text={isFull ? '收起' : '全屏'}
29
+ for files; file i; file.path
30
+ button class={activeIndex === i ? 'code-tab code-tab-active' : 'code-tab'} onclick={() => switchTab(i)} text={file.name}
31
+ div ref={normalPreview} class="code-panel-preview"
32
+ pre class="code-panel"
33
+ code class="hljs" html={activeFile.html}
34
+ if preview
35
+ div class="code-preview"
36
+ {preview}
37
+ div ref={normalBlock} class="code-block"
38
+ div ref={fullBlock} class={isFull ? "code-block-full code-block-full-active" : "code-block-full"}
39
+ `;
40
+ }
41
+
42
+ module.exports = Code;
43
+ //# sourceMappingURL=code.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code.cjs.js","sources":["../src/plugins/markdown/components/code.ts"],"sourcesContent":["import { bobe, Store } from 'bobe';\nimport './code.css';\nimport './markdown.css';\nimport './tokyo-night-dark.css';\n\n\nclass Code extends Store {\n activeIndex = 0;\n files: Array<{ name: string; html: string }> = [];\n\n switchTab(i: number) { this.activeIndex = i }\n\n get activeFile() { return this.files[this.activeIndex]; }\n preview = null;\n\n normalBlock = null;\n fullBlock = null;\n\n isFull = false;\n\n toggleFull = () => {\n this.isFull = !this.isFull;\n console.log('isFull', this.isFull);\n \n }\n\n get blockTarget() {\n return this.isFull ? this.fullBlock : this.normalBlock;\n }\n\n ui = bobe`\n tp node={blockTarget} \n div class=\"code-tabs\"\n button class=\"full-button\" onclick={toggleFull} text={isFull ? '收起' : '全屏'}\n for files; file i; file.path\n button class={activeIndex === i ? 'code-tab code-tab-active' : 'code-tab'} onclick={() => switchTab(i)} text={file.name}\n div ref={normalPreview} class=\"code-panel-preview\"\n pre class=\"code-panel\" \n code class=\"hljs\" html={activeFile.html}\n if preview \n div class=\"code-preview\"\n {preview} \n div ref={normalBlock} class=\"code-block\"\n div ref={fullBlock} class={isFull ? \"code-block-full code-block-full-active\" : \"code-block-full\"} \n `;\n}\n\nexport default Code;\n"],"names":["Code","Store","activeIndex","files","switchTab","i","activeFile","preview","normalBlock","fullBlock","isFull","toggleFull","console","log","blockTarget","ui","bobe"],"mappings":";;;;AAMA,MAAMA,IAAI,SAASC,UAAK,CAAC;AACvBC,EAAAA,WAAW,GAAG,CAAC;AACfC,EAAAA,KAAK,GAA0C,EAAE;EAEjDC,SAASA,CAACC,CAAS,EAAE;IAAE,IAAI,CAACH,WAAW,GAAGG,CAAC;AAAC,EAAA;EAE5C,IAAIC,UAAUA,GAAG;AAAE,IAAA,OAAO,IAAI,CAACH,KAAK,CAAC,IAAI,CAACD,WAAW,CAAC;AAAE,EAAA;AACxDK,EAAAA,OAAO,GAAG,IAAI;AAEdC,EAAAA,WAAW,GAAG,IAAI;AAClBC,EAAAA,SAAS,GAAG,IAAI;AAEhBC,EAAAA,MAAM,GAAG,KAAK;EAEdC,UAAU,GAAGA,MAAM;AACjB,IAAA,IAAI,CAACD,MAAM,GAAG,CAAC,IAAI,CAACA,MAAM;IAC1BE,OAAO,CAACC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAACH,MAAM,CAAC;EAEpC,CAAC;EAED,IAAII,WAAWA,GAAG;IAChB,OAAO,IAAI,CAACJ,MAAM,GAAG,IAAI,CAACD,SAAS,GAAG,IAAI,CAACD,WAAW;AACxD,EAAA;AAEAO,EAAAA,EAAE,GAAGC,SAAI;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA,CAAG;AACH;;;;"}
package/dist/code.css ADDED
@@ -0,0 +1,107 @@
1
+ .code-block {
2
+ border: 1px solid var(--md-border, #3c3f47);
3
+ border-radius: 6px;
4
+ overflow: hidden;
5
+ margin: 16px 0;
6
+ height: 700px;
7
+ display: flex;
8
+ flex-direction: column;
9
+ background: var(--md-bg, #1b1b1f);
10
+ }
11
+
12
+ .code-block-full {
13
+ left: 0;
14
+ top: 0;
15
+ height: 100vh;
16
+ width: 100vw;
17
+ position: fixed;
18
+ z-index: 9999;
19
+ opacity: 0;
20
+ pointer-events: none;
21
+ display: flex;
22
+ flex-direction: column;
23
+ background: var(--md-bg, #1b1b1f);
24
+ }
25
+
26
+ .code-block-full-active {
27
+ opacity: 1;
28
+ pointer-events: auto;
29
+ }
30
+
31
+ .code-tabs {
32
+ display: flex;
33
+ background: var(--md-bg-secondary, #22222a);
34
+ border-bottom: 1px solid var(--md-border, #3c3f47);
35
+ overflow-x: auto;
36
+ flex: 0 0 auto;
37
+ }
38
+
39
+ .code-panel-preview {
40
+ display: flex;
41
+ flex: 1 1 auto;
42
+ height: 1px;
43
+ }
44
+
45
+ .full-button {
46
+ padding: 6px 14px;
47
+ font-size: 12px;
48
+ font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
49
+ color: var(--md-text-muted, #9898a5);
50
+ background: none;
51
+ border: 0 solid var(--md-border, #3c3f47);
52
+ border-right: 1px solid var(--md-border, #3c3f47);;
53
+ border-radius: 4px 0 0 0;
54
+ cursor: pointer;
55
+ white-space: nowrap;
56
+ flex-shrink: 0;
57
+ transition: color 0.15s, border-color 0.15s;
58
+ }
59
+
60
+ .full-button:hover {
61
+ color: var(--md-accent-focus, #539bf5);
62
+ }
63
+
64
+ .code-tab {
65
+ padding: 8px 16px;
66
+ font-size: 13px;
67
+ font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
68
+ color: var(--md-text-muted, #9898a5);
69
+ background: none;
70
+ border: none;
71
+ border-bottom: 2px solid transparent;
72
+ cursor: pointer;
73
+ white-space: nowrap;
74
+ }
75
+
76
+ .code-tab:hover {
77
+ color: var(--md-text, #e1e1e5);
78
+ background: var(--md-bg-code, #282c38);
79
+ }
80
+
81
+ .code-tab-active {
82
+ color: var(--md-text, #e1e1e5);
83
+ background: var(--md-bg, #1b1b1f);
84
+ border-bottom-color: var(--md-accent-focus, #539bf5);
85
+ font-weight: 500;
86
+ }
87
+
88
+ .code-panel-preview .code-panel {
89
+ flex: 1 1 1px;
90
+ overflow: auto;
91
+ margin-bottom: 0px;
92
+ }
93
+
94
+ .code-panel code.hljs {
95
+ overflow-x: visible;
96
+ }
97
+
98
+ .code-panel pre {
99
+ margin: 0;
100
+ padding: 16px;
101
+ font-size: 13px;
102
+ line-height: 1.5;
103
+ }
104
+
105
+ .code-preview {
106
+ flex: 1 1 1px;
107
+ }
@@ -0,0 +1,41 @@
1
+ import { Store, bobe } from 'bobe';
2
+
3
+ class Code extends Store {
4
+ activeIndex = 0;
5
+ files = [];
6
+ switchTab(i) {
7
+ this.activeIndex = i;
8
+ }
9
+ get activeFile() {
10
+ return this.files[this.activeIndex];
11
+ }
12
+ preview = null;
13
+ normalBlock = null;
14
+ fullBlock = null;
15
+ isFull = false;
16
+ toggleFull = () => {
17
+ this.isFull = !this.isFull;
18
+ console.log('isFull', this.isFull);
19
+ };
20
+ get blockTarget() {
21
+ return this.isFull ? this.fullBlock : this.normalBlock;
22
+ }
23
+ ui = bobe`
24
+ tp node={blockTarget}
25
+ div class="code-tabs"
26
+ button class="full-button" onclick={toggleFull} text={isFull ? '收起' : '全屏'}
27
+ for files; file i; file.path
28
+ button class={activeIndex === i ? 'code-tab code-tab-active' : 'code-tab'} onclick={() => switchTab(i)} text={file.name}
29
+ div ref={normalPreview} class="code-panel-preview"
30
+ pre class="code-panel"
31
+ code class="hljs" html={activeFile.html}
32
+ if preview
33
+ div class="code-preview"
34
+ {preview}
35
+ div ref={normalBlock} class="code-block"
36
+ div ref={fullBlock} class={isFull ? "code-block-full code-block-full-active" : "code-block-full"}
37
+ `;
38
+ }
39
+
40
+ export { Code as default };
41
+ //# sourceMappingURL=code.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code.esm.js","sources":["../src/plugins/markdown/components/code.ts"],"sourcesContent":["import { bobe, Store } from 'bobe';\nimport './code.css';\nimport './markdown.css';\nimport './tokyo-night-dark.css';\n\n\nclass Code extends Store {\n activeIndex = 0;\n files: Array<{ name: string; html: string }> = [];\n\n switchTab(i: number) { this.activeIndex = i }\n\n get activeFile() { return this.files[this.activeIndex]; }\n preview = null;\n\n normalBlock = null;\n fullBlock = null;\n\n isFull = false;\n\n toggleFull = () => {\n this.isFull = !this.isFull;\n console.log('isFull', this.isFull);\n \n }\n\n get blockTarget() {\n return this.isFull ? this.fullBlock : this.normalBlock;\n }\n\n ui = bobe`\n tp node={blockTarget} \n div class=\"code-tabs\"\n button class=\"full-button\" onclick={toggleFull} text={isFull ? '收起' : '全屏'}\n for files; file i; file.path\n button class={activeIndex === i ? 'code-tab code-tab-active' : 'code-tab'} onclick={() => switchTab(i)} text={file.name}\n div ref={normalPreview} class=\"code-panel-preview\"\n pre class=\"code-panel\" \n code class=\"hljs\" html={activeFile.html}\n if preview \n div class=\"code-preview\"\n {preview} \n div ref={normalBlock} class=\"code-block\"\n div ref={fullBlock} class={isFull ? \"code-block-full code-block-full-active\" : \"code-block-full\"} \n `;\n}\n\nexport default Code;\n"],"names":["Code","Store","activeIndex","files","switchTab","i","activeFile","preview","normalBlock","fullBlock","isFull","toggleFull","console","log","blockTarget","ui","bobe"],"mappings":";;AAMA,MAAMA,IAAI,SAASC,KAAK,CAAC;AACvBC,EAAAA,WAAW,GAAG,CAAC;AACfC,EAAAA,KAAK,GAA0C,EAAE;EAEjDC,SAASA,CAACC,CAAS,EAAE;IAAE,IAAI,CAACH,WAAW,GAAGG,CAAC;AAAC,EAAA;EAE5C,IAAIC,UAAUA,GAAG;AAAE,IAAA,OAAO,IAAI,CAACH,KAAK,CAAC,IAAI,CAACD,WAAW,CAAC;AAAE,EAAA;AACxDK,EAAAA,OAAO,GAAG,IAAI;AAEdC,EAAAA,WAAW,GAAG,IAAI;AAClBC,EAAAA,SAAS,GAAG,IAAI;AAEhBC,EAAAA,MAAM,GAAG,KAAK;EAEdC,UAAU,GAAGA,MAAM;AACjB,IAAA,IAAI,CAACD,MAAM,GAAG,CAAC,IAAI,CAACA,MAAM;IAC1BE,OAAO,CAACC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAACH,MAAM,CAAC;EAEpC,CAAC;EAED,IAAII,WAAWA,GAAG;IAChB,OAAO,IAAI,CAACJ,MAAM,GAAG,IAAI,CAACD,SAAS,GAAG,IAAI,CAACD,WAAW;AACxD,EAAA;AAEAO,EAAAA,EAAE,GAAGC,IAAI;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA,CAAG;AACH;;;;"}
Binary file
package/dist/index.css ADDED
@@ -0,0 +1,9 @@
1
+ .code-block{border:1px solid var(--md-border,#3c3f47);border-radius:6px;height:700px;margin:16px 0;overflow:hidden}.code-block,.code-block-full{background:var(--md-bg,#1b1b1f);display:flex;flex-direction:column}.code-block-full{height:100vh;left:0;opacity:0;pointer-events:none;position:fixed;top:0;width:100vw;z-index:9999}.code-block-full-active{opacity:1;pointer-events:auto}.code-tabs{background:var(--md-bg-secondary,#22222a);border-bottom:1px solid var(--md-border,#3c3f47);display:flex;flex:0 0 auto;overflow-x:auto}.code-panel-preview{display:flex;flex:1 1 auto;height:1px}.full-button{background:none;border-right:0 solid var(--md-border,#3c3f47);border:solid var(--md-border,#3c3f47);border-radius:4px 0 0 0;border-width:0 1px 0 0;color:var(--md-text-muted,#9898a5);cursor:pointer;flex-shrink:0;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:12px;padding:6px 14px;transition:color .15s,border-color .15s;white-space:nowrap}.full-button:hover{color:var(--md-accent-focus,#539bf5)}.code-tab{background:none;border:none;border-bottom:2px solid transparent;color:var(--md-text-muted,#9898a5);cursor:pointer;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:13px;padding:8px 16px;white-space:nowrap}.code-tab:hover{background:var(--md-bg-code,#282c38);color:var(--md-text,#e1e1e5)}.code-tab-active{background:var(--md-bg,#1b1b1f);border-bottom-color:var(--md-accent-focus,#539bf5);color:var(--md-text,#e1e1e5);font-weight:500}.code-panel-preview .code-panel{flex:1 1 1px;margin-bottom:0;overflow:auto}.code-panel code.hljs{overflow-x:visible}.code-panel pre{font-size:13px;line-height:1.5;margin:0;padding:16px}.code-preview{flex:1 1 1px}:root{--md-text:#e1e1e5;--md-text-muted:#9898a5;--md-text-link:#6cb2ff;--md-bg:#1b1b1f;--md-bg-secondary:#22222a;--md-bg-code:#282c38;--md-bg-inline-code:#282c38;--md-bg-mark:#f2c94e26;--md-bg-transparent:transparent;--md-border:#3c3f47;--md-border-muted:#3c3f47b3;--md-accent-focus:#539bf5;--md-syntax-keyword:#ff7b72;--md-syntax-string:#9ecbff;--md-syntax-number:#7ac0ff;--md-syntax-function:#d2a8ff;--md-syntax-builtin:#7ee787;--md-syntax-variable:#ffa860;--md-syntax-meta:#f2cc60;--md-diff-del-text:#ffdcd7;--md-diff-del-bg:#5c1a1e;--md-diff-add-text:#aff5b4;--md-diff-add-bg:#0d3b20;--md-diff-changed-text:#ffdfb6;--md-diff-changed-bg:#5c2d0e;--md-diff-meta-bg:#1a5fb4;--md-danger-fg:#f85149;--md-danger-bg:#a12525;--md-alert-note-border:#539bf5;--md-alert-note-title:#6cb2ff;--md-alert-important-border:#986ee2;--md-alert-important-title:#b992f8;--md-alert-warning-border:#b0881a;--md-alert-warning-title:#e0b044;--md-alert-tip-border:#2ea855;--md-alert-tip-title:#4ec96a;--md-alert-caution-border:#e04a45;--md-alert-caution-title:#f85149;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;word-wrap:break-word;background-color:var(--md-bg);color:var(--md-text);color-scheme:dark;flex:1 1 auto;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Noto Sans,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;font-size:16px;font-weight:400;line-height:1.5;margin:0}.markdown-body a{text-decoration:underline;text-underline-offset:.2rem}.markdown-body h1:hover .anchor .octicon-link:before,.markdown-body h2:hover .anchor .octicon-link:before,.markdown-body h3:hover .anchor .octicon-link:before,.markdown-body h4:hover .anchor .octicon-link:before,.markdown-body h5:hover .anchor .octicon-link:before,.markdown-body h6:hover .anchor .octicon-link:before{background-color:currentColor;content:" ";display:inline-block;height:16px;-webkit-mask-image:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" aria-hidden="true"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 0 0 1.06 1.06l1.25-1.25a2 2 0 1 1 2.83 2.83l-2.5 2.5a2 2 0 0 1-2.83 0 .75.75 0 0 0-1.06 1.06 3.5 3.5 0 0 0 4.95 0l2.5-2.5a3.5 3.5 0 0 0-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 0 1 0-2.83l2.5-2.5a2 2 0 0 1 2.83 0 .75.75 0 0 0 1.06-1.06 3.5 3.5 0 0 0-4.95 0l-2.5 2.5a3.5 3.5 0 0 0 4.95 4.95l1.25-1.25a.75.75 0 0 0-1.06-1.06l-1.25 1.25a2 2 0 0 1-2.83 0z"/></svg>');mask-image:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" aria-hidden="true"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 0 0 1.06 1.06l1.25-1.25a2 2 0 1 1 2.83 2.83l-2.5 2.5a2 2 0 0 1-2.83 0 .75.75 0 0 0-1.06 1.06 3.5 3.5 0 0 0 4.95 0l2.5-2.5a3.5 3.5 0 0 0-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 0 1 0-2.83l2.5-2.5a2 2 0 0 1 2.83 0 .75.75 0 0 0 1.06-1.06 3.5 3.5 0 0 0-4.95 0l-2.5 2.5a3.5 3.5 0 0 0 4.95 4.95l1.25-1.25a.75.75 0 0 0-1.06-1.06l-1.25 1.25a2 2 0 0 1-2.83 0z"/></svg>');width:16px}.markdown-body details,.markdown-body figcaption,.markdown-body figure{display:block}.markdown-body summary{display:list-item}.markdown-body [hidden]{display:none!important}.markdown-body a{background-color:var(--md-bg-transparent);color:var(--md-text-link);text-decoration:none}.markdown-body abbr[title]{border-bottom:none;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.markdown-body b,.markdown-body strong{font-weight:600}.markdown-body dfn{font-style:italic}.markdown-body h1{font-size:2em;margin:.67em 0;padding-bottom:.3em}.markdown-body mark{background-color:var(--md-bg-mark);color:var(--md-text)}.markdown-body small{font-size:90%}.markdown-body sub,.markdown-body sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}.markdown-body sub{bottom:-.25em}.markdown-body sup{top:-.5em}.markdown-body img{border-style:none;box-sizing:content-box;max-width:100%}.markdown-body code,.markdown-body kbd,.markdown-body pre,.markdown-body samp{font-family:monospace;font-size:1em}.markdown-body figure{margin:1em 2.5rem}.markdown-body hr{background:var(--md-bg-transparent);background-color:var(--md-border);border:0;box-sizing:content-box;height:.25em;margin:1.5rem 0;overflow:hidden;padding:0}.markdown-body input{font:inherit;font-family:inherit;font-size:inherit;line-height:inherit;margin:0;overflow:visible}.markdown-body [type=button],.markdown-body [type=reset],.markdown-body [type=submit]{-webkit-appearance:button;appearance:button}.markdown-body [type=checkbox],.markdown-body [type=radio]{box-sizing:border-box;padding:0}.markdown-body [type=number]::-webkit-inner-spin-button,.markdown-body [type=number]::-webkit-outer-spin-button{height:auto}.markdown-body [type=search]::-webkit-search-cancel-button,.markdown-body [type=search]::-webkit-search-decoration{-webkit-appearance:none;appearance:none}.markdown-body ::-webkit-input-placeholder{color:inherit;opacity:.54}.markdown-body ::-webkit-file-upload-button{-webkit-appearance:button;appearance:button;font:inherit}.markdown-body a:hover{text-decoration:underline}.markdown-body ::placeholder{color:var(--md-text-muted);opacity:1}.markdown-body hr:after,.markdown-body hr:before{content:"";display:table}.markdown-body hr:after{clear:both}.markdown-body table{border-collapse:collapse;border-spacing:0;display:block;font-variant:tabular-nums;max-width:100%;overflow:auto;width:max-content}.markdown-body td,.markdown-body th{padding:0}.markdown-body details summary{cursor:pointer}.markdown-body [role=button]:focus,.markdown-body a:focus,.markdown-body input[type=checkbox]:focus,.markdown-body input[type=radio]:focus{box-shadow:none;outline:2px solid var(--borderColor-accent-emphasis);outline-offset:-2px}.markdown-body [role=button]:focus:not(:focus-visible),.markdown-body a:focus:not(:focus-visible),.markdown-body input[type=checkbox]:focus:not(:focus-visible),.markdown-body input[type=radio]:focus:not(:focus-visible){outline:1px solid transparent}.markdown-body [role=button]:focus-visible,.markdown-body a:focus-visible,.markdown-body input[type=checkbox]:focus-visible,.markdown-body input[type=radio]:focus-visible{box-shadow:none;outline:2px solid var(--borderColor-accent-emphasis);outline-offset:-2px}.markdown-body a:not([class]):focus,.markdown-body a:not([class]):focus-visible,.markdown-body input[type=checkbox]:focus,.markdown-body input[type=checkbox]:focus-visible,.markdown-body input[type=radio]:focus,.markdown-body input[type=radio]:focus-visible{outline-offset:0}.markdown-body kbd{background-color:var(--md-bg-secondary);border-bottom-color:var(--borderColor-muted);border:1px solid var(--borderColor-muted);border-radius:6px;box-shadow:inset 0 -1px 0 var(--borderColor-muted);color:var(--md-text);display:inline-block;font:11px ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;line-height:10px;padding:.25rem;vertical-align:middle}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{font-weight:500;letter-spacing:.05em;line-height:1.25;margin-bottom:1rem;margin-top:1.5rem}.markdown-body h2{font-size:1.5em;padding-bottom:.3em}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:.875em}.markdown-body h6{color:var(--md-text-muted);font-size:.85em}.markdown-body p{margin-bottom:10px;margin-top:0}.markdown-body blockquote{border-left:.25em solid var(--md-border);color:var(--md-text-muted);margin:0;padding:0 1em}.markdown-body ol,.markdown-body ul{margin-bottom:0;margin-top:0;padding-left:2em}.markdown-body ol ol,.markdown-body ul ol{list-style-type:lower-roman}.markdown-body ol ol ol,.markdown-body ol ul ol,.markdown-body ul ol ol,.markdown-body ul ul ol{list-style-type:lower-alpha}.markdown-body dd{margin-left:0}.markdown-body code,.markdown-body pre,.markdown-body samp,.markdown-body tt{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:12px}.markdown-body pre{word-wrap:normal;margin-bottom:0;margin-top:0}.markdown-body .octicon{fill:currentColor;display:inline-block;overflow:visible!important;vertical-align:text-bottom}.markdown-body input::-webkit-inner-spin-button,.markdown-body input::-webkit-outer-spin-button{appearance:none;margin:0}.markdown-body .mr-2{margin-right:.5rem!important}.markdown-body:after,.markdown-body:before{content:"";display:table}.markdown-body:after{clear:both}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .absent{color:var(--md-danger-fg)}.markdown-body .anchor{float:left;line-height:1;margin-left:-20px;padding-right:.25rem}.markdown-body .anchor:focus{outline:none}.markdown-body blockquote,.markdown-body details,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-bottom:1rem;margin-top:0}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:var(--md-text);vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{font-size:inherit;padding:0 .2em}.markdown-body summary h1,.markdown-body summary h2,.markdown-body summary h3,.markdown-body summary h4,.markdown-body summary h5,.markdown-body summary h6{display:inline-block}.markdown-body summary h1 .anchor,.markdown-body summary h2 .anchor,.markdown-body summary h3 .anchor,.markdown-body summary h4 .anchor,.markdown-body summary h5 .anchor,.markdown-body summary h6 .anchor{margin-left:-40px}.markdown-body summary h1,.markdown-body summary h2{border-bottom:0;padding-bottom:0}.markdown-body ol.no-list,.markdown-body ul.no-list{list-style-type:none;padding:0}.markdown-body ol[type="a s"]{list-style-type:lower-alpha}.markdown-body ol[type="A s"]{list-style-type:upper-alpha}.markdown-body ol[type="i s"]{list-style-type:lower-roman}.markdown-body ol[type="I s"]{list-style-type:upper-roman}.markdown-body div>ol:not([type]),.markdown-body ol[type="1"]{list-style-type:decimal}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-bottom:0;margin-top:0}.markdown-body li>p{margin-top:1rem}.markdown-body li+li{margin-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{font-size:1em;font-style:italic;font-weight:600;margin-top:1rem;padding:0}.markdown-body dl dd{margin-bottom:1rem;padding:0 1rem}.markdown-body table th{font-weight:600}.markdown-body table td,.markdown-body table th{border:1px solid var(--md-border);padding:6px 13px}.markdown-body table td>:last-child{margin-bottom:0}.markdown-body table tr{background-color:var(--md-bg);border-top:1px solid var(--md-border-muted)}.markdown-body table tr:nth-child(2n){background-color:var(--md-bg-secondary)}.markdown-body table img{background-color:var(--md-bg-transparent)}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body .emoji{background-color:var(--md-bg-transparent);max-width:none;vertical-align:text-top}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{border:1px solid var(--md-border);display:block;float:left;margin:13px 0 0;overflow:hidden;padding:7px;width:auto}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{clear:both;color:var(--md-text);display:block;padding:5px 0 0}.markdown-body span.align-center{clear:both;display:block;overflow:hidden}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{clear:both;display:block;overflow:hidden}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body p>code{background-color:var(--md-bg-inline-code)}.markdown-body code,.markdown-body tt{background-color:var(--md-bg-code);border-radius:6px;font-size:85%;margin:0;padding:.2em .4em;white-space:break-spaces}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body samp{font-size:85%}.markdown-body pre code{font-size:100%}.markdown-body pre>code{background:var(--md-bg-transparent);border:0;margin:0;padding:0;white-space:pre;word-break:normal}.markdown-body .highlight{margin-bottom:1rem}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{background-color:var(--md-bg-secondary);border-radius:6px;color:var(--md-text);font-size:85%;line-height:1.45;overflow:auto;padding:1rem}.markdown-body pre code,.markdown-body pre tt{word-wrap:normal;background-color:var(--md-bg-transparent);border:0;display:inline;line-height:inherit;margin:0;overflow:visible;padding:0}.markdown-body .csv-data td,.markdown-body .csv-data th{font-size:12px;line-height:1;overflow:hidden;padding:5px;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-num{background:var(--md-bg);border:0;padding:10px .5rem 9px;text-align:right}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{background:var(--md-bg-secondary);border-top:0;font-weight:600}.markdown-body [data-footnote-ref]:before{content:"["}.markdown-body [data-footnote-ref]:after{content:"]"}.markdown-body .footnotes{border-top:1px solid var(--md-border);color:var(--md-text-muted);font-size:12px}.markdown-body .footnotes ol{padding-left:1rem}.markdown-body .footnotes ol ul{display:inline-block;margin-top:1rem;padding-left:1rem}.markdown-body .footnotes li{position:relative}.markdown-body .footnotes li:target:before{border:2px solid var(--md-accent-focus);border-radius:6px;bottom:-.5rem;content:"";left:-1.5rem;pointer-events:none;position:absolute;right:-.5rem;top:-.5rem}.markdown-body .footnotes li:target{color:var(--md-text)}.markdown-body .footnotes .data-footnote-backref g-emoji{font-family:monospace}.markdown-body .pl-c{color:var(--md-text-muted)}.markdown-body .pl-c1,.markdown-body .pl-s .pl-v{color:var(--md-syntax-number)}.markdown-body .pl-e,.markdown-body .pl-en{color:var(--md-syntax-function)}.markdown-body .pl-s .pl-s1,.markdown-body .pl-smi{color:var(--md-text)}.markdown-body .pl-ent{color:var(--md-syntax-builtin)}.markdown-body .pl-k{color:var(--md-syntax-keyword)}.markdown-body .pl-pds,.markdown-body .pl-s,.markdown-body .pl-s .pl-pse .pl-s1,.markdown-body .pl-sr,.markdown-body .pl-sr .pl-cce,.markdown-body .pl-sr .pl-sra,.markdown-body .pl-sr .pl-sre{color:var(--md-syntax-string)}.markdown-body .pl-smw,.markdown-body .pl-v{color:var(--md-syntax-variable)}.markdown-body .pl-bu{color:var(--md-danger-fg)}.markdown-body .pl-ii{background-color:var(--bgColor-danger-muted);color:var(--fgColor-danger)}.markdown-body .pl-c2{background-color:var(--md-danger-bg);color:var(--md-text)}.markdown-body .pl-sr .pl-cce{color:var(--md-syntax-builtin);font-weight:700}.markdown-body .pl-ml{color:var(--md-syntax-meta)}.markdown-body .pl-mh,.markdown-body .pl-mh .pl-en,.markdown-body .pl-ms{color:var(--md-accent-focus);font-weight:700}.markdown-body .pl-mi{color:var(--md-text);font-style:italic}.markdown-body .pl-mb{color:var(--md-text);font-weight:700}.markdown-body .pl-md{background-color:var(--md-diff-del-bg);color:var(--md-diff-del-text)}.markdown-body .pl-mi1{background-color:var(--md-diff-add-bg);color:var(--md-diff-add-text)}.markdown-body .pl-mc{background-color:var(--md-diff-changed-bg);color:var(--md-diff-changed-text)}.markdown-body .pl-mi2{background-color:var(--md-diff-meta-bg);color:var(--md-text)}.markdown-body .pl-mdr{color:var(--md-syntax-function);font-weight:700}.markdown-body .pl-ba{color:var(--md-text-muted)}.markdown-body .pl-sg{color:var(--md-border)}.markdown-body .pl-corl{color:var(--md-syntax-string);text-decoration:underline}.markdown-body [role=button]:focus:not(:focus-visible),.markdown-body [role=tabpanel][tabindex="0"]:focus:not(:focus-visible),.markdown-body a:focus:not(:focus-visible),.markdown-body button:focus:not(:focus-visible),.markdown-body summary:focus:not(:focus-visible){box-shadow:none;outline:none}.markdown-body [tabindex="0"]:focus:not(:focus-visible),.markdown-body details-dialog:focus:not(:focus-visible){outline:none}.markdown-body g-emoji{display:inline-block;font-family:Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;font-size:1em;font-style:normal!important;font-weight:400;line-height:1;min-width:1ch;vertical-align:-.075em}.markdown-body g-emoji img{height:1em;width:1em}.markdown-body a:has(>p,>div,>pre,>blockquote){display:block}.markdown-body a:has(>p,>div,>pre,>blockquote):not(:has(.snippet-clipboard-content,>pre)){width:fit-content}.markdown-body a:has(>p,>div,>pre,>blockquote):has(.snippet-clipboard-content,>pre):focus-visible{outline:2px solid var(--borderColor-accent-emphasis);outline-offset:2px}.markdown-body .task-list-item{list-style-type:none}.markdown-body .task-list-item label{font-weight:400}.markdown-body .task-list-item.enabled label{cursor:pointer}.markdown-body .task-list-item+.task-list-item{margin-top:.25rem}.markdown-body .task-list-item .handle{display:none}.markdown-body .task-list-item-checkbox{margin:0 .2em .25em -1.4em;vertical-align:middle}.markdown-body ul:dir(rtl) .task-list-item-checkbox{margin:0 -1.6em .25em .2em}.markdown-body ol:dir(rtl) .task-list-item-checkbox{margin:0 -1.6em .25em .2em}.markdown-body .contains-task-list:focus-within .task-list-item-convert-container,.markdown-body .contains-task-list:hover .task-list-item-convert-container{clip-path:none;display:block;height:24px;overflow:visible;width:auto}.markdown-body ::-webkit-calendar-picker-indicator{filter:invert(50%)}.markdown-body .markdown-alert{border-left:.25em solid var(--md-border);color:inherit;margin-bottom:1rem;padding:.5rem 1rem}.markdown-body .markdown-alert>:first-child{margin-top:0}.markdown-body .markdown-alert>:last-child{margin-bottom:0}.markdown-body .markdown-alert .markdown-alert-title{align-items:center;display:flex;font-weight:500;line-height:1}.markdown-body .markdown-alert.markdown-alert-note{border-left-color:var(--md-alert-note-border)}.markdown-body .markdown-alert.markdown-alert-note .markdown-alert-title{color:var(--md-text-link)}.markdown-body .markdown-alert.markdown-alert-important{border-left-color:var(--md-alert-important-border)}.markdown-body .markdown-alert.markdown-alert-important .markdown-alert-title{color:var(--md-alert-important-title)}.markdown-body .markdown-alert.markdown-alert-warning{border-left-color:var(--md-alert-warning-border)}.markdown-body .markdown-alert.markdown-alert-warning .markdown-alert-title{color:var(--md-alert-warning-title)}.markdown-body .markdown-alert.markdown-alert-tip{border-left-color:var(--md-alert-tip-border)}.markdown-body .markdown-alert.markdown-alert-tip .markdown-alert-title{color:var(--md-alert-tip-title)}.markdown-body .markdown-alert.markdown-alert-caution{border-left-color:var(--md-alert-caution-border)}.markdown-body .markdown-alert.markdown-alert-caution .markdown-alert-title{color:var(--md-danger-fg)}.markdown-body>:first-child>.heading-element:first-child{margin-top:0!important}.markdown-body .highlight pre:has(+.zeroclipboard-container){min-height:52px}@font-face{font-family:Twilio;font-style:normal;font-weight:400;src:url(fonts/twilio.woff2) format("woff2")}pre code.hljs{-webkit-font-feature-settings:"calt" 1;font-feature-settings:"calt" 1;display:block;font-family:Twilio,monospace;font-variant-ligatures:common-ligatures contextual;letter-spacing:.1;line-height:2.2;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}
2
+ /*!
3
+ Theme: Tokyo-night-Dark
4
+ origin: https://github.com/enkia/tokyo-night-vscode-theme
5
+ Description: Original highlight.js style
6
+ Author: (c) Henri Vandersleyen <hvandersleyen@gmail.com>
7
+ License: see project LICENSE
8
+ Touched: 2022
9
+ */.hljs-comment,.hljs-meta{color:#565f89}.hljs-deletion,.hljs-doctag,.hljs-regexp,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-tag,.hljs-template-tag,.hljs-variable.language_{color:#f7768e}.hljs-link,.hljs-literal,.hljs-number,.hljs-params,.hljs-template-variable,.hljs-type,.hljs-variable{color:#ff9e64}.hljs-attribute,.hljs-built_in{color:#e0af68}.hljs-selector-tag{color:#2ac3de}.hljs-keyword,.hljs-property,.hljs-subst,.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#7dcfff}.hljs-selector-tag{color:#73daca}.hljs-addition,.hljs-bullet,.hljs-quote,.hljs-string,.hljs-symbol{color:#9ece6a}.hljs-code,.hljs-formula,.hljs-section{color:#7aa2f7}.hljs-attr,.hljs-char.escape_,.hljs-keyword,.hljs-name,.hljs-operator{color:#bb9af7}.hljs-punctuation{color:#c0caf5}.hljs{background:#1a1b26;color:#9aa5ce}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
@@ -1,26 +1,215 @@
1
1
  'use strict';
2
2
 
3
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
+ }
4
158
 
5
159
  function esc(s) {
6
160
  return s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$');
7
161
  }
8
- function gen(html, headers) {
9
- const code = [`import { bobe } from 'bobe';`, `const mdHtml = \`${esc(html)}\`;`, `export default bobe\``, ` div class="markdown" style="display: flex;"`, ` main class="markdown-main" style="overflow-y: auto;" html=\${mdHtml}`, ` if showAside`, ` div class="markdown-aside" style="display: flex; flex-direction: column; overflow-y: auto;"`, ...headers.map(({
10
- depth,
11
- id,
12
- text
13
- }) => {
14
- return ` a href="#${id}" text="${text}" class="markdown-aside-item markdown-aside-depth-${depth}"`;
15
- }), `\`;`].join('\n');
16
- return code;
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');
17
201
  }
202
+ const CODE_TAG_RE = /<code\s+src="([^"]+)"(\s+preview)?\s*\/>/g;
18
203
  function markdownPlugin(opt = {}) {
19
204
  let headers = [];
205
+ const headClassMap = {
206
+ '1': 'cyber-title'
207
+ };
20
208
  return {
21
209
  name: 'bobe-markdown',
22
210
  enforce: 'pre',
23
211
  configResolved() {
212
+ registerBobeLang();
24
213
  marked.marked.use({
25
214
  gfm: true,
26
215
  renderer: {
@@ -29,27 +218,47 @@ function markdownPlugin(opt = {}) {
29
218
  depth
30
219
  }) {
31
220
  const text = this.parser.parseInline(tokens);
32
- const id = text.toLowerCase().replace(/[^\w\u4e00-\u9fff]+/g, '-');
33
- if (depth <= opt.asideDeep || 3) {
221
+ const id = text.toLowerCase().replace(/[^\w一-鿿]+/g, '-');
222
+ if (depth <= (opt.asideDeep || 3)) {
34
223
  headers.push({
35
224
  depth,
36
225
  id,
37
226
  text
38
227
  });
39
228
  }
40
- return `<h${depth} id="${id}">${text}</h${depth}>`;
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>`;
41
238
  }
42
239
  }
43
240
  });
44
241
  if (opt.marked) marked.marked.use(opt.marked);
45
242
  },
46
- transform(code, id) {
243
+ async transform(code, id) {
47
244
  if (!id.match(/\.mdx?$/)) return;
48
245
  headers = [];
49
246
  try {
50
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))));
51
260
  return {
52
- code: gen(html, headers),
261
+ code: gen(finalHtml, headers, previewEntries, codeTrees),
53
262
  moduleSideEffects: false
54
263
  };
55
264
  } catch (e) {
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.cjs.js","sources":["../src/plugins/markdown/index.ts"],"sourcesContent":["import type { Plugin } from 'vite';\nimport type { MarkedExtension } from 'marked';\nimport { marked } from 'marked';\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[]): string {\n const code = [\n `import { bobe } from 'bobe';`,\n `const mdHtml = \\`${esc(html)}\\`;`,\n `export default bobe\\``,\n ` div class=\"markdown\" style=\"display: flex;\"`,\n ` main class=\"markdown-main\" style=\"overflow-y: auto;\" html=\\${mdHtml}`,\n ` if showAside`,\n ` div class=\"markdown-aside\" style=\"display: flex; flex-direction: column; overflow-y: auto;\"`,\n ...headers.map(({ depth, id, text }) => {\n return ` a href=\"#${id}\" text=\"${text}\" class=\"markdown-aside-item markdown-aside-depth-${depth}\"`;\n }),\n `\\`;`\n ].join('\\n');\n return code;\n}\n\n/**\n * bobe-markdown Vite 插件。\n *\n * 将 .md / .mdx 文件编译为 bobe 组件:\n * import Readme from './README.md';\n */\n\nexport type HeadItem = {\n depth: number;\n id: string;\n text: string;\n};\nexport default function markdownPlugin(opt: MarkdownPluginOptions = {}): Plugin {\n let headers: HeadItem[] = [];\n return {\n name: 'bobe-markdown',\n enforce: 'pre',\n\n configResolved() {\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\\u4e00-\\u9fff]+/g, '-');\n if(depth <= opt.asideDeep || 3) {\n headers.push({ depth, id, text });\n }\n return `<h${depth} id=\"${id}\">${text}</h${depth}>`;\n }\n }\n });\n if (opt.marked) marked.use(opt.marked);\n },\n\n transform(code, id) {\n if (!id.match(/\\.mdx?$/)) return;\n headers = [];\n try {\n const html = marked.parse(code) as string;\n return { code: gen(html, headers), moduleSideEffects: false };\n } catch (e: any) {\n this.error(`[bobe-markdown] 解析失败: ${id}\\n${e.message}`);\n }\n }\n };\n}\n"],"names":["esc","s","replace","gen","html","headers","code","map","depth","id","text","join","markdownPlugin","opt","name","enforce","configResolved","marked","use","gfm","renderer","heading","tokens","parser","parseInline","toLowerCase","asideDeep","push","transform","match","parse","moduleSideEffects","e","error","message"],"mappings":";;;;AAYA,SAASA,GAAGA,CAACC,CAAS,EAAU;EAC9B,OAAOA,CAAC,CAACC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAACA,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAACA,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;AAC5E;AAGA,SAASC,GAAGA,CAACC,IAAY,EAAEC,OAAmB,EAAU;EACtD,MAAMC,IAAI,GAAG,CACX,CAAA,4BAAA,CAA8B,EAC9B,CAAA,iBAAA,EAAoBN,GAAG,CAACI,IAAI,CAAC,CAAA,GAAA,CAAK,EAClC,CAAA,qBAAA,CAAuB,EACvB,CAAA,6CAAA,CAA+C,EAC/C,CAAA,wEAAA,CAA0E,EAC1E,CAAA,gBAAA,CAAkB,EAClB,CAAA,iGAAA,CAAmG,EACnG,GAAGC,OAAO,CAACE,GAAG,CAAC,CAAC;IAAEC,KAAK;IAAEC,EAAE;AAAEC,IAAAA;AAAK,GAAC,KAAK;AACtC,IAAA,OAAO,oBAAoBD,EAAE,CAAA,QAAA,EAAWC,IAAI,CAAA,kDAAA,EAAqDF,KAAK,CAAA,CAAA,CAAG;EAC3G,CAAC,CAAC,EACF,CAAA,GAAA,CAAK,CACN,CAACG,IAAI,CAAC,IAAI,CAAC;AACZ,EAAA,OAAOL,IAAI;AACb;AAce,SAASM,cAAcA,CAACC,GAA0B,GAAG,EAAE,EAAU;EAC9E,IAAIR,OAAmB,GAAG,EAAE;EAC5B,OAAO;AACLS,IAAAA,IAAI,EAAE,eAAe;AACrBC,IAAAA,OAAO,EAAE,KAAK;AAEdC,IAAAA,cAAcA,GAAG;MACfC,aAAM,CAACC,GAAG,CAAC;AACTC,QAAAA,GAAG,EAAE,IAAI;AACTC,QAAAA,QAAQ,EAAE;AACRC,UAAAA,OAAOA,CAAC;YAAEC,MAAM;AAAEd,YAAAA;AAAM,WAAC,EAAE;YACzB,MAAME,IAAI,GAAG,IAAI,CAACa,MAAM,CAACC,WAAW,CAACF,MAAM,CAAC;AAC5C,YAAA,MAAMb,EAAE,GAAGC,IAAI,CAACe,WAAW,EAAE,CAACvB,OAAO,CAAC,sBAAsB,EAAE,GAAG,CAAC;AAClE,YAAA,IAAGM,KAAK,IAAIK,GAAG,CAACa,SAAS,IAAI,CAAC,EAAE;cAC9BrB,OAAO,CAACsB,IAAI,CAAC;gBAAEnB,KAAK;gBAAEC,EAAE;AAAEC,gBAAAA;AAAK,eAAC,CAAC;AACnC,YAAA;YACA,OAAO,CAAA,EAAA,EAAKF,KAAK,CAAA,KAAA,EAAQC,EAAE,KAAKC,IAAI,CAAA,GAAA,EAAMF,KAAK,CAAA,CAAA,CAAG;AACpD,UAAA;AACF;AACF,OAAC,CAAC;MACF,IAAIK,GAAG,CAACI,MAAM,EAAEA,aAAM,CAACC,GAAG,CAACL,GAAG,CAACI,MAAM,CAAC;IACxC,CAAC;AAEDW,IAAAA,SAASA,CAACtB,IAAI,EAAEG,EAAE,EAAE;AAClB,MAAA,IAAI,CAACA,EAAE,CAACoB,KAAK,CAAC,SAAS,CAAC,EAAE;AAC1BxB,MAAAA,OAAO,GAAG,EAAE;MACZ,IAAI;AACF,QAAA,MAAMD,IAAI,GAAGa,aAAM,CAACa,KAAK,CAACxB,IAAI,CAAW;QACzC,OAAO;AAAEA,UAAAA,IAAI,EAAEH,GAAG,CAACC,IAAI,EAAEC,OAAO,CAAC;AAAE0B,UAAAA,iBAAiB,EAAE;SAAO;MAC/D,CAAC,CAAC,OAAOC,CAAM,EAAE;QACf,IAAI,CAACC,KAAK,CAAC,CAAA,sBAAA,EAAyBxB,EAAE,KAAKuB,CAAC,CAACE,OAAO,CAAA,CAAE,CAAC;AACzD,MAAA;AACF,IAAA;GACD;AACH;;;;"}
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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"}
@@ -12,6 +12,9 @@ interface MarkdownPluginOptions {
12
12
  *
13
13
  * 将 .md / .mdx 文件编译为 bobe 组件:
14
14
  * import Readme from './README.md';
15
+ *
16
+ * 支持 <code src="xxx.ts" /> 引入代码文件及 import 树(非 node_modules),
17
+ * 以 Code 组件 + tp 传送方式渲染。
15
18
  */
16
19
  type HeadItem = {
17
20
  depth: number;
@@ -1,24 +1,213 @@
1
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
+ }
2
156
 
3
157
  function esc(s) {
4
158
  return s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$');
5
159
  }
6
- function gen(html, headers) {
7
- const code = [`import { bobe } from 'bobe';`, `const mdHtml = \`${esc(html)}\`;`, `export default bobe\``, ` div class="markdown" style="display: flex;"`, ` main class="markdown-main" style="overflow-y: auto;" html=\${mdHtml}`, ` if showAside`, ` div class="markdown-aside" style="display: flex; flex-direction: column; overflow-y: auto;"`, ...headers.map(({
8
- depth,
9
- id,
10
- text
11
- }) => {
12
- return ` a href="#${id}" text="${text}" class="markdown-aside-item markdown-aside-depth-${depth}"`;
13
- }), `\`;`].join('\n');
14
- return code;
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');
15
199
  }
200
+ const CODE_TAG_RE = /<code\s+src="([^"]+)"(\s+preview)?\s*\/>/g;
16
201
  function markdownPlugin(opt = {}) {
17
202
  let headers = [];
203
+ const headClassMap = {
204
+ '1': 'cyber-title'
205
+ };
18
206
  return {
19
207
  name: 'bobe-markdown',
20
208
  enforce: 'pre',
21
209
  configResolved() {
210
+ registerBobeLang();
22
211
  marked.use({
23
212
  gfm: true,
24
213
  renderer: {
@@ -27,27 +216,47 @@ function markdownPlugin(opt = {}) {
27
216
  depth
28
217
  }) {
29
218
  const text = this.parser.parseInline(tokens);
30
- const id = text.toLowerCase().replace(/[^\w\u4e00-\u9fff]+/g, '-');
31
- if (depth <= opt.asideDeep || 3) {
219
+ const id = text.toLowerCase().replace(/[^\w一-鿿]+/g, '-');
220
+ if (depth <= (opt.asideDeep || 3)) {
32
221
  headers.push({
33
222
  depth,
34
223
  id,
35
224
  text
36
225
  });
37
226
  }
38
- return `<h${depth} id="${id}">${text}</h${depth}>`;
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>`;
39
236
  }
40
237
  }
41
238
  });
42
239
  if (opt.marked) marked.use(opt.marked);
43
240
  },
44
- transform(code, id) {
241
+ async transform(code, id) {
45
242
  if (!id.match(/\.mdx?$/)) return;
46
243
  headers = [];
47
244
  try {
48
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))));
49
258
  return {
50
- code: gen(html, headers),
259
+ code: gen(finalHtml, headers, previewEntries, codeTrees),
51
260
  moduleSideEffects: false
52
261
  };
53
262
  } catch (e) {
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.esm.js","sources":["../src/plugins/markdown/index.ts"],"sourcesContent":["import type { Plugin } from 'vite';\nimport type { MarkedExtension } from 'marked';\nimport { marked } from 'marked';\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[]): string {\n const code = [\n `import { bobe } from 'bobe';`,\n `const mdHtml = \\`${esc(html)}\\`;`,\n `export default bobe\\``,\n ` div class=\"markdown\" style=\"display: flex;\"`,\n ` main class=\"markdown-main\" style=\"overflow-y: auto;\" html=\\${mdHtml}`,\n ` if showAside`,\n ` div class=\"markdown-aside\" style=\"display: flex; flex-direction: column; overflow-y: auto;\"`,\n ...headers.map(({ depth, id, text }) => {\n return ` a href=\"#${id}\" text=\"${text}\" class=\"markdown-aside-item markdown-aside-depth-${depth}\"`;\n }),\n `\\`;`\n ].join('\\n');\n return code;\n}\n\n/**\n * bobe-markdown Vite 插件。\n *\n * 将 .md / .mdx 文件编译为 bobe 组件:\n * import Readme from './README.md';\n */\n\nexport type HeadItem = {\n depth: number;\n id: string;\n text: string;\n};\nexport default function markdownPlugin(opt: MarkdownPluginOptions = {}): Plugin {\n let headers: HeadItem[] = [];\n return {\n name: 'bobe-markdown',\n enforce: 'pre',\n\n configResolved() {\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\\u4e00-\\u9fff]+/g, '-');\n if(depth <= opt.asideDeep || 3) {\n headers.push({ depth, id, text });\n }\n return `<h${depth} id=\"${id}\">${text}</h${depth}>`;\n }\n }\n });\n if (opt.marked) marked.use(opt.marked);\n },\n\n transform(code, id) {\n if (!id.match(/\\.mdx?$/)) return;\n headers = [];\n try {\n const html = marked.parse(code) as string;\n return { code: gen(html, headers), moduleSideEffects: false };\n } catch (e: any) {\n this.error(`[bobe-markdown] 解析失败: ${id}\\n${e.message}`);\n }\n }\n };\n}\n"],"names":["esc","s","replace","gen","html","headers","code","map","depth","id","text","join","markdownPlugin","opt","name","enforce","configResolved","marked","use","gfm","renderer","heading","tokens","parser","parseInline","toLowerCase","asideDeep","push","transform","match","parse","moduleSideEffects","e","error","message"],"mappings":";;AAYA,SAASA,GAAGA,CAACC,CAAS,EAAU;EAC9B,OAAOA,CAAC,CAACC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAACA,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAACA,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;AAC5E;AAGA,SAASC,GAAGA,CAACC,IAAY,EAAEC,OAAmB,EAAU;EACtD,MAAMC,IAAI,GAAG,CACX,CAAA,4BAAA,CAA8B,EAC9B,CAAA,iBAAA,EAAoBN,GAAG,CAACI,IAAI,CAAC,CAAA,GAAA,CAAK,EAClC,CAAA,qBAAA,CAAuB,EACvB,CAAA,6CAAA,CAA+C,EAC/C,CAAA,wEAAA,CAA0E,EAC1E,CAAA,gBAAA,CAAkB,EAClB,CAAA,iGAAA,CAAmG,EACnG,GAAGC,OAAO,CAACE,GAAG,CAAC,CAAC;IAAEC,KAAK;IAAEC,EAAE;AAAEC,IAAAA;AAAK,GAAC,KAAK;AACtC,IAAA,OAAO,oBAAoBD,EAAE,CAAA,QAAA,EAAWC,IAAI,CAAA,kDAAA,EAAqDF,KAAK,CAAA,CAAA,CAAG;EAC3G,CAAC,CAAC,EACF,CAAA,GAAA,CAAK,CACN,CAACG,IAAI,CAAC,IAAI,CAAC;AACZ,EAAA,OAAOL,IAAI;AACb;AAce,SAASM,cAAcA,CAACC,GAA0B,GAAG,EAAE,EAAU;EAC9E,IAAIR,OAAmB,GAAG,EAAE;EAC5B,OAAO;AACLS,IAAAA,IAAI,EAAE,eAAe;AACrBC,IAAAA,OAAO,EAAE,KAAK;AAEdC,IAAAA,cAAcA,GAAG;MACfC,MAAM,CAACC,GAAG,CAAC;AACTC,QAAAA,GAAG,EAAE,IAAI;AACTC,QAAAA,QAAQ,EAAE;AACRC,UAAAA,OAAOA,CAAC;YAAEC,MAAM;AAAEd,YAAAA;AAAM,WAAC,EAAE;YACzB,MAAME,IAAI,GAAG,IAAI,CAACa,MAAM,CAACC,WAAW,CAACF,MAAM,CAAC;AAC5C,YAAA,MAAMb,EAAE,GAAGC,IAAI,CAACe,WAAW,EAAE,CAACvB,OAAO,CAAC,sBAAsB,EAAE,GAAG,CAAC;AAClE,YAAA,IAAGM,KAAK,IAAIK,GAAG,CAACa,SAAS,IAAI,CAAC,EAAE;cAC9BrB,OAAO,CAACsB,IAAI,CAAC;gBAAEnB,KAAK;gBAAEC,EAAE;AAAEC,gBAAAA;AAAK,eAAC,CAAC;AACnC,YAAA;YACA,OAAO,CAAA,EAAA,EAAKF,KAAK,CAAA,KAAA,EAAQC,EAAE,KAAKC,IAAI,CAAA,GAAA,EAAMF,KAAK,CAAA,CAAA,CAAG;AACpD,UAAA;AACF;AACF,OAAC,CAAC;MACF,IAAIK,GAAG,CAACI,MAAM,EAAEA,MAAM,CAACC,GAAG,CAACL,GAAG,CAACI,MAAM,CAAC;IACxC,CAAC;AAEDW,IAAAA,SAASA,CAACtB,IAAI,EAAEG,EAAE,EAAE;AAClB,MAAA,IAAI,CAACA,EAAE,CAACoB,KAAK,CAAC,SAAS,CAAC,EAAE;AAC1BxB,MAAAA,OAAO,GAAG,EAAE;MACZ,IAAI;AACF,QAAA,MAAMD,IAAI,GAAGa,MAAM,CAACa,KAAK,CAACxB,IAAI,CAAW;QACzC,OAAO;AAAEA,UAAAA,IAAI,EAAEH,GAAG,CAACC,IAAI,EAAEC,OAAO,CAAC;AAAE0B,UAAAA,iBAAiB,EAAE;SAAO;MAC/D,CAAC,CAAC,OAAOC,CAAM,EAAE;QACf,IAAI,CAACC,KAAK,CAAC,CAAA,sBAAA,EAAyBxB,EAAE,KAAKuB,CAAC,CAACE,OAAO,CAAA,CAAE,CAAC;AACzD,MAAA;AACF,IAAA;GACD;AACH;;;;"}
1
+ {"version":3,"file":"markdown.esm.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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"}
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "bobe-dom",
3
- "version": "0.0.61",
3
+ "version": "0.0.62",
4
4
  "main": "dist/bobe-dom.cjs.js",
5
5
  "module": "dist/bobe-dom.esm.js",
6
6
  "browser": "dist/bobe-dom.umd.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "private": false,
9
9
  "dependencies": {
10
+ "highlight.js": "^11.11.1",
10
11
  "marked": "^18.0.4",
11
- "bobe": "0.0.61"
12
+ "bobe": "0.0.62"
12
13
  },
13
14
  "devDependencies": {
14
15
  "vitest": "^4.1.7"
@@ -23,7 +24,14 @@
23
24
  "types": "./dist/markdown.d.ts",
24
25
  "import": "./dist/markdown.esm.js",
25
26
  "require": "./dist/markdown.cjs.js"
26
- }
27
+ },
28
+ "./plugin-markdown/code": {
29
+ "types": "./dist/code.d.ts",
30
+ "import": "./dist/code.esm.js",
31
+ "require": "./dist/code.cjs.js"
32
+ },
33
+ "./plugin-markdown/index.css": "./dist/index.css",
34
+ "./plugin-markdown/code.css": "./dist/code.css"
27
35
  },
28
36
  "files": [
29
37
  "dist"