vite-plugin-svelte-md 0.3.0 → 0.4.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/README.md CHANGED
@@ -16,7 +16,7 @@ _`vite-plugin-svelte-md` is heavily inspired by [vite-plugin-md](https://github.
16
16
 
17
17
  ## 📛 Features
18
18
 
19
- This plugin converts markdown files to Svelte component templates.
19
+ This plugin converts markdown files to Svelte component templates.<br>
20
20
  Combined with [the Svelte plugin](https://github.com/sveltejs/vite-plugin-svelte), you can convert markdown files to Svelte components.
21
21
 
22
22
  For example, Input:
@@ -135,6 +135,7 @@ import svelteMd from "vite-plugin-svelte-md";
135
135
  svelteMd({
136
136
  headEnabled: true,
137
137
  markdownItOptions: {},
138
+ use: (md) => { /* ... */ },
138
139
  markdownItUses: [],
139
140
  wrapperClasses: "markdown-body",
140
141
  });
@@ -146,12 +147,28 @@ Enables head tag generation from frontmatter. The default is `true`.
146
147
 
147
148
  #### `markdownItOptions`
148
149
 
149
- [markdown-it](https://github.com/markdown-it/markdown-it)'s option.
150
- See [markdown-it's docs](https://markdown-it.github.io/markdown-it/) for more details.
150
+ [markdown-exit](https://github.com/serkodev/markdown-exit)'s option.
151
+ See [markdown-exit's docs](https://markdown-exit.pages.dev/reference/api/Interface.MarkdownExitOptions.html) for more details.
152
+
153
+ markdown-exit is a TypeScript rewrite of [markdown-it](https://github.com/markdown-it/markdown-it), designed as a drop-in replacement. The name `markdownItOptions` was preserved for backwards compatibility.
154
+
155
+ #### `use`
156
+
157
+ A hook to register [markdown-exit](https://github.com/serkodev/markdown-exit) or [markdown-it](https://github.com/markdown-it/markdown-it) plugins, in a type-safe way.
158
+
159
+ Example:
160
+
161
+ ```js
162
+ svelteMd({
163
+ use: (md) => md.use(plugin1).use(plugin2, options),
164
+ });
165
+ ```
166
+
167
+ Note: you may encounter benign type errors when using markdown-it plugins that are not yet compatible with markdown-exit.
151
168
 
152
169
  #### `markdownItUses`
153
170
 
154
- An array of [markdown-it](https://github.com/markdown-it/markdown-it)'s plugins.
171
+ An array of [markdown-exit](https://github.com/serkodev/markdown-exit) or [markdown-it](https://github.com/markdown-it/markdown-it) plugins.
155
172
 
156
173
  Example:
157
174
 
@@ -161,10 +178,112 @@ svelteMd({
161
178
  });
162
179
  ```
163
180
 
181
+ You should favor `use` over `markdownItUses` as it enables better auto-completion and type-safety.
182
+
164
183
  #### `wrapperClasses`
165
184
 
166
185
  The class name of the div that wraps the content.
167
186
 
187
+ ## 🎏 Comparison
188
+
189
+ `vite-plugin-svelte-md` is not the only library that converts Markdown to Svelte components:
190
+
191
+ <table>
192
+ <tr>
193
+ <th></th>
194
+ <th>
195
+ <a href="https://github.com/ota-meshi/vite-plugin-svelte-md">ota-meshi/vite-plugin-svelte-md</a>
196
+ </th>
197
+ <th>
198
+ <a href="https://github.com/pngwn/MDsveX">pngwn/MDsveX</a>
199
+ </th>
200
+ </tr>
201
+ <tr>
202
+ <td>Popularity</td>
203
+ <td><a href="https://npmx.dev/package/vite-plugin-svelte-md"><img alt="NPM Downloads" src="https://img.shields.io/npm/dw/vite-plugin-svelte-md?style=flat-square&color=d73d36"></a> <a href="https://github.com/ota-meshi/vite-plugin-svelte-md"><img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/ota-meshi/vite-plugin-svelte-md?style=flat-square&color=eac54f"></a></td>
204
+ <td><a href="https://npmx.dev/package/mdsvex"><img alt="NPM Downloads" src="https://img.shields.io/npm/dw/mdsvex?style=flat-square&color=d73d36"></a> <a href="https://github.com/pngwn/MDsveX"><img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/pngwn/MDsveX?style=flat-square&color=eac54f"></a></td>
205
+ </tr>
206
+ <tr>
207
+ <td>License</td>
208
+ <td><a href="https://github.com/ota-meshi/vite-plugin-svelte-md/blob/main/LICENSE">MIT</a></td>
209
+ <td><a href="https://github.com/pngwn/MDsveX/blob/main/LICENSE">MIT</a></td>
210
+ </tr>
211
+ <tr>
212
+ <th colspan="3">Architecture</th>
213
+ </tr>
214
+ <tr>
215
+ <td>Markdown parser</td>
216
+ <td><a href="https://npmx.dev/package/markdown-exit">markdown-exit</a> (supports sync and async plugins)</td>
217
+ <td><a href="https://npmx.dev/package/remark">remark</a> + <a href="https://npmx.dev/package/rehype">rehype</a> (supports plugins)</td>
218
+ </tr>
219
+ <tr>
220
+ <td>Transformation step</td>
221
+ <td>Vite plugin (compatible with other Vite plugins, e.g. <a href="https://svelte.dev/docs/kit/images#sveltejs-enhanced-img"><code>@sveltejs/enhanced-img</code></a>)</td>
222
+ <td>Svelte preprocessor</td>
223
+ </tr>
224
+ <tr>
225
+ <th colspan="3">Features</th>
226
+ </tr>
227
+ <tr>
228
+ <td>Frontmatter</td>
229
+ <td><a href="https://npmx.dev/package/gray-matter">✅ (YAML, JSON or JS)</a><br>
230
+ Accessible through <code>{frontmatter.variable}</code></td>
231
+ <td>✅ (YAML, <a href="https://mdsvex.pngwn.io/docs#frontmatter">can be changed</a>)<br>
232
+ Accessible through <code>{variable}</code>
233
+ </td>
234
+ </tr>
235
+ <tr>
236
+ <td><code>&lt;head></code> tag generation</td>
237
+ <td>✅ (from frontmatter, <a href="#headenabled">can be disabled</a>)</td>
238
+ <td>⚙️ (possible with layouts)</td>
239
+ </tr>
240
+ <tr>
241
+ <td>Syntax highlighting</td>
242
+ <td>⚙️ (bring your own in <a href="https://github.com/markdown-it/markdown-it#syntax-highlighting"><code>markdownItOptions.highlight</code></a>)</td>
243
+ <td>✅ (defaults to <a href="https://github.com/PrismJS/prism/">Prism</a>, <a href="https://mdsvex.pngwn.io/docs#highlight">can be changed</a>)</td>
244
+ </tr>
245
+ <tr>
246
+ <td>Replace any HTML tag after Markdown processing</td>
247
+ <td>❌</td>
248
+ <td><a href="https://mdsvex.pngwn.io/docs#custom-components">✅</a></td>
249
+ </tr>
250
+ <tr>
251
+ <td>Layout</td>
252
+ <td>Optional wrapper <code>&lt;div></code> with classes</td>
253
+ <td>Svelte components, configurable in frontmatter</td>
254
+ </td>
255
+ <tr>
256
+ <td>Fancy typography replacements<br>(e.g. <code>...</code> → <code>…</code>)</td>
257
+ <td>✅</td>
258
+ <td>✅</td>
259
+ </tr>
260
+ <tr>
261
+ <td>+page.md (in SvelteKit)</td>
262
+ <td>✅</td>
263
+ <td>✅</td>
264
+ </tr>
265
+ </table>
266
+
267
+ ## 🍊 Svelte Compatibility
268
+
269
+ You might encounter issues with markdown-it plugins that produce invalid Svelte code, e.g. a TeX plugin that outputs unescaped `{` and `}` characters. In this case, the simplest workaround is to wrap the plugin output in a Svelte [`{@html ...}`](https://svelte.dev/docs/svelte/@html) tag:
270
+
271
+ ```js
272
+ import { tex } from '@mdit/plugin-tex';
273
+ import katex from 'katex';
274
+
275
+ mdSvelte({
276
+ use: (md) =>
277
+ md.use(tex, {
278
+ // `katex.renderToString` produces HTML with unescaped `{` and `}` characters,
279
+ // wrap its output with {@html JSON.stringify(...)} to avoid Svelte parsing errors.
280
+ render: (content, displayMode) =>
281
+ `{@html ${JSON.stringify(katex.renderToString(content, { displayMode }))}}`,
282
+ }),
283
+ });
284
+
285
+ ```
286
+
168
287
  ## :beers: Contributing
169
288
 
170
289
  Welcome contributing!
@@ -1,5 +1,5 @@
1
- import type MarkdownIt from "markdown-it";
1
+ import type { MarkdownExit } from "markdown-exit";
2
2
  /**
3
3
  * Escape curly braces in code block plugin
4
4
  */
5
- export default function plugin(md: MarkdownIt): void;
5
+ export default function plugin(md: MarkdownExit): void;
@@ -4,15 +4,15 @@ import { escapeBraces } from "../utils.js";
4
4
  */
5
5
  export default function plugin(md) {
6
6
  const originalCodeBlock = md.renderer.rules.code_block;
7
- md.renderer.rules.code_block = (...args) => {
8
- return escapeBraces(originalCodeBlock(...args));
7
+ md.renderer.rules.code_block = async (...args) => {
8
+ return escapeBraces(await originalCodeBlock(...args));
9
9
  };
10
10
  const originalCodeInline = md.renderer.rules.code_inline;
11
- md.renderer.rules.code_inline = (...args) => {
12
- return escapeBraces(originalCodeInline(...args));
11
+ md.renderer.rules.code_inline = async (...args) => {
12
+ return escapeBraces(await originalCodeInline(...args));
13
13
  };
14
14
  const originalFence = md.renderer.rules.fence;
15
- md.renderer.rules.fence = (...args) => {
16
- return escapeBraces(originalFence(...args));
15
+ md.renderer.rules.fence = async (...args) => {
16
+ return escapeBraces(await originalFence(...args));
17
17
  };
18
18
  }
@@ -1,5 +1,5 @@
1
- import type MarkdownIt from "markdown-it";
1
+ import type { MarkdownExit } from "markdown-exit";
2
2
  /**
3
3
  * Svelte tags (e.g. `<svelte:head>`) plugin
4
4
  */
5
- export default function plugin(md: MarkdownIt): void;
5
+ export default function plugin(md: MarkdownExit): void;
package/lib/markdown.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ResolvedOptions } from "./options.ts";
2
- export type MarkdownProcessor = (id: string, text: string) => string;
2
+ export type MarkdownProcessor = (id: string, text: string) => Promise<string>;
3
3
  /**
4
4
  * Creates md processor
5
5
  */
package/lib/markdown.js CHANGED
@@ -1,4 +1,4 @@
1
- import MarkdownIt from "markdown-it";
1
+ import { createMarkdownExit } from "markdown-exit";
2
2
  import grayMatter from "gray-matter";
3
3
  import markdownItSvelteTags from "./markdown-it-svelte-tags/index.js";
4
4
  import markdownItSvelteCurlyBracesEscape from "./markdown-it-svelte-curly-braces-escape/index.js";
@@ -69,14 +69,13 @@ function parseHtml(html) {
69
69
  * Creates md processor
70
70
  */
71
71
  export function createMarkdownProcessor(options) {
72
- const markdownIt = new MarkdownIt({
72
+ const markdownIt = createMarkdownExit({
73
73
  html: true,
74
74
  linkify: true,
75
75
  typographer: true,
76
76
  ...options.markdownItOptions,
77
77
  });
78
78
  markdownIt.linkify.set({ fuzzyLink: false });
79
- // eslint-disable-next-line @typescript-eslint/unbound-method -- ignore
80
79
  const originalValidateLink = markdownIt.validateLink;
81
80
  markdownIt.validateLink = (url) => {
82
81
  if (!originalValidateLink(url)) {
@@ -85,16 +84,17 @@ export function createMarkdownProcessor(options) {
85
84
  return !IS_SVELTE_TAG_NAME_RE.test(url);
86
85
  };
87
86
  markdownIt.use(markdownItSvelteTags).use(markdownItSvelteCurlyBracesEscape);
87
+ options.use?.(markdownIt);
88
88
  options.markdownItUses.forEach((e) => {
89
89
  const [plugin, ...opts] = toArray(e);
90
90
  markdownIt.use(plugin, ...opts);
91
91
  });
92
- return (id, text) => {
92
+ return async (id, text) => {
93
93
  const raw = text.trimEnd();
94
94
  const { wrapperClasses, headEnabled } = options;
95
95
  const parsedFrontmatter = grayMatter(raw);
96
96
  const plainMarkdown = parsedFrontmatter?.content ?? raw;
97
- let html = markdownIt.render(plainMarkdown, { id });
97
+ let html = await markdownIt.renderAsync(plainMarkdown, { id });
98
98
  if (wrapperClasses) {
99
99
  html = `<div class="${wrapperClasses}">${html}</div>`;
100
100
  }
package/lib/options.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type * as MarkdownIt from "markdown-it";
1
+ import type { MarkdownExit, MarkdownExitOptions } from "markdown-exit";
2
2
  export interface Options {
3
3
  /**
4
4
  * Enable head support
@@ -7,13 +7,22 @@ export interface Options {
7
7
  */
8
8
  headEnabled?: boolean;
9
9
  /**
10
- * Options passed to Markdown It
10
+ * Options passed to Markdown Exit
11
11
  */
12
- markdownItOptions?: MarkdownIt.Options;
12
+ markdownItOptions?: MarkdownExitOptions;
13
13
  /**
14
- * Plugins for Markdown It
14
+ * Plugins for Markdown Exit
15
+ *
16
+ * @example
17
+ * use: (md) => md.use(plugin1).use(plugin2, options)
18
+ */
19
+ use?: (md: MarkdownExit) => void;
20
+ /**
21
+ * Plugins for Markdown Exit
22
+ *
23
+ * Prefer the `use` option for better type safety
15
24
  */
16
- markdownItUses?: (MarkdownIt.PluginSimple | [MarkdownIt.PluginSimple | MarkdownIt.PluginWithOptions, any] | any)[];
25
+ markdownItUses?: any[];
17
26
  /**
18
27
  * Class names for wrapper div
19
28
  *
@@ -23,7 +32,7 @@ export interface Options {
23
32
  include?: (string | RegExp)[] | string | RegExp | undefined;
24
33
  exclude?: (string | RegExp)[] | string | RegExp | undefined;
25
34
  }
26
- export type ResolvedOptions = Required<Omit<Options, "include" | "exclude">> & Pick<Options, "include" | "exclude"> & {
35
+ export type ResolvedOptions = Required<Omit<Options, "include" | "exclude" | "use">> & Pick<Options, "include" | "exclude" | "use"> & {
27
36
  wrapperClasses: string;
28
37
  };
29
38
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-svelte-md",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Vite plugin to convert markdown to svelte template",
6
6
  "files": [
@@ -40,7 +40,8 @@
40
40
  "vite-plugin",
41
41
  "svelte",
42
42
  "markdown",
43
- "markdown-it"
43
+ "markdown-it",
44
+ "markdown-exit"
44
45
  ],
45
46
  "author": "Yosuke Ota",
46
47
  "funding": "https://github.com/sponsors/ota-meshi",
@@ -53,8 +54,10 @@
53
54
  "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0"
54
55
  },
55
56
  "dependencies": {
57
+ "@types/linkify-it": "^5.0.0",
58
+ "@types/mdurl": "^2.0.0",
56
59
  "gray-matter": "^4.0.3",
57
- "markdown-it": "^14.0.0"
60
+ "markdown-exit": "^1.0.0-beta.8"
58
61
  },
59
62
  "devDependencies": {
60
63
  "@changesets/cli": "^2.29.5",
@@ -62,7 +65,6 @@
62
65
  "@ota-meshi/eslint-plugin": "^0.20.0",
63
66
  "@svitejs/changesets-changelog-github-compact": "^1.2.0",
64
67
  "@types/escape-html": "^1.0.1",
65
- "@types/markdown-it": "^14.0.0",
66
68
  "@types/node": "^24.0.0",
67
69
  "@types/prismjs": "^1.16.6",
68
70
  "@typescript-eslint/eslint-plugin": "^8.0.0",
@@ -73,9 +75,9 @@
73
75
  "eslint-config-prettier": "^10.0.0",
74
76
  "eslint-plugin-jsdoc": "^62.0.0",
75
77
  "eslint-plugin-json-schema-validator": "^6.0.0",
76
- "eslint-plugin-jsonc": "^2.0.0",
78
+ "eslint-plugin-jsonc": "^3.0.0",
77
79
  "eslint-plugin-n": "^17.0.0",
78
- "eslint-plugin-node-dependencies": "^1.0.0",
80
+ "eslint-plugin-node-dependencies": "^2.0.0",
79
81
  "eslint-plugin-prettier": "^5.0.0",
80
82
  "eslint-plugin-regexp": "^3.0.0",
81
83
  "prettier": "^3.0.0",