@vmz/plugin-markdown-it 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,3 @@
1
1
  # @vmz/plugin-markdown-it
2
2
 
3
- Placeholder package (0.0.0). Reserved for the VMZ project.
3
+ VMZ package 0.0.2.
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <div class="markdown-host" html={format(source)}></div>
3
+ </template>
4
+
5
+ <script client>
6
+ import { renderMarkdown } from '@vmz/plugin-markdown-it/runtime';
7
+
8
+ function format(source) {
9
+ try {
10
+ return renderMarkdown(source ?? '');
11
+ } catch {
12
+ return '';
13
+ }
14
+ }
15
+
16
+ export default class MarkdownIt {
17
+ public source: string = '';
18
+ }
19
+ </script>
package/package.json CHANGED
@@ -1,10 +1,37 @@
1
1
  {
2
2
  "name": "@vmz/plugin-markdown-it",
3
- "version": "0.0.0",
4
- "description": "VMZ placeholder — not for production use.",
3
+ "version": "0.0.2",
4
+ "type": "module",
5
+ "description": "VMZ markdown-it adapter — MarkdownIt + engines.markdown registration",
5
6
  "license": "MIT",
6
- "private": false,
7
- "files": [
8
- "README.md"
9
- ]
7
+ "main": "./vmz.plugin.ts",
8
+ "types": "./vmz.plugin.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./vmz.plugin.ts",
12
+ "default": "./vmz.plugin.ts"
13
+ },
14
+ "./runtime": {
15
+ "types": "./runtime.ts",
16
+ "default": "./runtime.ts"
17
+ },
18
+ "./package.json": "./package.json"
19
+ },
20
+ "dependencies": {
21
+ "@vmz/plugin": "0.0.2",
22
+ "markdown-it": "^14.1.0"
23
+ },
24
+ "keywords": [
25
+ "vmz",
26
+ "plugin",
27
+ "markdown",
28
+ "markdown-it"
29
+ ],
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/doki-land/vmz-framework.git"
36
+ }
10
37
  }
package/runtime.ts ADDED
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Deterministic CommonMark-ish subset for documents + `<Markdown>` (D1).
3
+ * HTML / JS / MDX disabled — see 规划设计/vmz/19 §3.
4
+ */
5
+ import MarkdownIt from 'markdown-it';
6
+
7
+ /** @type {import('markdown-it').default | null} */
8
+ let cached = null;
9
+
10
+ function createMd() {
11
+ if (cached) return cached;
12
+ cached = new MarkdownIt({
13
+ html: false,
14
+ linkify: true,
15
+ typographer: false,
16
+ breaks: false,
17
+ });
18
+ return cached;
19
+ }
20
+
21
+ /**
22
+ * @param {string} source
23
+ * @returns {string} HTML fragment (no wrapping document)
24
+ */
25
+ export function renderMarkdown(source) {
26
+ const md = createMd();
27
+ return md.render(String(source ?? ''));
28
+ }
29
+
30
+ /**
31
+ * @param {string} source
32
+ * @returns {{
33
+ * html: string,
34
+ * headings: Array<{ level: number, id: string, text: string }>,
35
+ * links: Array<{ href: string, text: string }>,
36
+ * fences: Array<{ lang: string, info: string, content: string, lineStart: number, lineEnd: number }>
37
+ * }}
38
+ */
39
+ export function analyzeMarkdown(source) {
40
+ const md = createMd();
41
+ const tokens = md.parse(String(source ?? ''), {});
42
+ /** @type {Array<{ level: number, id: string, text: string }>} */
43
+ const headings = [];
44
+ /** @type {Array<{ href: string, text: string }>} */
45
+ const links = [];
46
+ /** @type {Array<{ lang: string, info: string, content: string, lineStart: number, lineEnd: number }>} */
47
+ const fences = [];
48
+ const seenIds = new Set();
49
+
50
+ for (let i = 0; i < tokens.length; i++) {
51
+ const t = tokens[i];
52
+ if (t.type === 'heading_open') {
53
+ const level = Number(String(t.tag || 'h1').slice(1)) || 1;
54
+ const inline = tokens[i + 1];
55
+ const text = inline && inline.type === 'inline' ? inline.content : '';
56
+ let id = slugify(text);
57
+ if (seenIds.has(id)) {
58
+ let n = 2;
59
+ while (seenIds.has(`${id}-${n}`)) n++;
60
+ id = `${id}-${n}`;
61
+ }
62
+ seenIds.add(id);
63
+ headings.push({ level, id, text });
64
+ // Inject id into open token attrs for render.
65
+ t.attrSet('id', id);
66
+ }
67
+ if (t.type === 'fence') {
68
+ const info = String(t.info || '').trim();
69
+ const lang = (info.split(/\s+/)[0] || '').toLowerCase();
70
+ const map = Array.isArray(t.map) ? t.map : [0, 0];
71
+ fences.push({
72
+ lang,
73
+ info,
74
+ content: String(t.content || ''),
75
+ lineStart: map[0] + 1,
76
+ lineEnd: map[1],
77
+ });
78
+ }
79
+ if (t.type === 'inline' && Array.isArray(t.children)) {
80
+ for (const c of t.children) {
81
+ if (c.type === 'link_open') {
82
+ const href = c.attrGet('href') || '';
83
+ links.push({ href, text: '' });
84
+ }
85
+ }
86
+ }
87
+ }
88
+
89
+ const html = md.renderer.render(tokens, md.options, {});
90
+ return { html, headings, links, fences };
91
+ }
92
+
93
+ /** @param {string} text */
94
+ export function slugify(text) {
95
+ return (
96
+ String(text || '')
97
+ .trim()
98
+ .toLowerCase()
99
+ .replace(/[^\p{L}\p{N}\s_-]/gu, '')
100
+ .replace(/\s+/g, '-')
101
+ .replace(/-+/g, '-')
102
+ .replace(/^-|-$/g, '') || 'section'
103
+ );
104
+ }
package/vmz.plugin.ts ADDED
@@ -0,0 +1,50 @@
1
+ import { definePlugin, loadPluginSource } from '@vmz/plugin';
2
+
3
+ const source = loadPluginSource(import.meta.url, 'components/MarkdownIt.vmz');
4
+
5
+ export default definePlugin({
6
+ name: '@vmz/plugin-markdown-it',
7
+ version: '0.1.0',
8
+ protocol: '0.1.0',
9
+ stages: ['workspace_resolve', 'analyzer'],
10
+ deterministic: true,
11
+ async contribute(ctx) {
12
+ if (ctx.stage === 'workspace_resolve') {
13
+ return {
14
+ stage: 'workspace_resolve',
15
+ cacheKey: `@vmz/plugin-markdown-it:MarkdownIt.vmz:${source.contentHash.slice(0, 12)}`,
16
+ items: [
17
+ {
18
+ id: 'component-markdown-it',
19
+ kind: 'source',
20
+ path: 'src/components/MarkdownIt.vmz',
21
+ content: source.content,
22
+ contentHash: source.contentHash,
23
+ materialize: true,
24
+ engine: 'markdown-it',
25
+ engineKind: 'markdown',
26
+ },
27
+ ],
28
+ };
29
+ }
30
+ if (ctx.stage === 'analyzer') {
31
+ return {
32
+ stage: 'analyzer',
33
+ cacheKey: '@vmz/plugin-markdown-it:analyzer',
34
+ items: [
35
+ {
36
+ id: 'engine-markdown-it',
37
+ kind: 'analyzer',
38
+ path: 'src/components/MarkdownIt.vmz',
39
+ severity: 'advice',
40
+ message: 'markdown engine markdown-it online',
41
+ code: 'vmz.engine.markdown-it',
42
+ engine: 'markdown-it',
43
+ engineKind: 'markdown',
44
+ },
45
+ ],
46
+ };
47
+ }
48
+ return { stage: ctx.stage, items: [] };
49
+ },
50
+ });