vue3-markdown-kit 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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - Add a Vue 3.5 Markdown preview component using the Composition API.
6
+ - Preserve the Vue 2 package's preview props, events, theme API, renderer, and sanitizer behavior.
7
+ - Add Vue 3 application-plugin installation and component-mount tests.
8
+ - Add ESM, CommonJS, TypeScript declaration, modern, and compatibility entry points.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 eatmeatHJ
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE.md ADDED
@@ -0,0 +1,16 @@
1
+ # Third-party notices
2
+
3
+ Vue 3 Markdown Kit is distributed under the MIT License.
4
+
5
+ Its runtime dependencies are used through their public APIs and are not copied
6
+ into this repository:
7
+
8
+ - DOMPurify — Mozilla Public License 2.0 or Apache License 2.0
9
+ - highlight.js — BSD 3-Clause License
10
+ - markdown-it — MIT License
11
+ - markdown-it-attrs — MIT License
12
+ - Vue.js — MIT License (peer dependency)
13
+
14
+ The generated JavaScript bundles keep runtime dependencies external. Consumers
15
+ should include the dependency licenses in their own software notices as
16
+ required by their distribution process.
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # Vue 3 Markdown Kit
2
+
3
+ A small, auditable Markdown preview toolkit for Vue 3.5. It provides a
4
+ component-friendly preview API, a framework-independent renderer, and
5
+ GitHub-style presentation.
6
+
7
+ This package is the Vue 3 counterpart of
8
+ [`vue-markdown-kit`](https://github.com/eatmeatHJ/vue-markdown-kit). It keeps
9
+ the same preview props, events, themes, CSS, and import layout while using the
10
+ Vue 3 application and rendering APIs.
11
+
12
+ ## Features
13
+
14
+ - Vue 3.5 preview component built with the Composition API
15
+ - Markdown rendering through markdown-it
16
+ - HTML sanitization through DOMPurify
17
+ - Opt-in, tree-shakeable highlight.js language registration
18
+ - GitHub-style Markdown CSS
19
+ - Image-click and rendered-content events
20
+ - TypeScript declarations and ESM/CommonJS builds
21
+ - Compatibility and modern package entry points
22
+
23
+ ## Requirements
24
+
25
+ - Vue 3.5 or newer
26
+ - Node.js 18 or newer for package tooling
27
+
28
+ ## Install
29
+
30
+ ```sh
31
+ npm install vue3-markdown-kit
32
+ ```
33
+
34
+ ## Recommended usage
35
+
36
+ Configure the theme once in your application entry point:
37
+
38
+ ```ts
39
+ import { createApp } from 'vue'
40
+ import App from './App.vue'
41
+
42
+ import VueMarkdownKit, { VMdPreview, githubTheme } from 'vue3-markdown-kit'
43
+ import 'vue3-markdown-kit/style/preview.css'
44
+ import 'vue3-markdown-kit/theme/style/github.css'
45
+
46
+ VMdPreview.use(githubTheme)
47
+
48
+ createApp(App)
49
+ .use(VueMarkdownKit)
50
+ .mount('#app')
51
+ ```
52
+
53
+ The plugin globally registers `<v-md-preview>`:
54
+
55
+ ```vue
56
+ <script setup lang="ts">
57
+ import { ref } from 'vue'
58
+
59
+ const markdown = ref('# Hello, Vue 3')
60
+
61
+ function handleImageClick(images: string[], index: number) {
62
+ console.log(images[index])
63
+ }
64
+ </script>
65
+
66
+ <template>
67
+ <v-md-preview
68
+ :text="markdown"
69
+ @image-click="handleImageClick"
70
+ />
71
+ </template>
72
+ ```
73
+
74
+ For local registration, import the component directly:
75
+
76
+ ```vue
77
+ <script setup lang="ts">
78
+ import { VMdPreview, githubTheme } from 'vue3-markdown-kit'
79
+ import 'vue3-markdown-kit/style/preview.css'
80
+ import 'vue3-markdown-kit/theme/style/github.css'
81
+
82
+ VMdPreview.use(githubTheme)
83
+
84
+ const markdown = '# Locally registered component'
85
+ </script>
86
+
87
+ <template>
88
+ <VMdPreview :text="markdown" />
89
+ </template>
90
+ ```
91
+
92
+ ## highlight.js
93
+
94
+ Register only the languages your application uses:
95
+
96
+ ```ts
97
+ import { VMdPreview, githubTheme } from 'vue3-markdown-kit'
98
+ import hljs from 'highlight.js/lib/core'
99
+ import javascript from 'highlight.js/lib/languages/javascript'
100
+
101
+ hljs.registerLanguage('javascript', javascript)
102
+
103
+ VMdPreview.use(githubTheme, {
104
+ Hljs: hljs,
105
+ })
106
+ ```
107
+
108
+ ## Compatibility entry points
109
+
110
+ Integrations migrating from the Vue 2 package can retain the old import
111
+ layout and change only the package name:
112
+
113
+ ```ts
114
+ import VMdPreview from 'vue3-markdown-kit/lib/preview'
115
+ import 'vue3-markdown-kit/lib/style/preview.css'
116
+
117
+ import githubTheme from 'vue3-markdown-kit/lib/theme/github.js'
118
+ import 'vue3-markdown-kit/lib/theme/style/github.css'
119
+
120
+ VMdPreview.use(githubTheme)
121
+ ```
122
+
123
+ Vue 3 uses `createApp(...).use(...)`; replace any Vue 2 `Vue.use(...)`,
124
+ `Vue.extend(...)`, `$mount()`, `$on()`, and `$destroy()` integration code with
125
+ their Vue 3 equivalents.
126
+
127
+ ## Framework-independent renderer
128
+
129
+ The renderer and sanitizer can be used without mounting a Vue component:
130
+
131
+ ```ts
132
+ import {
133
+ createMarkdownRenderer,
134
+ sanitizeHtml,
135
+ } from 'vue3-markdown-kit/core'
136
+
137
+ const parser = createMarkdownRenderer()
138
+ const safeHtml = sanitizeHtml(parser.render('# Hello'))
139
+ ```
140
+
141
+ ## Preview props
142
+
143
+ | Prop | Type | Default | Description |
144
+ | --- | --- | --- | --- |
145
+ | `text` | `string` | `''` | Markdown source |
146
+ | `theme` | `object` | `undefined` | Per-instance theme plugin or theme config |
147
+ | `tabSize` | `number` | `2` | CSS tab size |
148
+ | `scrollContainer` | `function` | `() => window` | Scroll target retained for API compatibility |
149
+ | `top` | `number` | `0` | Scroll offset retained for API compatibility |
150
+ | `sanitizeOptions` | `object` | `{}` | Additional DOMPurify options |
151
+
152
+ ## Events
153
+
154
+ - `change(text, html)` fires after Markdown is rendered and sanitized.
155
+ - `image-click(images, index)` fires when a rendered image is clicked.
156
+
157
+ ## Security
158
+
159
+ Raw HTML is enabled for compatibility, then sanitized as the final rendering
160
+ step. Applications that do not need raw HTML can pass `html: false` when
161
+ creating a custom renderer. Keep all runtime dependencies updated and apply
162
+ an application-level Markdown input length limit.
163
+
164
+ ## Development
165
+
166
+ ```sh
167
+ npm ci
168
+ npm test
169
+ npm run check
170
+ ```
171
+
172
+ The generated `lib` directory is committed so the package can also be
173
+ installed directly from GitHub.
174
+
175
+ ## License
176
+
177
+ MIT. See [LICENSE](LICENSE) and [NOTICE.md](NOTICE.md).
package/SECURITY.md ADDED
@@ -0,0 +1,14 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Only the latest released minor version receives security updates.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ Please report suspected vulnerabilities privately through GitHub's private
10
+ vulnerability reporting feature. Do not include exploit details in a public
11
+ issue before a fix is available.
12
+
13
+ Markdown rendering is performed in the browser. Rendered HTML is sanitized by
14
+ DOMPurify before it reaches Vue's `innerHTML` render property.
package/lib/core.cjs ADDED
@@ -0,0 +1,197 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/core/index.js
30
+ var core_exports = {};
31
+ __export(core_exports, {
32
+ createMarkdownRenderer: () => createMarkdownRenderer,
33
+ sanitizeHtml: () => sanitizeHtml,
34
+ sanitizer: () => sanitizer,
35
+ slugifyHeading: () => slugifyHeading
36
+ });
37
+ module.exports = __toCommonJS(core_exports);
38
+
39
+ // src/core/renderer.js
40
+ var import_markdown_it = __toESM(require("markdown-it"), 1);
41
+ var import_markdown_it_attrs = __toESM(require("markdown-it-attrs"), 1);
42
+ function escapeHtml(value) {
43
+ return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
44
+ }
45
+ function slugifyHeading(value) {
46
+ const slug = String(value || "").normalize("NFKC").trim().toLowerCase().replace(/\s+/g, "-").replace(/[^\p{Letter}\p{Number}_-]+/gu, "").replace(/-{2,}/g, "-").replace(/^-|-$/g, "");
47
+ return slug || "section";
48
+ }
49
+ function highlightCode(code, language, options) {
50
+ const {
51
+ Hljs,
52
+ codeHighlightExtensionMap = {},
53
+ codeBlockClass = (lang) => `v-md-hljs-${lang || ""}`
54
+ } = options;
55
+ const normalizedLanguage = codeHighlightExtensionMap[language] || language;
56
+ let highlighted = escapeHtml(code);
57
+ if (Hljs && normalizedLanguage && typeof Hljs.getLanguage === "function" && Hljs.getLanguage(normalizedLanguage)) {
58
+ try {
59
+ highlighted = Hljs.highlight(code, {
60
+ language: normalizedLanguage,
61
+ ignoreIllegals: true
62
+ }).value;
63
+ } catch {
64
+ highlighted = Hljs.highlight(normalizedLanguage, code, true).value;
65
+ }
66
+ }
67
+ return `<pre class="${escapeHtml(codeBlockClass(normalizedLanguage))}"><code>${highlighted}</code></pre>`;
68
+ }
69
+ function installHeadingAnchors(parser) {
70
+ parser.core.ruler.before("block", "vue_markdown_kit_heading_state", (state) => {
71
+ state.env.__vueMarkdownKitHeadingSlugs = /* @__PURE__ */ new Map();
72
+ });
73
+ const fallback = parser.renderer.rules.heading_open || ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options));
74
+ parser.renderer.rules.heading_open = (tokens, index, options, env, self) => {
75
+ const inline = tokens[index + 1];
76
+ const baseSlug = slugifyHeading(inline && inline.content);
77
+ const slugs = env.__vueMarkdownKitHeadingSlugs || /* @__PURE__ */ new Map();
78
+ const count = slugs.get(baseSlug) || 0;
79
+ const slug = count === 0 ? baseSlug : `${baseSlug}-${count}`;
80
+ slugs.set(baseSlug, count + 1);
81
+ env.__vueMarkdownKitHeadingSlugs = slugs;
82
+ tokens[index].attrSet("id", slug);
83
+ tokens[index].attrSet("data-v-md-heading", slug);
84
+ return fallback(tokens, index, options, env, self);
85
+ };
86
+ }
87
+ function installSafeExternalLinks(parser) {
88
+ const fallback = parser.renderer.rules.link_open || ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options));
89
+ parser.renderer.rules.link_open = (tokens, index, options, env, self) => {
90
+ const token = tokens[index];
91
+ const href = token.attrGet("href") || "";
92
+ if (/^https?:\/\//i.test(href)) {
93
+ token.attrSet("target", "_blank");
94
+ token.attrSet("rel", "noopener noreferrer");
95
+ }
96
+ return fallback(tokens, index, options, env, self);
97
+ };
98
+ }
99
+ function createMarkdownRenderer(options = {}) {
100
+ var _a, _b, _c, _d;
101
+ const parser = new import_markdown_it.default({
102
+ html: (_a = options.html) != null ? _a : true,
103
+ breaks: (_b = options.breaks) != null ? _b : true,
104
+ linkify: (_c = options.linkify) != null ? _c : false,
105
+ typographer: (_d = options.typographer) != null ? _d : true,
106
+ highlight: (code, language) => highlightCode(code, language, options)
107
+ });
108
+ if (options.attrs !== false) {
109
+ parser.use(import_markdown_it_attrs.default, {
110
+ leftDelimiter: "{{{",
111
+ rightDelimiter: "}}}",
112
+ allowedAttributes: [
113
+ "class",
114
+ "height",
115
+ "id",
116
+ "title",
117
+ "width",
118
+ ...options.allowedAttributes || []
119
+ ]
120
+ });
121
+ }
122
+ installHeadingAnchors(parser);
123
+ installSafeExternalLinks(parser);
124
+ return parser;
125
+ }
126
+
127
+ // src/core/sanitize.js
128
+ var import_dompurify = __toESM(require("dompurify"), 1);
129
+ var BASE_SANITIZE_OPTIONS = Object.freeze({
130
+ USE_PROFILES: {
131
+ html: true
132
+ },
133
+ ADD_ATTR: [
134
+ "data-mention-id",
135
+ "data-v-md-anchor",
136
+ "data-v-md-heading",
137
+ "data-v-md-line",
138
+ "rel",
139
+ "target"
140
+ ],
141
+ FORBID_TAGS: ["script"]
142
+ });
143
+ var sharedOptions = {};
144
+ function mergeOptions(base, extra) {
145
+ const merged = {
146
+ ...base,
147
+ ...extra
148
+ };
149
+ for (const key of ["ADD_ATTR", "ADD_TAGS", "FORBID_ATTR", "FORBID_TAGS"]) {
150
+ if (base[key] || extra[key]) {
151
+ merged[key] = [.../* @__PURE__ */ new Set([...base[key] || [], ...extra[key] || []])];
152
+ }
153
+ }
154
+ if (base.USE_PROFILES || extra.USE_PROFILES) {
155
+ merged.USE_PROFILES = {
156
+ ...base.USE_PROFILES || {},
157
+ ...extra.USE_PROFILES || {}
158
+ };
159
+ }
160
+ return merged;
161
+ }
162
+ function resolvePurifier(windowLike) {
163
+ if (typeof import_dompurify.default.sanitize === "function") {
164
+ return import_dompurify.default;
165
+ }
166
+ if (windowLike && typeof import_dompurify.default === "function") {
167
+ return (0, import_dompurify.default)(windowLike);
168
+ }
169
+ return null;
170
+ }
171
+ function escapeHtml2(value) {
172
+ return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
173
+ }
174
+ function sanitizeHtml(dirtyHtml, options = {}, windowLike = typeof window === "undefined" ? void 0 : window) {
175
+ const purifier = resolvePurifier(windowLike);
176
+ if (!purifier || typeof purifier.sanitize !== "function") {
177
+ return escapeHtml2(dirtyHtml || "");
178
+ }
179
+ return purifier.sanitize(
180
+ dirtyHtml || "",
181
+ mergeOptions(mergeOptions(BASE_SANITIZE_OPTIONS, sharedOptions), options)
182
+ );
183
+ }
184
+ var sanitizer = {
185
+ process(dirtyHtml, options) {
186
+ return sanitizeHtml(dirtyHtml, options);
187
+ },
188
+ extend(options = {}) {
189
+ sharedOptions = mergeOptions(sharedOptions, options);
190
+ return this;
191
+ },
192
+ reset() {
193
+ sharedOptions = {};
194
+ return this;
195
+ }
196
+ };
197
+ //# sourceMappingURL=core.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/index.js", "../src/core/renderer.js", "../src/core/sanitize.js"],
4
+ "sourcesContent": ["export { createMarkdownRenderer, slugifyHeading } from './renderer.js'\nexport { sanitizeHtml, sanitizer } from './sanitize.js'\n", "import MarkdownIt from 'markdown-it'\nimport markdownItAttrs from 'markdown-it-attrs'\n\nfunction escapeHtml(value) {\n return String(value)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n\nexport function slugifyHeading(value) {\n const slug = String(value || '')\n .normalize('NFKC')\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^\\p{Letter}\\p{Number}_-]+/gu, '')\n .replace(/-{2,}/g, '-')\n .replace(/^-|-$/g, '')\n\n return slug || 'section'\n}\n\nfunction highlightCode(code, language, options) {\n const {\n Hljs,\n codeHighlightExtensionMap = {},\n codeBlockClass = (lang) => `v-md-hljs-${lang || ''}`,\n } = options\n\n const normalizedLanguage = codeHighlightExtensionMap[language] || language\n let highlighted = escapeHtml(code)\n\n if (\n Hljs &&\n normalizedLanguage &&\n typeof Hljs.getLanguage === 'function' &&\n Hljs.getLanguage(normalizedLanguage)\n ) {\n try {\n highlighted = Hljs.highlight(code, {\n language: normalizedLanguage,\n ignoreIllegals: true,\n }).value\n } catch {\n // highlight.js 10 compatibility.\n highlighted = Hljs.highlight(normalizedLanguage, code, true).value\n }\n }\n\n return `<pre class=\"${escapeHtml(codeBlockClass(normalizedLanguage))}\"><code>${highlighted}</code></pre>`\n}\n\nfunction installHeadingAnchors(parser) {\n parser.core.ruler.before('block', 'vue_markdown_kit_heading_state', (state) => {\n state.env.__vueMarkdownKitHeadingSlugs = new Map()\n })\n\n const fallback =\n parser.renderer.rules.heading_open ||\n ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options))\n\n parser.renderer.rules.heading_open = (tokens, index, options, env, self) => {\n const inline = tokens[index + 1]\n const baseSlug = slugifyHeading(inline && inline.content)\n const slugs = env.__vueMarkdownKitHeadingSlugs || new Map()\n const count = slugs.get(baseSlug) || 0\n const slug = count === 0 ? baseSlug : `${baseSlug}-${count}`\n\n slugs.set(baseSlug, count + 1)\n env.__vueMarkdownKitHeadingSlugs = slugs\n\n tokens[index].attrSet('id', slug)\n tokens[index].attrSet('data-v-md-heading', slug)\n\n return fallback(tokens, index, options, env, self)\n }\n}\n\nfunction installSafeExternalLinks(parser) {\n const fallback =\n parser.renderer.rules.link_open ||\n ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options))\n\n parser.renderer.rules.link_open = (tokens, index, options, env, self) => {\n const token = tokens[index]\n const href = token.attrGet('href') || ''\n\n if (/^https?:\\/\\//i.test(href)) {\n token.attrSet('target', '_blank')\n token.attrSet('rel', 'noopener noreferrer')\n }\n\n return fallback(tokens, index, options, env, self)\n }\n}\n\nexport function createMarkdownRenderer(options = {}) {\n const parser = new MarkdownIt({\n html: options.html ?? true,\n breaks: options.breaks ?? true,\n linkify: options.linkify ?? false,\n typographer: options.typographer ?? true,\n highlight: (code, language) => highlightCode(code, language, options),\n })\n\n if (options.attrs !== false) {\n parser.use(markdownItAttrs, {\n leftDelimiter: '{{{',\n rightDelimiter: '}}}',\n allowedAttributes: [\n 'class',\n 'height',\n 'id',\n 'title',\n 'width',\n ...(options.allowedAttributes || []),\n ],\n })\n }\n\n installHeadingAnchors(parser)\n installSafeExternalLinks(parser)\n\n return parser\n}\n", "import createDOMPurify from 'dompurify'\n\nconst BASE_SANITIZE_OPTIONS = Object.freeze({\n USE_PROFILES: {\n html: true,\n },\n ADD_ATTR: [\n 'data-mention-id',\n 'data-v-md-anchor',\n 'data-v-md-heading',\n 'data-v-md-line',\n 'rel',\n 'target',\n ],\n FORBID_TAGS: ['script'],\n})\n\nlet sharedOptions = {}\n\nfunction mergeOptions(base, extra) {\n const merged = {\n ...base,\n ...extra,\n }\n\n for (const key of ['ADD_ATTR', 'ADD_TAGS', 'FORBID_ATTR', 'FORBID_TAGS']) {\n if (base[key] || extra[key]) {\n merged[key] = [...new Set([...(base[key] || []), ...(extra[key] || [])])]\n }\n }\n\n if (base.USE_PROFILES || extra.USE_PROFILES) {\n merged.USE_PROFILES = {\n ...(base.USE_PROFILES || {}),\n ...(extra.USE_PROFILES || {}),\n }\n }\n\n return merged\n}\n\nfunction resolvePurifier(windowLike) {\n if (typeof createDOMPurify.sanitize === 'function') {\n return createDOMPurify\n }\n\n if (windowLike && typeof createDOMPurify === 'function') {\n return createDOMPurify(windowLike)\n }\n\n return null\n}\n\nfunction escapeHtml(value) {\n return String(value)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n}\n\nexport function sanitizeHtml(\n dirtyHtml,\n options = {},\n windowLike = typeof window === 'undefined' ? undefined : window,\n) {\n const purifier = resolvePurifier(windowLike)\n\n // Fail closed in non-DOM environments rather than returning executable HTML.\n if (!purifier || typeof purifier.sanitize !== 'function') {\n return escapeHtml(dirtyHtml || '')\n }\n\n return purifier.sanitize(\n dirtyHtml || '',\n mergeOptions(mergeOptions(BASE_SANITIZE_OPTIONS, sharedOptions), options),\n )\n}\n\nexport const sanitizer = {\n process(dirtyHtml, options) {\n return sanitizeHtml(dirtyHtml, options)\n },\n\n extend(options = {}) {\n sharedOptions = mergeOptions(sharedOptions, options)\n return this\n },\n\n reset() {\n sharedOptions = {}\n return this\n },\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["MarkdownIt", "markdownItAttrs", "createDOMPurify", "escapeHtml"]
7
+ }
package/lib/core.js ADDED
@@ -0,0 +1,165 @@
1
+ // src/core/renderer.js
2
+ import MarkdownIt from "markdown-it";
3
+ import markdownItAttrs from "markdown-it-attrs";
4
+ function escapeHtml(value) {
5
+ return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
6
+ }
7
+ function slugifyHeading(value) {
8
+ const slug = String(value || "").normalize("NFKC").trim().toLowerCase().replace(/\s+/g, "-").replace(/[^\p{Letter}\p{Number}_-]+/gu, "").replace(/-{2,}/g, "-").replace(/^-|-$/g, "");
9
+ return slug || "section";
10
+ }
11
+ function highlightCode(code, language, options) {
12
+ const {
13
+ Hljs,
14
+ codeHighlightExtensionMap = {},
15
+ codeBlockClass = (lang) => `v-md-hljs-${lang || ""}`
16
+ } = options;
17
+ const normalizedLanguage = codeHighlightExtensionMap[language] || language;
18
+ let highlighted = escapeHtml(code);
19
+ if (Hljs && normalizedLanguage && typeof Hljs.getLanguage === "function" && Hljs.getLanguage(normalizedLanguage)) {
20
+ try {
21
+ highlighted = Hljs.highlight(code, {
22
+ language: normalizedLanguage,
23
+ ignoreIllegals: true
24
+ }).value;
25
+ } catch {
26
+ highlighted = Hljs.highlight(normalizedLanguage, code, true).value;
27
+ }
28
+ }
29
+ return `<pre class="${escapeHtml(codeBlockClass(normalizedLanguage))}"><code>${highlighted}</code></pre>`;
30
+ }
31
+ function installHeadingAnchors(parser) {
32
+ parser.core.ruler.before("block", "vue_markdown_kit_heading_state", (state) => {
33
+ state.env.__vueMarkdownKitHeadingSlugs = /* @__PURE__ */ new Map();
34
+ });
35
+ const fallback = parser.renderer.rules.heading_open || ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options));
36
+ parser.renderer.rules.heading_open = (tokens, index, options, env, self) => {
37
+ const inline = tokens[index + 1];
38
+ const baseSlug = slugifyHeading(inline && inline.content);
39
+ const slugs = env.__vueMarkdownKitHeadingSlugs || /* @__PURE__ */ new Map();
40
+ const count = slugs.get(baseSlug) || 0;
41
+ const slug = count === 0 ? baseSlug : `${baseSlug}-${count}`;
42
+ slugs.set(baseSlug, count + 1);
43
+ env.__vueMarkdownKitHeadingSlugs = slugs;
44
+ tokens[index].attrSet("id", slug);
45
+ tokens[index].attrSet("data-v-md-heading", slug);
46
+ return fallback(tokens, index, options, env, self);
47
+ };
48
+ }
49
+ function installSafeExternalLinks(parser) {
50
+ const fallback = parser.renderer.rules.link_open || ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options));
51
+ parser.renderer.rules.link_open = (tokens, index, options, env, self) => {
52
+ const token = tokens[index];
53
+ const href = token.attrGet("href") || "";
54
+ if (/^https?:\/\//i.test(href)) {
55
+ token.attrSet("target", "_blank");
56
+ token.attrSet("rel", "noopener noreferrer");
57
+ }
58
+ return fallback(tokens, index, options, env, self);
59
+ };
60
+ }
61
+ function createMarkdownRenderer(options = {}) {
62
+ var _a, _b, _c, _d;
63
+ const parser = new MarkdownIt({
64
+ html: (_a = options.html) != null ? _a : true,
65
+ breaks: (_b = options.breaks) != null ? _b : true,
66
+ linkify: (_c = options.linkify) != null ? _c : false,
67
+ typographer: (_d = options.typographer) != null ? _d : true,
68
+ highlight: (code, language) => highlightCode(code, language, options)
69
+ });
70
+ if (options.attrs !== false) {
71
+ parser.use(markdownItAttrs, {
72
+ leftDelimiter: "{{{",
73
+ rightDelimiter: "}}}",
74
+ allowedAttributes: [
75
+ "class",
76
+ "height",
77
+ "id",
78
+ "title",
79
+ "width",
80
+ ...options.allowedAttributes || []
81
+ ]
82
+ });
83
+ }
84
+ installHeadingAnchors(parser);
85
+ installSafeExternalLinks(parser);
86
+ return parser;
87
+ }
88
+
89
+ // src/core/sanitize.js
90
+ import createDOMPurify from "dompurify";
91
+ var BASE_SANITIZE_OPTIONS = Object.freeze({
92
+ USE_PROFILES: {
93
+ html: true
94
+ },
95
+ ADD_ATTR: [
96
+ "data-mention-id",
97
+ "data-v-md-anchor",
98
+ "data-v-md-heading",
99
+ "data-v-md-line",
100
+ "rel",
101
+ "target"
102
+ ],
103
+ FORBID_TAGS: ["script"]
104
+ });
105
+ var sharedOptions = {};
106
+ function mergeOptions(base, extra) {
107
+ const merged = {
108
+ ...base,
109
+ ...extra
110
+ };
111
+ for (const key of ["ADD_ATTR", "ADD_TAGS", "FORBID_ATTR", "FORBID_TAGS"]) {
112
+ if (base[key] || extra[key]) {
113
+ merged[key] = [.../* @__PURE__ */ new Set([...base[key] || [], ...extra[key] || []])];
114
+ }
115
+ }
116
+ if (base.USE_PROFILES || extra.USE_PROFILES) {
117
+ merged.USE_PROFILES = {
118
+ ...base.USE_PROFILES || {},
119
+ ...extra.USE_PROFILES || {}
120
+ };
121
+ }
122
+ return merged;
123
+ }
124
+ function resolvePurifier(windowLike) {
125
+ if (typeof createDOMPurify.sanitize === "function") {
126
+ return createDOMPurify;
127
+ }
128
+ if (windowLike && typeof createDOMPurify === "function") {
129
+ return createDOMPurify(windowLike);
130
+ }
131
+ return null;
132
+ }
133
+ function escapeHtml2(value) {
134
+ return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
135
+ }
136
+ function sanitizeHtml(dirtyHtml, options = {}, windowLike = typeof window === "undefined" ? void 0 : window) {
137
+ const purifier = resolvePurifier(windowLike);
138
+ if (!purifier || typeof purifier.sanitize !== "function") {
139
+ return escapeHtml2(dirtyHtml || "");
140
+ }
141
+ return purifier.sanitize(
142
+ dirtyHtml || "",
143
+ mergeOptions(mergeOptions(BASE_SANITIZE_OPTIONS, sharedOptions), options)
144
+ );
145
+ }
146
+ var sanitizer = {
147
+ process(dirtyHtml, options) {
148
+ return sanitizeHtml(dirtyHtml, options);
149
+ },
150
+ extend(options = {}) {
151
+ sharedOptions = mergeOptions(sharedOptions, options);
152
+ return this;
153
+ },
154
+ reset() {
155
+ sharedOptions = {};
156
+ return this;
157
+ }
158
+ };
159
+ export {
160
+ createMarkdownRenderer,
161
+ sanitizeHtml,
162
+ sanitizer,
163
+ slugifyHeading
164
+ };
165
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/renderer.js", "../src/core/sanitize.js"],
4
+ "sourcesContent": ["import MarkdownIt from 'markdown-it'\nimport markdownItAttrs from 'markdown-it-attrs'\n\nfunction escapeHtml(value) {\n return String(value)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n\nexport function slugifyHeading(value) {\n const slug = String(value || '')\n .normalize('NFKC')\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^\\p{Letter}\\p{Number}_-]+/gu, '')\n .replace(/-{2,}/g, '-')\n .replace(/^-|-$/g, '')\n\n return slug || 'section'\n}\n\nfunction highlightCode(code, language, options) {\n const {\n Hljs,\n codeHighlightExtensionMap = {},\n codeBlockClass = (lang) => `v-md-hljs-${lang || ''}`,\n } = options\n\n const normalizedLanguage = codeHighlightExtensionMap[language] || language\n let highlighted = escapeHtml(code)\n\n if (\n Hljs &&\n normalizedLanguage &&\n typeof Hljs.getLanguage === 'function' &&\n Hljs.getLanguage(normalizedLanguage)\n ) {\n try {\n highlighted = Hljs.highlight(code, {\n language: normalizedLanguage,\n ignoreIllegals: true,\n }).value\n } catch {\n // highlight.js 10 compatibility.\n highlighted = Hljs.highlight(normalizedLanguage, code, true).value\n }\n }\n\n return `<pre class=\"${escapeHtml(codeBlockClass(normalizedLanguage))}\"><code>${highlighted}</code></pre>`\n}\n\nfunction installHeadingAnchors(parser) {\n parser.core.ruler.before('block', 'vue_markdown_kit_heading_state', (state) => {\n state.env.__vueMarkdownKitHeadingSlugs = new Map()\n })\n\n const fallback =\n parser.renderer.rules.heading_open ||\n ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options))\n\n parser.renderer.rules.heading_open = (tokens, index, options, env, self) => {\n const inline = tokens[index + 1]\n const baseSlug = slugifyHeading(inline && inline.content)\n const slugs = env.__vueMarkdownKitHeadingSlugs || new Map()\n const count = slugs.get(baseSlug) || 0\n const slug = count === 0 ? baseSlug : `${baseSlug}-${count}`\n\n slugs.set(baseSlug, count + 1)\n env.__vueMarkdownKitHeadingSlugs = slugs\n\n tokens[index].attrSet('id', slug)\n tokens[index].attrSet('data-v-md-heading', slug)\n\n return fallback(tokens, index, options, env, self)\n }\n}\n\nfunction installSafeExternalLinks(parser) {\n const fallback =\n parser.renderer.rules.link_open ||\n ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options))\n\n parser.renderer.rules.link_open = (tokens, index, options, env, self) => {\n const token = tokens[index]\n const href = token.attrGet('href') || ''\n\n if (/^https?:\\/\\//i.test(href)) {\n token.attrSet('target', '_blank')\n token.attrSet('rel', 'noopener noreferrer')\n }\n\n return fallback(tokens, index, options, env, self)\n }\n}\n\nexport function createMarkdownRenderer(options = {}) {\n const parser = new MarkdownIt({\n html: options.html ?? true,\n breaks: options.breaks ?? true,\n linkify: options.linkify ?? false,\n typographer: options.typographer ?? true,\n highlight: (code, language) => highlightCode(code, language, options),\n })\n\n if (options.attrs !== false) {\n parser.use(markdownItAttrs, {\n leftDelimiter: '{{{',\n rightDelimiter: '}}}',\n allowedAttributes: [\n 'class',\n 'height',\n 'id',\n 'title',\n 'width',\n ...(options.allowedAttributes || []),\n ],\n })\n }\n\n installHeadingAnchors(parser)\n installSafeExternalLinks(parser)\n\n return parser\n}\n", "import createDOMPurify from 'dompurify'\n\nconst BASE_SANITIZE_OPTIONS = Object.freeze({\n USE_PROFILES: {\n html: true,\n },\n ADD_ATTR: [\n 'data-mention-id',\n 'data-v-md-anchor',\n 'data-v-md-heading',\n 'data-v-md-line',\n 'rel',\n 'target',\n ],\n FORBID_TAGS: ['script'],\n})\n\nlet sharedOptions = {}\n\nfunction mergeOptions(base, extra) {\n const merged = {\n ...base,\n ...extra,\n }\n\n for (const key of ['ADD_ATTR', 'ADD_TAGS', 'FORBID_ATTR', 'FORBID_TAGS']) {\n if (base[key] || extra[key]) {\n merged[key] = [...new Set([...(base[key] || []), ...(extra[key] || [])])]\n }\n }\n\n if (base.USE_PROFILES || extra.USE_PROFILES) {\n merged.USE_PROFILES = {\n ...(base.USE_PROFILES || {}),\n ...(extra.USE_PROFILES || {}),\n }\n }\n\n return merged\n}\n\nfunction resolvePurifier(windowLike) {\n if (typeof createDOMPurify.sanitize === 'function') {\n return createDOMPurify\n }\n\n if (windowLike && typeof createDOMPurify === 'function') {\n return createDOMPurify(windowLike)\n }\n\n return null\n}\n\nfunction escapeHtml(value) {\n return String(value)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n}\n\nexport function sanitizeHtml(\n dirtyHtml,\n options = {},\n windowLike = typeof window === 'undefined' ? undefined : window,\n) {\n const purifier = resolvePurifier(windowLike)\n\n // Fail closed in non-DOM environments rather than returning executable HTML.\n if (!purifier || typeof purifier.sanitize !== 'function') {\n return escapeHtml(dirtyHtml || '')\n }\n\n return purifier.sanitize(\n dirtyHtml || '',\n mergeOptions(mergeOptions(BASE_SANITIZE_OPTIONS, sharedOptions), options),\n )\n}\n\nexport const sanitizer = {\n process(dirtyHtml, options) {\n return sanitizeHtml(dirtyHtml, options)\n },\n\n extend(options = {}) {\n sharedOptions = mergeOptions(sharedOptions, options)\n return this\n },\n\n reset() {\n sharedOptions = {}\n return this\n },\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["escapeHtml"]
7
+ }