feature: vor und nachteile

This commit is contained in:
Hikyu
2026-05-31 13:54:31 +02:00
parent 552a947a1c
commit e3dad17446
23270 changed files with 3024794 additions and 200 deletions
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2022-present, mdit-vue Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+75
View File
@@ -0,0 +1,75 @@
# @mdit-vue/plugin-component
[![npm](https://badgen.net/npm/v/@mdit-vue/plugin-component)](https://www.npmjs.com/package/@mdit-vue/plugin-component)
[![license](https://badgen.net/github/license/mdit-vue/mdit-vue)](https://github.com/mdit-vue/mdit-vue/blob/main/LICENSE)
A [markdown-it](https://github.com/markdown-it/markdown-it) plugin to allow Vue components in markdown.
- Treats [vue built-in components](https://vuejs.org/api/built-in-components.html) and unknown HTML tags as vue components (markdown-it would treat them as inline tags by default).
- Allows vue [`@` directive](https://vuejs.org/api/built-in-directives.html#v-on) on native HTML tags.
## Install
```sh
npm i @mdit-vue/plugin-component
```
## Usage
This plugin will only take effects when the `html` option of markdown-it is enabled:
```ts
import { componentPlugin } from '@mdit-vue/plugin-component';
import MarkdownIt from 'markdown-it';
const md = MarkdownIt({ html: true }).use(componentPlugin, {
// options
});
const rendered = md.render(
`\
<!-- @ shorthand is supported -->
<Foo @click="onClick" />
<!-- multi-line syntax won't be wrapped with <p> -->
<Foo
class="foo"
:bar="bar"
/>
`,
);
```
## Options
### blockTags
- Type: `string[]`
- Default: `[]`
- Details:
Extra tags to be treated as block tags.
By default, all standard [HTML inline elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements) will be treated as inline tags (excluding [Vue built-in special elements](https://vuejs.org/api/built-in-special-elements.html)). All unknown elements will be assumed as Vue components, and will be treated as block tags (with slight differences).
In some cases (should be rare though) you might want to force some tags to behave like block tags, then you can use this option to specify the tag names.
Notice that this option is case-sensitive, and has higher priority than the [inlineTags](#inlinetags) option.
### inlineTags
- Type: `string[]`
- Default: `[]`
- Details:
Extra tags to be treated as inline tags.
By default, only standard [HTML inline elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements) will be treated as inline tags (excluding [Vue built-in special elements](https://vuejs.org/api/built-in-special-elements.html)). All unknown elements will be assumed as Vue components, and will be treated as block tags (with slight differences).
Treating Vue components like block tags would work as expected in most cases. However, in some cases you might want to force some tags to behave like inline tags, then you can use this option to specify the tag names.
Notice that this option is case-sensitive, and has lower priority than the [blockTags](#blocktags) option.
+316
View File
@@ -0,0 +1,316 @@
'use strict';
const attr_name = "[a-zA-Z_:@][a-zA-Z0-9:._-]*";
const unquoted = "[^\"'=<>`\\x00-\\x20]+";
const single_quoted = "'[^']*'";
const double_quoted = '"[^"]*"';
const attr_value = "(?:" + unquoted + "|" + single_quoted + "|" + double_quoted + ")";
const attribute = "(?:\\s+" + attr_name + "(?:\\s*=\\s*" + attr_value + ")?)";
const open_tag = "<[A-Za-z][A-Za-z0-9\\-]*" + attribute + "*\\s*\\/?>";
const close_tag = "<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>";
const comment = "<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->";
const processing = "<[?][\\s\\S]*?[?]>";
const declaration = "<![A-Z]+\\s+[^>]*>";
const cdata = "<!\\[CDATA\\[[\\s\\S]*?\\]\\]>";
const HTML_TAG_RE = new RegExp(
"^(?:" + open_tag + "|" + close_tag + "|" + comment + "|" + processing + "|" + declaration + "|" + cdata + ")"
);
const HTML_OPEN_CLOSE_TAG_RE = new RegExp(
"^(?:" + open_tag + "|" + close_tag + ")"
);
const HTML_SELF_CLOSING_TAG_RE = new RegExp(
"^<[A-Za-z][A-Za-z0-9\\-]*" + attribute + "*\\s*\\/>"
);
const HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE = new RegExp(
"^<([A-Za-z][A-Za-z0-9\\-]*)" + attribute + "*\\s*>.*<\\/\\1\\s*>"
);
const TAGS_BLOCK = [
"address",
"article",
"aside",
"base",
"basefont",
"blockquote",
"body",
"caption",
"center",
"col",
"colgroup",
"dd",
"details",
"dialog",
"dir",
"div",
"dl",
"dt",
"fieldset",
"figcaption",
"figure",
"footer",
"form",
"frame",
"frameset",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hr",
"html",
"iframe",
"legend",
"li",
"link",
"main",
"menu",
"menuitem",
"nav",
"noframes",
"ol",
"optgroup",
"option",
"p",
"param",
"search",
"section",
"summary",
"table",
"tbody",
"td",
"tfoot",
"th",
"thead",
"title",
"tr",
"track",
"ul"
];
const TAGS_INLINE = [
"a",
"abbr",
"acronym",
"audio",
"b",
"bdi",
"bdo",
"big",
"br",
"button",
"canvas",
"cite",
"code",
"data",
"datalist",
"del",
"dfn",
"em",
"embed",
"i",
"iframe",
"img",
"input",
"ins",
"kbd",
"label",
"map",
"mark",
"meter",
"noscript",
"object",
"output",
"picture",
"progress",
"q",
"ruby",
"s",
"samp",
"script",
"select",
"slot",
"small",
"span",
"strong",
"sub",
"sup",
"svg",
"template",
"textarea",
"time",
"u",
"tt",
"var",
"video",
"wbr"
];
const TAGS_VUE_RESERVED = [
"template",
"component",
"transition",
"transition-group",
"keep-alive",
"slot",
"teleport"
];
const createHtmlSequences = ({
blockTags,
inlineTags
}) => {
const forceBlockTags = [...blockTags, ...TAGS_BLOCK];
const forceInlineTags = [
...inlineTags,
...TAGS_INLINE.filter((item) => !TAGS_VUE_RESERVED.includes(item))
];
const HTML_SEQUENCES = [
[/^<(script|pre|style)(?=(\s|>|$))/i, /<\/(script|pre|style)>/i, true],
[/^<!--/, /-->/, true],
[/^<\?/, /\?>/, true],
[/^<![A-Z]/, />/, true],
[/^<!\[CDATA\[/, /\]\]>/, true],
// MODIFIED: Support extra block tags from user options
[
new RegExp("^</?(" + forceBlockTags.join("|") + ")(?=(\\s|/?>|$))", "i"),
/^$/,
true
],
// ADDED: Matching component tags (all unknown tags) (i = 6)
[
new RegExp(
"^</?(?!(" + forceInlineTags.join("|") + ")(?![\\w-]))[A-Za-z][A-Za-z0-9\\-]*(?=(\\s|/?>|$))"
),
/^$/,
true
],
// this line is to treat a line that only have a single self-closed html tag
// as html_block, even if it's a self-closed inline tag
// MODIFIED: Tweak the original HTML_OPEN_CLOSE_TAG_RE
[new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + "\\s*$"), /^$/, false]
];
return HTML_SEQUENCES;
};
const createHtmlBlockRule = (options) => {
const HTML_SEQUENCES = createHtmlSequences(options);
return (state, startLine, endLine, silent) => {
let i;
let nextLine;
let lineText;
let pos = state.bMarks[startLine] + state.tShift[startLine];
let max = state.eMarks[startLine];
if (state.sCount[startLine] - state.blkIndent >= 4) {
return false;
}
if (!state.md.options.html) {
return false;
}
if (state.src.charCodeAt(pos) !== 60) {
return false;
}
lineText = state.src.slice(pos, max);
for (i = 0; i < HTML_SEQUENCES.length; i++) {
if (HTML_SEQUENCES[i][0].test(lineText)) {
break;
}
}
if (i === HTML_SEQUENCES.length) {
return false;
}
if (silent) {
return HTML_SEQUENCES[i][2];
}
if (i === 6) {
const match = (
// if the component tag is self-closing
lineText.match(HTML_SELF_CLOSING_TAG_RE) ?? // or has open and close tag in the same line
lineText.match(HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE)
);
if (match) {
state.line = startLine + 1;
let token2 = state.push("html_inline", "", 0);
token2.content = match[0];
token2.map = [startLine, state.line];
token2 = state.push("inline", "", 0);
token2.content = lineText.slice(match[0].length);
token2.map = [startLine, state.line];
token2.children = [];
return true;
}
}
nextLine = startLine + 1;
if (!HTML_SEQUENCES[i][1].test(lineText)) {
for (; nextLine < endLine; nextLine++) {
if (state.sCount[nextLine] < state.blkIndent) {
break;
}
pos = state.bMarks[nextLine] + state.tShift[nextLine];
max = state.eMarks[nextLine];
lineText = state.src.slice(pos, max);
if (HTML_SEQUENCES[i][1].test(lineText)) {
if (lineText.length !== 0) {
nextLine++;
}
break;
}
}
}
state.line = nextLine;
const token = state.push("html_block", "", 0);
token.map = [startLine, nextLine];
token.content = state.getLines(startLine, nextLine, state.blkIndent, true);
return true;
};
};
const isLetter = (ch) => {
const lc = ch | 32;
return lc >= 97 && lc <= 122;
};
const htmlInlineRule = (state, silent) => {
const { pos } = state;
if (!state.md.options.html) {
return false;
}
const max = state.posMax;
if (state.src.charCodeAt(pos) !== 60 || pos + 2 >= max) {
return false;
}
const ch = state.src.charCodeAt(pos + 1);
if (ch !== 33 && ch !== 63 && ch !== 47 && !isLetter(ch)) {
return false;
}
const match = state.src.slice(pos).match(HTML_TAG_RE);
if (!match) {
return false;
}
if (!silent) {
const token = state.push("html_inline", "", 0);
token.content = state.src.slice(pos, pos + match[0].length);
}
state.pos += match[0].length;
return true;
};
const componentPlugin = (md, { blockTags = [], inlineTags = [] } = {}) => {
const htmlBlockRule = createHtmlBlockRule({
blockTags,
inlineTags
});
md.block.ruler.at("html_block", htmlBlockRule, {
alt: ["paragraph", "reference", "blockquote"]
});
md.inline.ruler.at("html_inline", htmlInlineRule);
};
exports.HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE = HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE;
exports.HTML_OPEN_CLOSE_TAG_RE = HTML_OPEN_CLOSE_TAG_RE;
exports.HTML_SELF_CLOSING_TAG_RE = HTML_SELF_CLOSING_TAG_RE;
exports.HTML_TAG_RE = HTML_TAG_RE;
exports.TAGS_BLOCK = TAGS_BLOCK;
exports.TAGS_INLINE = TAGS_INLINE;
exports.TAGS_VUE_RESERVED = TAGS_VUE_RESERVED;
exports.componentPlugin = componentPlugin;
exports.createHtmlBlockRule = createHtmlBlockRule;
exports.htmlInlineRule = htmlInlineRule;
+71
View File
@@ -0,0 +1,71 @@
import { PluginWithOptions } from 'markdown-it';
import { RuleBlock } from 'markdown-it/lib/parser_block.mjs';
import { RuleInline } from 'markdown-it/lib/parser_inline.mjs';
/**
* Options of @mdit-vue/plugin-component
*/
interface ComponentPluginOptions {
/**
* Extra tags to be treated as block tags.
*
* @default []
*/
blockTags?: string[];
/**
* Extra tags to be treated as inline tags.
*
* @default []
*/
inlineTags?: string[];
}
/**
* Allows better use of Vue components in Markdown
*/
declare const componentPlugin: PluginWithOptions<ComponentPluginOptions>;
declare const createHtmlBlockRule: (options: Required<ComponentPluginOptions>) => RuleBlock;
declare const htmlInlineRule: RuleInline;
declare const HTML_TAG_RE: RegExp;
declare const HTML_OPEN_CLOSE_TAG_RE: RegExp;
declare const HTML_SELF_CLOSING_TAG_RE: RegExp;
declare const HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE: RegExp;
/**
* List of block tags
*
* @see https://spec.commonmark.org/0.30/#html-blocks
* @see https://github.com/markdown-it/markdown-it/blob/master/lib/common/html_blocks.mjs
*/
declare const TAGS_BLOCK: string[];
/**
* According to markdown spec, all non-block html tags are treated as "inline"
* tags (wrapped with <p></p>), including those "unknown" tags
*
* Therefore, markdown-it processes "inline" tags and "unknown" tags in the same
* way, and does not care if a tag is "inline" or "unknown"
*
* As we want to take those "unknown" tags as custom components, we should
* treat them as "block" tags
*
* So we have to distinguish between "inline" and "unknown" tags ourselves
*
* The inline tags list comes from MDN
*
* @see https://spec.commonmark.org/0.30/#raw-html
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements
*/
declare const TAGS_INLINE: string[];
/**
* Tags of Vue built-in components
*
* @see https://vuejs.org/api/built-in-components.html
* @see https://vuejs.org/api/built-in-special-elements.html
*/
declare const TAGS_VUE_RESERVED: string[];
export { HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE, HTML_OPEN_CLOSE_TAG_RE, HTML_SELF_CLOSING_TAG_RE, HTML_TAG_RE, TAGS_BLOCK, TAGS_INLINE, TAGS_VUE_RESERVED, componentPlugin, createHtmlBlockRule, htmlInlineRule };
export type { ComponentPluginOptions };
+71
View File
@@ -0,0 +1,71 @@
import { PluginWithOptions } from 'markdown-it';
import { RuleBlock } from 'markdown-it/lib/parser_block.mjs';
import { RuleInline } from 'markdown-it/lib/parser_inline.mjs';
/**
* Options of @mdit-vue/plugin-component
*/
interface ComponentPluginOptions {
/**
* Extra tags to be treated as block tags.
*
* @default []
*/
blockTags?: string[];
/**
* Extra tags to be treated as inline tags.
*
* @default []
*/
inlineTags?: string[];
}
/**
* Allows better use of Vue components in Markdown
*/
declare const componentPlugin: PluginWithOptions<ComponentPluginOptions>;
declare const createHtmlBlockRule: (options: Required<ComponentPluginOptions>) => RuleBlock;
declare const htmlInlineRule: RuleInline;
declare const HTML_TAG_RE: RegExp;
declare const HTML_OPEN_CLOSE_TAG_RE: RegExp;
declare const HTML_SELF_CLOSING_TAG_RE: RegExp;
declare const HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE: RegExp;
/**
* List of block tags
*
* @see https://spec.commonmark.org/0.30/#html-blocks
* @see https://github.com/markdown-it/markdown-it/blob/master/lib/common/html_blocks.mjs
*/
declare const TAGS_BLOCK: string[];
/**
* According to markdown spec, all non-block html tags are treated as "inline"
* tags (wrapped with <p></p>), including those "unknown" tags
*
* Therefore, markdown-it processes "inline" tags and "unknown" tags in the same
* way, and does not care if a tag is "inline" or "unknown"
*
* As we want to take those "unknown" tags as custom components, we should
* treat them as "block" tags
*
* So we have to distinguish between "inline" and "unknown" tags ourselves
*
* The inline tags list comes from MDN
*
* @see https://spec.commonmark.org/0.30/#raw-html
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements
*/
declare const TAGS_INLINE: string[];
/**
* Tags of Vue built-in components
*
* @see https://vuejs.org/api/built-in-components.html
* @see https://vuejs.org/api/built-in-special-elements.html
*/
declare const TAGS_VUE_RESERVED: string[];
export { HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE, HTML_OPEN_CLOSE_TAG_RE, HTML_SELF_CLOSING_TAG_RE, HTML_TAG_RE, TAGS_BLOCK, TAGS_INLINE, TAGS_VUE_RESERVED, componentPlugin, createHtmlBlockRule, htmlInlineRule };
export type { ComponentPluginOptions };
+71
View File
@@ -0,0 +1,71 @@
import { PluginWithOptions } from 'markdown-it';
import { RuleBlock } from 'markdown-it/lib/parser_block.mjs';
import { RuleInline } from 'markdown-it/lib/parser_inline.mjs';
/**
* Options of @mdit-vue/plugin-component
*/
interface ComponentPluginOptions {
/**
* Extra tags to be treated as block tags.
*
* @default []
*/
blockTags?: string[];
/**
* Extra tags to be treated as inline tags.
*
* @default []
*/
inlineTags?: string[];
}
/**
* Allows better use of Vue components in Markdown
*/
declare const componentPlugin: PluginWithOptions<ComponentPluginOptions>;
declare const createHtmlBlockRule: (options: Required<ComponentPluginOptions>) => RuleBlock;
declare const htmlInlineRule: RuleInline;
declare const HTML_TAG_RE: RegExp;
declare const HTML_OPEN_CLOSE_TAG_RE: RegExp;
declare const HTML_SELF_CLOSING_TAG_RE: RegExp;
declare const HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE: RegExp;
/**
* List of block tags
*
* @see https://spec.commonmark.org/0.30/#html-blocks
* @see https://github.com/markdown-it/markdown-it/blob/master/lib/common/html_blocks.mjs
*/
declare const TAGS_BLOCK: string[];
/**
* According to markdown spec, all non-block html tags are treated as "inline"
* tags (wrapped with <p></p>), including those "unknown" tags
*
* Therefore, markdown-it processes "inline" tags and "unknown" tags in the same
* way, and does not care if a tag is "inline" or "unknown"
*
* As we want to take those "unknown" tags as custom components, we should
* treat them as "block" tags
*
* So we have to distinguish between "inline" and "unknown" tags ourselves
*
* The inline tags list comes from MDN
*
* @see https://spec.commonmark.org/0.30/#raw-html
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements
*/
declare const TAGS_INLINE: string[];
/**
* Tags of Vue built-in components
*
* @see https://vuejs.org/api/built-in-components.html
* @see https://vuejs.org/api/built-in-special-elements.html
*/
declare const TAGS_VUE_RESERVED: string[];
export { HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE, HTML_OPEN_CLOSE_TAG_RE, HTML_SELF_CLOSING_TAG_RE, HTML_TAG_RE, TAGS_BLOCK, TAGS_INLINE, TAGS_VUE_RESERVED, componentPlugin, createHtmlBlockRule, htmlInlineRule };
export type { ComponentPluginOptions };
+305
View File
@@ -0,0 +1,305 @@
const attr_name = "[a-zA-Z_:@][a-zA-Z0-9:._-]*";
const unquoted = "[^\"'=<>`\\x00-\\x20]+";
const single_quoted = "'[^']*'";
const double_quoted = '"[^"]*"';
const attr_value = "(?:" + unquoted + "|" + single_quoted + "|" + double_quoted + ")";
const attribute = "(?:\\s+" + attr_name + "(?:\\s*=\\s*" + attr_value + ")?)";
const open_tag = "<[A-Za-z][A-Za-z0-9\\-]*" + attribute + "*\\s*\\/?>";
const close_tag = "<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>";
const comment = "<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->";
const processing = "<[?][\\s\\S]*?[?]>";
const declaration = "<![A-Z]+\\s+[^>]*>";
const cdata = "<!\\[CDATA\\[[\\s\\S]*?\\]\\]>";
const HTML_TAG_RE = new RegExp(
"^(?:" + open_tag + "|" + close_tag + "|" + comment + "|" + processing + "|" + declaration + "|" + cdata + ")"
);
const HTML_OPEN_CLOSE_TAG_RE = new RegExp(
"^(?:" + open_tag + "|" + close_tag + ")"
);
const HTML_SELF_CLOSING_TAG_RE = new RegExp(
"^<[A-Za-z][A-Za-z0-9\\-]*" + attribute + "*\\s*\\/>"
);
const HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE = new RegExp(
"^<([A-Za-z][A-Za-z0-9\\-]*)" + attribute + "*\\s*>.*<\\/\\1\\s*>"
);
const TAGS_BLOCK = [
"address",
"article",
"aside",
"base",
"basefont",
"blockquote",
"body",
"caption",
"center",
"col",
"colgroup",
"dd",
"details",
"dialog",
"dir",
"div",
"dl",
"dt",
"fieldset",
"figcaption",
"figure",
"footer",
"form",
"frame",
"frameset",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hr",
"html",
"iframe",
"legend",
"li",
"link",
"main",
"menu",
"menuitem",
"nav",
"noframes",
"ol",
"optgroup",
"option",
"p",
"param",
"search",
"section",
"summary",
"table",
"tbody",
"td",
"tfoot",
"th",
"thead",
"title",
"tr",
"track",
"ul"
];
const TAGS_INLINE = [
"a",
"abbr",
"acronym",
"audio",
"b",
"bdi",
"bdo",
"big",
"br",
"button",
"canvas",
"cite",
"code",
"data",
"datalist",
"del",
"dfn",
"em",
"embed",
"i",
"iframe",
"img",
"input",
"ins",
"kbd",
"label",
"map",
"mark",
"meter",
"noscript",
"object",
"output",
"picture",
"progress",
"q",
"ruby",
"s",
"samp",
"script",
"select",
"slot",
"small",
"span",
"strong",
"sub",
"sup",
"svg",
"template",
"textarea",
"time",
"u",
"tt",
"var",
"video",
"wbr"
];
const TAGS_VUE_RESERVED = [
"template",
"component",
"transition",
"transition-group",
"keep-alive",
"slot",
"teleport"
];
const createHtmlSequences = ({
blockTags,
inlineTags
}) => {
const forceBlockTags = [...blockTags, ...TAGS_BLOCK];
const forceInlineTags = [
...inlineTags,
...TAGS_INLINE.filter((item) => !TAGS_VUE_RESERVED.includes(item))
];
const HTML_SEQUENCES = [
[/^<(script|pre|style)(?=(\s|>|$))/i, /<\/(script|pre|style)>/i, true],
[/^<!--/, /-->/, true],
[/^<\?/, /\?>/, true],
[/^<![A-Z]/, />/, true],
[/^<!\[CDATA\[/, /\]\]>/, true],
// MODIFIED: Support extra block tags from user options
[
new RegExp("^</?(" + forceBlockTags.join("|") + ")(?=(\\s|/?>|$))", "i"),
/^$/,
true
],
// ADDED: Matching component tags (all unknown tags) (i = 6)
[
new RegExp(
"^</?(?!(" + forceInlineTags.join("|") + ")(?![\\w-]))[A-Za-z][A-Za-z0-9\\-]*(?=(\\s|/?>|$))"
),
/^$/,
true
],
// this line is to treat a line that only have a single self-closed html tag
// as html_block, even if it's a self-closed inline tag
// MODIFIED: Tweak the original HTML_OPEN_CLOSE_TAG_RE
[new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + "\\s*$"), /^$/, false]
];
return HTML_SEQUENCES;
};
const createHtmlBlockRule = (options) => {
const HTML_SEQUENCES = createHtmlSequences(options);
return (state, startLine, endLine, silent) => {
let i;
let nextLine;
let lineText;
let pos = state.bMarks[startLine] + state.tShift[startLine];
let max = state.eMarks[startLine];
if (state.sCount[startLine] - state.blkIndent >= 4) {
return false;
}
if (!state.md.options.html) {
return false;
}
if (state.src.charCodeAt(pos) !== 60) {
return false;
}
lineText = state.src.slice(pos, max);
for (i = 0; i < HTML_SEQUENCES.length; i++) {
if (HTML_SEQUENCES[i][0].test(lineText)) {
break;
}
}
if (i === HTML_SEQUENCES.length) {
return false;
}
if (silent) {
return HTML_SEQUENCES[i][2];
}
if (i === 6) {
const match = (
// if the component tag is self-closing
lineText.match(HTML_SELF_CLOSING_TAG_RE) ?? // or has open and close tag in the same line
lineText.match(HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE)
);
if (match) {
state.line = startLine + 1;
let token2 = state.push("html_inline", "", 0);
token2.content = match[0];
token2.map = [startLine, state.line];
token2 = state.push("inline", "", 0);
token2.content = lineText.slice(match[0].length);
token2.map = [startLine, state.line];
token2.children = [];
return true;
}
}
nextLine = startLine + 1;
if (!HTML_SEQUENCES[i][1].test(lineText)) {
for (; nextLine < endLine; nextLine++) {
if (state.sCount[nextLine] < state.blkIndent) {
break;
}
pos = state.bMarks[nextLine] + state.tShift[nextLine];
max = state.eMarks[nextLine];
lineText = state.src.slice(pos, max);
if (HTML_SEQUENCES[i][1].test(lineText)) {
if (lineText.length !== 0) {
nextLine++;
}
break;
}
}
}
state.line = nextLine;
const token = state.push("html_block", "", 0);
token.map = [startLine, nextLine];
token.content = state.getLines(startLine, nextLine, state.blkIndent, true);
return true;
};
};
const isLetter = (ch) => {
const lc = ch | 32;
return lc >= 97 && lc <= 122;
};
const htmlInlineRule = (state, silent) => {
const { pos } = state;
if (!state.md.options.html) {
return false;
}
const max = state.posMax;
if (state.src.charCodeAt(pos) !== 60 || pos + 2 >= max) {
return false;
}
const ch = state.src.charCodeAt(pos + 1);
if (ch !== 33 && ch !== 63 && ch !== 47 && !isLetter(ch)) {
return false;
}
const match = state.src.slice(pos).match(HTML_TAG_RE);
if (!match) {
return false;
}
if (!silent) {
const token = state.push("html_inline", "", 0);
token.content = state.src.slice(pos, pos + match[0].length);
}
state.pos += match[0].length;
return true;
};
const componentPlugin = (md, { blockTags = [], inlineTags = [] } = {}) => {
const htmlBlockRule = createHtmlBlockRule({
blockTags,
inlineTags
});
md.block.ruler.at("html_block", htmlBlockRule, {
alt: ["paragraph", "reference", "blockquote"]
});
md.inline.ruler.at("html_inline", htmlInlineRule);
};
export { HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE, HTML_OPEN_CLOSE_TAG_RE, HTML_SELF_CLOSING_TAG_RE, HTML_TAG_RE, TAGS_BLOCK, TAGS_INLINE, TAGS_VUE_RESERVED, componentPlugin, createHtmlBlockRule, htmlInlineRule };
+55
View File
@@ -0,0 +1,55 @@
{
"name": "@mdit-vue/plugin-component",
"version": "2.1.4",
"description": "A markdown-it plugin to allow vue components in markdown",
"keywords": [
"markdown-it",
"markdown-it-plugin",
"vue",
"component"
],
"homepage": "https://github.com/mdit-vue",
"bugs": {
"url": "https://github.com/mdit-vue/mdit-vue/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/mdit-vue/mdit-vue.git"
},
"license": "MIT",
"author": "meteorlxy <meteor.lxy@foxmail.com>",
"type": "module",
"exports": {
".": {
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"./dist"
],
"scripts": {
"build": "unbuild",
"test": "vitest"
},
"dependencies": {
"@types/markdown-it": "^14.1.2",
"markdown-it": "^14.1.0"
},
"devDependencies": {
"@vue/shared": "^3.5.13"
},
"publishConfig": {
"access": "public"
},
"gitHead": "01a6daa37fff48ea3992becfd4ba8c0f97a605ad"
}