@comark/vue 0.1.0

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.
Files changed (47) hide show
  1. package/dist/components/Comark.d.ts +77 -0
  2. package/dist/components/Comark.js +131 -0
  3. package/dist/components/ComarkRenderer.d.ts +57 -0
  4. package/dist/components/ComarkRenderer.js +288 -0
  5. package/dist/components/Math.d.ts +33 -0
  6. package/dist/components/Math.js +47 -0
  7. package/dist/components/Mermaid.d.ts +62 -0
  8. package/dist/components/Mermaid.js +101 -0
  9. package/dist/index.d.ts +18 -0
  10. package/dist/index.js +164 -0
  11. package/dist/parse.d.ts +1 -0
  12. package/dist/parse.js +1 -0
  13. package/dist/plugins/alert.d.ts +2 -0
  14. package/dist/plugins/alert.js +2 -0
  15. package/dist/plugins/emoji.d.ts +2 -0
  16. package/dist/plugins/emoji.js +2 -0
  17. package/dist/plugins/headings.d.ts +2 -0
  18. package/dist/plugins/headings.js +2 -0
  19. package/dist/plugins/highlight.d.ts +2 -0
  20. package/dist/plugins/highlight.js +2 -0
  21. package/dist/plugins/math.d.ts +3 -0
  22. package/dist/plugins/math.js +3 -0
  23. package/dist/plugins/mermaid.d.ts +3 -0
  24. package/dist/plugins/mermaid.js +3 -0
  25. package/dist/plugins/security.d.ts +2 -0
  26. package/dist/plugins/security.js +2 -0
  27. package/dist/plugins/summary.d.ts +2 -0
  28. package/dist/plugins/summary.js +2 -0
  29. package/dist/plugins/task-list.d.ts +2 -0
  30. package/dist/plugins/task-list.js +2 -0
  31. package/dist/plugins/toc.d.ts +2 -0
  32. package/dist/plugins/toc.js +2 -0
  33. package/dist/render.d.ts +1 -0
  34. package/dist/render.js +1 -0
  35. package/dist/utils/caret.d.ts +7 -0
  36. package/dist/utils/caret.js +38 -0
  37. package/dist/utils/index.d.ts +1 -0
  38. package/dist/utils/index.js +1 -0
  39. package/dist/utils/node.d.ts +8 -0
  40. package/dist/utils/node.js +83 -0
  41. package/dist/utils/slot.d.ts +3 -0
  42. package/dist/utils/slot.js +8 -0
  43. package/dist/utils/ssrSlot.d.ts +1 -0
  44. package/dist/utils/ssrSlot.js +8 -0
  45. package/dist/vite.d.ts +21 -0
  46. package/dist/vite.js +175 -0
  47. package/package.json +58 -0
package/dist/vite.js ADDED
@@ -0,0 +1,175 @@
1
+ import { fileURLToPath } from 'node:url';
2
+ import { readdir } from 'node:fs/promises';
3
+ import { join, basename } from 'node:path';
4
+ import { existsSync } from 'node:fs';
5
+ const runtimeDir = fileURLToPath(new URL('./utils', import.meta.url));
6
+ function viteComarkSlot(node, context) {
7
+ const isVueSlotWithUnwrap = node.tag === 'slot'
8
+ && node.props.find(p => p.name === 'unwrap' || p.name === 'mdc-wunwrap' || (p.name === 'bind' && p.rawName === ':comark-unwrap'));
9
+ if (isVueSlotWithUnwrap) {
10
+ const transform = context.ssr
11
+ ? context.nodeTransforms.find(nt => nt.name === 'ssrTransformSlotOutlet')
12
+ : context.nodeTransforms.find(nt => nt.name === 'transformSlotOutlet');
13
+ return () => {
14
+ node.tag = 'slot';
15
+ node.type = 1;
16
+ node.tagType = 2;
17
+ transform?.(node, context);
18
+ const codegen = context.ssr ? node.ssrCodegenNode : node.codegenNode;
19
+ codegen.callee = context.ssr ? '_ssrRenderComarkSlot' : '_renderComarkSlot';
20
+ const importExp = context.ssr
21
+ ? '{ ssrRenderSlot as _ssrRenderComarkSlot }'
22
+ : '{ renderSlot as _renderComarkSlot }';
23
+ if (!context.imports.some(i => String(i.exp) === importExp)) {
24
+ context.imports.push({
25
+ exp: importExp,
26
+ path: `${runtimeDir}/${context.ssr ? 'ssrSlot' : 'slot'}`,
27
+ });
28
+ }
29
+ };
30
+ }
31
+ if (context.nodeTransforms[0]?.name !== 'viteComarkSlot') {
32
+ const index = context.nodeTransforms.findIndex(f => f.name === 'viteComarkSlot');
33
+ if (index !== -1) {
34
+ const nt = context.nodeTransforms.splice(index, 1);
35
+ context.nodeTransforms.unshift(nt[0]);
36
+ }
37
+ }
38
+ }
39
+ const VIRTUAL_COMPONENTS_ID = 'virtual:comark-vue/components';
40
+ const RESOLVED_COMPONENTS_ID = '\0' + VIRTUAL_COMPONENTS_ID;
41
+ function toPascalCase(str) {
42
+ return str.replace(/(^|[-_.])(\w)/g, (_, __, c) => c.toUpperCase());
43
+ }
44
+ async function getProseFiles(proseDir) {
45
+ const files = [];
46
+ try {
47
+ const entries = await readdir(proseDir, { withFileTypes: true, recursive: true });
48
+ for (const entry of entries) {
49
+ if (!entry.isFile() || !entry.name.endsWith('.vue'))
50
+ continue;
51
+ // parentPath was added in Node 21.4 / 20.12; path is the legacy name
52
+ const dir = entry.parentPath ?? entry.path;
53
+ files.push(join(dir, entry.name));
54
+ }
55
+ }
56
+ catch {
57
+ // prose directory doesn't exist — that's fine
58
+ }
59
+ return files;
60
+ }
61
+ function generateComponentsModule(files) {
62
+ if (!files.length) {
63
+ return 'export default { install(app) {} }';
64
+ }
65
+ const lines = [];
66
+ for (let i = 0; i < files.length; i++) {
67
+ lines.push(`import __comp_${i} from ${JSON.stringify(files[i].replace(/\\/g, '/'))}`);
68
+ }
69
+ lines.push('');
70
+ lines.push('export default {');
71
+ lines.push(' install(app) {');
72
+ for (let i = 0; i < files.length; i++) {
73
+ const name = toPascalCase(basename(files[i], '.vue'));
74
+ lines.push(` app.component(${JSON.stringify(name)}, __comp_${i})`);
75
+ }
76
+ lines.push(' },');
77
+ lines.push('}');
78
+ return lines.join('\n');
79
+ }
80
+ /**
81
+ * Vite plugin for @comark/vue.
82
+ *
83
+ * - Adds `<slot unwrap="...">` support inside custom markdown components.
84
+ * - Auto-registers every `.vue` file in `src/components/prose` as a global
85
+ * component
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * // vite.config.ts
90
+ * import { defineConfig } from 'vite'
91
+ * import vue from '@vitejs/plugin-vue'
92
+ * import comark from '@comark/vue/vite'
93
+ *
94
+ * export default defineConfig({
95
+ * plugins: [vue(), comark()],
96
+ * })
97
+ * ```
98
+ */
99
+ export default function comark() {
100
+ let proseDir;
101
+ let proseFilesCache = null;
102
+ async function resolveProseFiles() {
103
+ if (!proseDir)
104
+ return [];
105
+ if (!proseFilesCache) {
106
+ proseFilesCache = await getProseFiles(proseDir);
107
+ }
108
+ return proseFilesCache;
109
+ }
110
+ function invalidateCache(file) {
111
+ if (file.startsWith(proseDir)) {
112
+ proseFilesCache = null;
113
+ }
114
+ }
115
+ return {
116
+ name: 'comark-vue',
117
+ enforce: 'pre',
118
+ configResolved(config) {
119
+ if (existsSync(join(config.root, 'src', 'components', 'prose'))) {
120
+ proseDir = join(config.root, 'src', 'components', 'prose');
121
+ }
122
+ if (existsSync(join(config.root, 'components', 'prose'))) {
123
+ proseDir = join(config.root, 'components', 'prose');
124
+ }
125
+ const vuePlugin = config.plugins.find(p => p.name === 'vite:vue');
126
+ if (!vuePlugin) {
127
+ console.warn('[comark-vue] @vitejs/plugin-vue not found. Make sure vue() is in your plugins.');
128
+ return;
129
+ }
130
+ const vueOptions = vuePlugin.api?.options;
131
+ if (!vueOptions)
132
+ return;
133
+ vueOptions.template ??= {};
134
+ vueOptions.template.compilerOptions ??= {};
135
+ vueOptions.template.compilerOptions.nodeTransforms ??= [];
136
+ vueOptions.template.compilerOptions.nodeTransforms.unshift(viteComarkSlot);
137
+ },
138
+ resolveId(id) {
139
+ if (id === VIRTUAL_COMPONENTS_ID)
140
+ return RESOLVED_COMPONENTS_ID;
141
+ },
142
+ async load(id) {
143
+ if (id !== RESOLVED_COMPONENTS_ID)
144
+ return;
145
+ const files = await resolveProseFiles();
146
+ return generateComponentsModule(files);
147
+ },
148
+ async transform(code) {
149
+ if (!code.includes('createApp') || !code.includes('.mount('))
150
+ return null;
151
+ // Skip if already injected
152
+ if (code.includes(VIRTUAL_COMPONENTS_ID))
153
+ return null;
154
+ const files = await resolveProseFiles();
155
+ if (!files.length)
156
+ return null;
157
+ const injected = `import __comarkProse from ${JSON.stringify(VIRTUAL_COMPONENTS_ID)};\n`
158
+ + code.replace(/\.mount\s*\(/, '.use(__comarkProse).mount(');
159
+ return { code: injected, map: null };
160
+ },
161
+ configureServer(server) {
162
+ if (!proseDir)
163
+ return;
164
+ server.watcher.add(proseDir);
165
+ const invalidate = (file) => {
166
+ invalidateCache(file);
167
+ const mod = server.moduleGraph.getModuleById(RESOLVED_COMPONENTS_ID);
168
+ if (mod)
169
+ server.moduleGraph.invalidateModule(mod);
170
+ };
171
+ server.watcher.on('add', invalidate);
172
+ server.watcher.on('unlink', invalidate);
173
+ },
174
+ };
175
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@comark/vue",
3
+ "type": "module",
4
+ "version": "0.1.0",
5
+ "description": "Vue components for Comark",
6
+ "exports": {
7
+ ".": "./dist/index.js",
8
+ "./vite": "./dist/vite.js",
9
+ "./plugins/*": "./dist/plugins/*.js",
10
+ "./utils": "./dist/utils/index.js",
11
+ "./parse": "./dist/parse.js",
12
+ "./render": "./dist/render.js",
13
+ "./components/*": "./dist/components/*.js"
14
+ },
15
+ "main": "./dist/index.js",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "scripts": {
25
+ "stub": "node ../../scripts/stub.mjs",
26
+ "build": "tsc",
27
+ "dev": "tsc --watch",
28
+ "test": "vitest run",
29
+ "prepack": "tsc",
30
+ "release": "release-it"
31
+ },
32
+ "peerDependencies": {
33
+ "vue": "^3.5.0",
34
+ "beautiful-mermaid": "^1.1.3",
35
+ "katex": "^0.16.33",
36
+ "shiki": "^3.22.0"
37
+ },
38
+ "peerDependenciesMeta": {
39
+ "shiki": {
40
+ "optional": true
41
+ },
42
+ "beautiful-mermaid": {
43
+ "optional": true
44
+ },
45
+ "katex": {
46
+ "optional": true
47
+ }
48
+ },
49
+ "dependencies": {
50
+ "comark": "^0.0.1"
51
+ },
52
+ "devDependencies": {
53
+ "@vue/server-renderer": "^3.5.30",
54
+ "comark": "workspace:*",
55
+ "vitest": "^4.1.1",
56
+ "vue": "^3.5.30"
57
+ }
58
+ }