Markdown2HTML 解析器
本文最后更新于2 天前,其中的信息可能已经过时,如有错误请发送邮件到asure_0506@foxmail.com

访问地址:https://www.npmjs.com/package/markdown2html-parser

Markdown2HTML Parser

一个功能完整、架构清晰的 Markdown 到 HTML 转换器,采用经典的编译器设计模式,通过词法分析、语法分析和渲染三个阶段,将 Markdown 文本高效转换为 HTML 代码。

📋 目录

– [项目简介](#项目简介)

– [核心特性](#核心特性)

– [架构设计](#架构设计)

– [核心代码解析](#核心代码解析)

– [安装使用](#安装使用)

– [API 文档](#api-文档)

– [支持语法](#支持语法)

– [技术栈](#技术栈)

🎯 项目简介

markdown2html-parser 是一个轻量级、高性能的 Markdown 解析器,采用 TypeScript 编写,支持将 Markdown 文本转换为标准的 HTML 代码。项目遵循编译器设计原则,通过词法分析(Lexer)、语法分析(Parser)和渲染(Render)三个阶段,实现了完整的 Markdown 解析流程。

设计理念

本项目采用经典的编译器前端设计模式

Markdown 文本 → [词法分析] → Token 流 → [语法分析] → AST → [渲染] → HTML

这种设计使得代码结构清晰、易于维护和扩展,同时保证了解析的准确性和性能。

✨ 核心特性

1. 完整的 Markdown 语法支持

  • 文本样式:加粗(`**bold**`、`__bold__`)、斜体(`*italic*`、`_italic_`)、删除线(`~~text~~`)
  • 标题:支持 H1-H6 六级标题(`#` 到 `######`)
  • 链接和图片**:支持标准 Markdown 链接和图片语法
  • 代码:行内代码(“ `code` “)和代码块(` “`code“` `)
  • 列表:有序列表(`1. item`)和无序列表(`*`、`+`、`-`)
  • 引用:块引用(`> quote`)
  • 分隔线:水平分隔线(`—`)
  • 复杂组合:支持多种样式组合(如加粗链接、斜体加粗等)

2. 模块化架构

  • 词法分析器(Lexer):将 Markdown 文本解析为 Token 流
  • 语法分析器(Parser):将 Token 流转换为抽象语法树(AST)
  • 渲染器(Render):将 AST 渲染为 HTML 代码

3. 类型安全

  • 完整的 TypeScript 类型定义
  • 严格的类型检查,确保代码质量

4. 多模块系统支持

  • 支持 ESM(ES Module)导入
  • 支持 CommonJS 导入
  • 支持默认导入

🏗️ 架构设计

项目结构

markdown2html-parser/

├── src/                          # 源代码目录

│   ├── md2html.ts               # 主入口函数,协调整个解析流程

│   ├── lexer.ts                 # 词法分析器

│   ├── parser.ts                # 语法分析器

│   ├── render.ts                # HTML 渲染器

│   └── common/

│       └── html_regexp.ts       # 正则表达式定义

├── dist/                         # 编译输出目录

├── index.ts                      # 包入口文件,导出 API

├── package.json                  # 项目配置

└── tsconfig.json                 # TypeScript 配置

数据流

输入 Markdown 文本

    ↓

[Lexer] 词法分析

    ↓

Token[] 数组

    ↓

[Parser] 语法分析

    ↓

AST (抽象语法树)

    ↓

[Render] 渲染

    ↓

输出 HTML 字符串

🔍 核心代码解析

1. 主入口函数 (`src/md2html.ts`)

这是整个解析流程的协调者,将三个阶段串联起来:

src/md2html.ts

export function markdownToHtml(input: string): string {

  const tokens = lexer(input); // 词法分析,生成 tokens

  const ast = parser(tokens); // 语法分析,生成 AST

  return render(ast); // 渲染 AST 为 HTML

}

设计亮点

  • 简洁的 API 设计,一行代码完成转换
  • 清晰的职责分离,每个阶段独立处理

2. 词法分析器 (`src/lexer.ts`)

词法分析器负责将 Markdown 文本解析为 Token 流。核心逻辑包括:

Token 类型定义

src/lexer.ts

type Token = {

  type:

    | "text"

    | "header"

    | "bold"

    | "italic"

    | "strikethrough"

    | "link"

    | "image"

    | "code"

    | "code_block"

    | "newline"

    | "list_item"

    | "horizontal_rule"

    | "blockquote"

    | "complex"

    | "order_list"

    | "unorder_list";

  content?: string; // 适用于 header, bold, italic, strikethrough, code, code_block, list_item, blockquote

  value?: string; // 适用于 text 类型

  level?: number; // 适用于 header

  href?: string; // 适用于 link

  text?: string; // 适用于 link

  src?: string; // 适用于 image

  alt?: string; // 适用于 image

  children?: String[]; // **允许所有 Token 存储子 Token**

  start?: number; //有序列表开始的顺序,默认为1

  listArr?: Array<{

    value: string;

    type: "order_list" | "unorder_list";

    start: number;

    isFirst: number;

  }>;

  isFirst?: number; //判断是否为第一项

};

 核心解析函数

src/lexer.ts

function lexer(input: string): Token[] {

  const tokens: Token[] = [];

  console.log("原生代码");

  console.log(input);

  const lines = input.split("\n"); // 按行分割输入文本

  lines.forEach((line, index) => {

    const token = TypeCheck(line);

    // 打印整个 token 数组的 JSON 字符串(已格式化)

    // console.log("打印返回的数组");

    console.log(JSON.stringify(token, null, 2));

    // console.log("输出数组位置");

    // console.log(index);

    // 遍历 token 数组,获取每个 token 的键值对

    const tokenType = token["type"] as string;

    const tokenContent = (token["content"] as string) ?? "";

    const tokenValue = (token["value"] as string) ?? "";

    const tokenLevel = (token["level"] as number) ?? 0;

    const tokenHref = (token["href"] as string) ?? "";

    const tokenText = (token["text"] as string) ?? "";

    const tokenSrc = (token["src"] as string) ?? "";

    const tokenAlt = (token["alt"] as string) ?? "";

    const tokenChildren = (token["children"] as string[]) ?? [];

    const tokenStart = (token["start"] as number) ?? 1;

    if (index !== 0) {

      tokens.push({ type: "newline" });

    }

    // 处理不同类型的 Token

    switch (tokenType) {

      case "text":

        console.log(token["value"]);

        tokens.push({

          type: "text",

          value: tokenValue,

        });

        break;

      case "header":

        tokens.push({

          type: "header",

          content: tokenContent,

          level: tokenLevel,

        });

        break;

      case "bold":

        tokens.push({

          type: "bold",

          content: tokenContent,

        });

        break;

      case "italic":

        tokens.push({

          type: "italic",

          content: tokenContent,

        });

        break;

      case "strikethrough":

        tokens.push({

          type: "strikethrough",

          content: tokenContent,

        });

        break;

      case "link":

        tokens.push({

          type: "link",

          href: tokenHref,

          text: tokenText,

        });

        break;

      case "image":

        tokens.push({

          type: "image",

          src: tokenSrc,

          alt: tokenAlt,

        });

        break;

      case "code":

        tokens.push({

          type: "code",

          content: tokenContent,

        });

        break;

      case "code_block":

        tokens.push({

          type: "code_block",

          content: tokenContent,

        });

        break;

      case "horizontal_rule":

        tokens.push({

          type: "horizontal_rule",

        });

        break;

      case "blockquote":

        tokens.push({

          type: "blockquote",

          content: tokenContent,

        });

        break;

      case "complex":

        tokens.push({

          type: "complex",

          children: tokenChildren,

          content: tokenContent,

        });

        break;

      case "newline":

        tokens.push({

          type: "newline",

        });

        break;

      case "order_list":

        tokens.push({

          type: "order_list",

          value: tokenValue,

          start: tokenStart,

        });

        break;

      case "unorder_list":

        tokens.push({

          type: "unorder_list",

          value: tokenValue,

        });

        break;

      default:

        console.warn(`未知的 Token 类型: ${tokenType}`);

        break;

    }

  });

  return tokens;

}

设计亮点

  • 按行处理,简化逻辑
  • 支持复杂样式组合(通过 `complex` 类型)
  • 完整的类型检查机制

类型检测函数

src/lexer.ts

function TypeCheck(input: string): Object {

  const token: { [key: string]: any } = {};

  const status: Array<string> = [];

  // 内容保存

  let content: string = "";

  const headerReg = [h1Regex, h2Regex, h3Regex, h4Regex, h5Regex, h6Regex];

  for (let i = 0; i < headerReg.length; i++) {

    const header = input.match(headerReg[i]);

    if (header) {

      let temp = i + 1;

      status.push("h" + temp);

      input = replaceInput(headerReg[i], input);

    }

  }

  // 处理加粗

  const boldRegexes = [boldRegex, boldAltRegex];

  const matchedBoldRegex = boldRegexes.find((regex) => input.match(regex));

  const bold = matchedBoldRegex ? input.match(matchedBoldRegex) : null;

  if (bold) {

    status.push("bold");

    input = replaceInput(matchedBoldRegex, input); // 确保替换用的是匹配到的正则

  }

  // 处理斜体

  const italicRegexes = [italicRegex, italicAltRegex];

  const matchedItalicRegex = italicRegexes.find((regex) => input.match(regex));

  const italic = matchedItalicRegex ? input.match(matchedItalicRegex) : null;

  if (italic) {

    status.push("italic");

    input = replaceInput(matchedItalicRegex, input);

  }

  // 匹配删除线

  const strikethrough = input.match(strikethroughRegex);

  if (strikethrough) {

    status.push("strikethrough");

    input = replaceInput(strikethroughRegex, input);

  }

  // 匹配图片

  const image = input.match(imageRegex);

  if (image) {

    status.push("image");

    input = imgAndLinkReplace(imageRegex, input);

  }

  // 匹配链接

  const link = input.match(linkRegex);

  if (link) {

    status.push("link");

    input = imgAndLinkReplace(linkRegex, input);

  }

  // 行内代码匹配

  const code = input.match(inlineCodeRegex);

  if (code) {

    status.push("code");

    input = replaceInput(inlineCodeRegex, input);

  }

  // 代码块匹配

  const code_block = input.match(codeBlockRegex);

  if (code_block) {

    status.push("code_block");

    input = replaceInput(codeBlockRegex, input);

  }

  // 换行符匹配

  const lineBreak = input.match(lineBreakRegex);

  if (lineBreak) {

    console.log("匹配到换行符");

    status.push("newline");

  }

  // 有序列表匹配

  const orderLine = input.match(orderedListItemRegex);

  let start: number = 1;

  if (orderLine) {

    status.push("order_list");

    // console.log("匹配到了列表项");

    let getStart = input.split(". "); //将数据分开

    input = replaceInput(orderedListItemRegex, input);

    start = +getStart[0];

  }

  const unorderedListRegexes = [

    unorderedListItemRegex,

    unorderedListItemAltRegex,

    unorderedListItemAlt2Regex,

  ];

  const matchedRegex = unorderedListRegexes.find((regex) => input.match(regex)); // 找到第一个成功匹配的正则

  const unorder = matchedRegex ? input.match(matchedRegex) : null;

  if (unorder) {

    status.push("unorder_list");

    input = replaceInput(matchedRegex, input); // 确保用匹配到的正则替换

    console.log("匹配到无序列表");

    console.log(input);

  }

  content += input;

  // 封装token

  if (status.length > 1) {

    for (let s of status) {

      if (s === "image") {

        let ans = typeImgOrUrl(content);

        token.type = "complex";

        token.src = ans.url;

        token.alt = ans.desc;

        token.children = [...status];

      } else if (s === "link") {

        let ans = typeImgOrUrl(content);

        token.type = "complex";

        token.text = ans.desc;

        token.href = ans.url;

        token.children = [...status];

      } else {

        token.type = "complex";

        token.content = content;

        token.children = [...status];

      }

    }

  } else if (status.length === 1) {

    const style = status[0];

    let headerLevel = typeHeader(style);

    if (headerLevel) {

      let str = style.split("");

      token.type = "header";

      token.level = +str[str.length - 1];

      token.content = content;

    } else {

      // 不是标题则是其他简单样式

      let ans = typeImgOrUrl(content);

      switch (style) {

        case "bold":

          token.type = "bold";

          token.content = content;

          break;

        case "italic":

          token.type = "italic";

          token.content = content;

          break;

        case "strikethrough":

          token.type = "strikethrough";

          token.content = content;

          break;

        case "image":

          // console.log("style是图片");

          token.type = "image";

          token.src = ans.url;

          token.alt = ans.desc;

          break;

        case "link":

          // console.log("style是链接" + style);

          token.type = "link";

          token.text = ans.desc;

          token.href = ans.url;

          break;

        case "order_list":

          token.type = "order_list";

          token.value = content;

          token.start = start;

          break;

        case "unorder_list":

          token.type = "unorder_list";

          token.value = content;

          break;

        default:

          break;

      }

    }

  } else {

    token.type = "text";

    token.value = content;

    console.log(token);

  }

  return token;

}

设计亮点

  • 使用状态数组记录匹配到的所有样式类型
  • 支持多种样式的组合(如加粗链接、斜体加粗等)
  • 通过正则表达式匹配,性能高效

3. 语法分析器 (`src/parser.ts`)

语法分析器将 Token 流转换为抽象语法树(AST)。

AST 节点类型定义

src/parser.ts

type ASTNode =

  | { type: "document"; children: ASTNode[] }

  | { type: "header"; level: number; content: string }

  | { type: "bold"; content: string }

  | { type: "italic"; content: string }

  | { type: "strikethrough"; content: string }

  | { type: "link"; href: string; text: string }

  | { type: "image"; src: string; alt: string }

  | { type: "code"; content: string }

  | { type: "code_block"; content: string }

  | { type: "blockquote"; children: ASTNode[] }

  | { type: "horizontal_rule" }

  | { type: "text"; value: string }

  | { type: "complex"; content: string; children: String[] } // 修改 complex 类型

  | { type: "newline" }

  | {

      type: "order_list";

      content: String;

      start: number;

      nestedItems?: ASTNode[];

    }

  | { type: "unorder_list"; content: String };

核心解析函数

src/parser.ts

function parser(tokens: Token[]): ASTNode {

  let current = 0;

  function parse(): ASTNode {

    const children: ASTNode[] = [];

    while (current < tokens.length) {

      const token = tokens[current];

      switch (token.type) {

        case "text":

          // 处理 text 类型

          children.push({ type: "text", value: token.value! });

          current++;

          break;

        case "header":

          // 处理 header 类型

          children.push({

            type: "header",

            level: token.level!,

            content: token.content!,

          });

          current++;

          break;

        case "bold":

          // 处理 bold 类型

          children.push({ type: "bold", content: token.content! });

          current++;

          break;

        case "italic":

          // 处理 italic 类型

          children.push({ type: "italic", content: token.content! });

          current++;

          break;

        case "strikethrough":

          // 处理 strikethrough 类型

          children.push({ type: "strikethrough", content: token.content! });

          current++;

          break;

        case "link":

          // 处理 link 类型

          children.push({

            type: "link",

            href: token.href!,

            text: token.text!,

          });

          current++;

          break;

        case "image":

          // 处理 image 类型

          children.push({

            type: "image",

            src: token.src!,

            alt: token.alt!,

          });

          current++;

          break;

        case "code":

          // 处理 inline code 类型

          children.push({ type: "code", content: token.content! });

          current++;

          break;

        case "code_block":

          // 处理 code block 类型

          children.push({ type: "code_block", content: token.content! });

          current++;

          break;

        case "blockquote":

          // 处理 blockquote 类型

          children.push({

            type: "blockquote",

            children: [{ type: "text", value: token.content! }],

          });

          current++;

          break;

        case "newline":

          // 处理 newline 类型

          children.push({ type: "newline" });

          current++;

          break;

        case "complex":

          // 处理 complex 类型,多个样式组合

          children.push({

            type: "complex",

            content: token.content!,

            children: token.children!, // 保存组合的样式信息

          });

          current++;

          break;

        case "order_list":

          children.push({

            type: "order_list",

            content: token.value,

            start: token.start,

            nestedItems: token.listArr

              ? token.listArr.map((item) => ({

                  type: "order_list",

                  content: item.value,

                  start: item.start,

                }))

              : [], // 如果 `listArr` 存在,则递归解析子项,否则为空数组

          });

          current++;

          break;

        case "unorder_list":

          children.push({

            type: "unorder_list",

            content: token.value,

          });

          current++;

          break;

        default:

          current++;

          break;

      }

    }

    // 返回包含所有内容的文档节点

    return { type: "document", children };

  }

  return parse();

}

设计亮点

  • 使用递归下降解析器模式
  • 统一的 AST 节点结构
  • 支持嵌套结构(如列表项)

4. 渲染器 (`src/render.ts`)

渲染器将 AST 转换为 HTML 字符串。

核心渲染函数

src/render.ts

function render(ast: ASTNode): string {

  switch (ast.type) {

    case "document":

      return ast.children.map((child) => render(child)).join("");

    case "header":

      return `<h${ast.level}>${ast.content}</h${ast.level}>`;

    case "bold":

      return `<strong>${ast.content}</strong>`;

    case "italic":

      return `<em>${ast.content}</em>`;

    case "strikethrough":

      return `<del>${ast.content}</del>`;

    case "text":

      return ast.value;

    case "link":

      return `<a href="${ast.href}" target="_blank" rel="nofollow">${ast.text}</a>`;

    case "image":

      return `<img src="${ast.src}" alt="${ast.alt}">`;

    case "blockquote":

      return `<blockquote>${ast.children

        .map((child) => render(child))

        .join("")}</blockquote>`;

    case "horizontal_rule":

      return `<hr>`;

    case "code":

      return `<code>${ast.content}</code>`;

    case "code_block":

      return `<pre><code>${ast.content}</code></pre>`;

    case "newline":

      // 确保处理换行符

      return `<br>`;

    case "order_list":

      return `<ol start = ${ast.start ?? "1"}><li>${ast.content}</li></ol>`;

    case "unorder_list":

      return `<ul><li>${ast.content}</li></ul>`;

    case "complex":

      return renderComplex(ast.content, ast.children);

    default:

      return "";

  }

}

复杂样式渲染

src/render.ts

function renderComplex(content: string, children: String[]): string {

  if (children.length === 0) {

    return content;

  }

  const style = children[0]; // 取出当前需要应用的样式

  const remainingStyles = children.slice(1); // 剩下的样式继续递归

  let ans = content.split(" ");

  switch (style) {

    case "bold":

      return `<strong>${renderComplex(content, remainingStyles)}</strong>`;

    case "italic":

      return `<em>${renderComplex(content, remainingStyles)}</em>`;

    case "strikethrough":

      return `<del>${renderComplex(content, remainingStyles)}</del>`;

    case "code":

      return `<code>${renderComplex(content, remainingStyles)}</code>`;

    case "link":

      return `<a href="${

        ans[1]

      }" target="_blank" rel="nofollow">${renderComplex(

        ans[0],

        remainingStyles

      )}</a>`;

    case "image":

      return `<img src="${ans[1]}" alt="${ans[0]}">`; // 图片不需要嵌套

    default:

      return renderComplex(content, remainingStyles); // 未知类型,继续递归

  }

}

设计亮点

  • 递归渲染,支持嵌套结构
  • 复杂样式通过递归方式处理,保证正确的 HTML 标签嵌套
  • 链接自动添加 `target=”_blank”` 和 `rel=”nofollow”` 属性

5. 正则表达式定义 (`src/common/html_regexp.ts`)

所有用于匹配 Markdown 语法的正则表达式都集中定义在这个文件中,便于维护和扩展。

src/common/html_regexp.ts

// 匹配一级标题(#)

// 例如: # 一级标题

export const h1Regex = /^#\s(.*)$/gm;

// 匹配二级标题(##)

// 例如: ## 二级标题

export const h2Regex = /^##\s(.*)$/gm;

// 匹配三级标题(###)

// 例如: ### 三级标题

export const h3Regex = /^###\s(.*)$/gm;

// 匹配四级标题(####)

// 例如: #### 四级标题

export const h4Regex = /^####\s(.*)$/gm;

// 匹配五级标题(#####)

// 例如: ##### 五级标题

export const h5Regex = /^#####\s(.*)$/gm;

// 匹配六级标题(######)

// 例如: ###### 六级标题

export const h6Regex = /^######\s(.*)$/gm;

// 匹配加粗文本(**bold** 或 __bold__)

// 例如: **加粗文本**

export const boldRegex = /\*\*(.*)\*\*/gm;

// 匹配加粗文本(__bold__)替代格式

// 例如: __加粗文本__

export const boldAltRegex = /__(.*)__/gm;

// 匹配斜体文本(*italic* 或 _italic_)

// 例如: *斜体文本* 或 _斜体文本_

export const italicRegex = /\*(.*)\*/gm;

// 匹配斜体文本(_italic_)替代格式

// 例如: _斜体文本_

export const italicAltRegex = /_(.*)_/gm;

// 匹配删除线文本(~~strikethrough~~)

// 例如: ~~删除线文本~~

export const strikethroughRegex = /~~(.*)~~/gm;

// 匹配链接([text](url))

// 例如: [点击这里](https://example.com)

export const linkRegex = /\[(.*?)\]\((.*?)\)/gm;

// 匹配图片(![alt](url))

// 例如: ![图片描述](https://example.com/image.jpg)

export const imageRegex = /!\[(.*?)\]\((.*?)\)/gm;

// 匹配行内代码(`code`)

// 例如: `console.log("Hello, world!");`

export const inlineCodeRegex = /`(.*?)`/gm;

// 匹配代码块(```code block```)

// 例如: ```

//  function hello() {

//      console.log("Hello");

//  }

// ```

export const codeBlockRegex = /```([\s\S]*?)```/gm;

// 匹配换行符(用于处理换行)

// 例如: \n

export const lineBreakRegex = /\n/gm;

// 匹配无序列表项(星号 *)

// 例如: * 列表项

export const unorderedListItemRegex = /^\*\s(.*)$/gm;

// 匹配无序列表项(加号 +)

// 例如: + 列表项

export const unorderedListItemAltRegex = /^\+\s(.*)$/gm;

// 匹配无序列表项(减号 -)

// 例如: - 列表项

export const unorderedListItemAlt2Regex = /^-\s(.*)$/gm;

// 匹配有序列表项(数字加点)

// 例如: 1. 列表项

export const orderedListItemRegex = /^\d+\.\s(.*)$/gm;

设计亮点

  • 集中管理所有正则表达式,便于维护
  • 每个正则都有详细的注释说明
  • 支持多种 Markdown 语法变体(如 `**bold**` 和 `__bold__`)

📦 安装使用

安装

npm install markdown2html-parser

基本使用

ESM 导入

import { convertMarkdownToHtml } from "markdown2html-parser";

const markdown = "# Hello World\n\nThis is **bold** text.";

const html = convertMarkdownToHtml(markdown);

console.log(html);

// 输出: <h1>Hello World</h1><br><br>This is <strong>bold</strong> text.

CommonJS 导入

const { convertMarkdownToHtml } = require("markdown2html-parser");

const markdown = "# Hello World\n\nThis is **bold** text.";

const html = convertMarkdownToHtml(markdown);

console.log(html);

默认导入

import convertMarkdownToHtml from "markdown2html-parser";

const html = convertMarkdownToHtml(markdown);

高级使用

如果需要单独使用词法分析器或语法分析器:

import { lexMarkdown, parseMarkdown, convertMarkdownToHtml } from "markdown2html-parser";

// 只进行词法分析

const tokens = lexMarkdown("# Hello World");

// 进行词法和语法分析

const tokens = lexMarkdown("# Hello World");

const ast = parseMarkdown(tokens);

// 完整转换

const html = convertMarkdownToHtml("# Hello World");

📚 API 文档

convertMarkdownToHtml(input: string): string

将 Markdown 文本转换为 HTML 字符串。

参数

input(string): 要转换的 Markdown 文本

返回

string: 转换后的 HTML 字符串

示例

const html = convertMarkdownToHtml("# Title\n\n**Bold** text");

lexMarkdown(input: string): Token[]

将 Markdown 文本解析为 Token 数组(词法分析)。

参数

`input` (string): 要解析的 Markdown 文本

返回

`Token[]`: Token 数组

parseMarkdown(tokens: Token[]): ASTNode

将 Token 数组解析为 AST(语法分析)。

参数

– `tokens` (Token[]): Token 数组

返回

– `ASTNode`: 抽象语法树根节点

📝 支持语法

标题

```markdown

# H1 标题

## H2 标题

### H3 标题

#### H4 标题

##### H5 标题

###### H6 标题

```

### 文本样式

```markdown

**加粗文本** 或 __加粗文本__

*斜体文本* 或 _斜体文本_

~~删除线文本~~

```

### 链接和图片

```markdown

[链接文本](https://example.com)

![图片描述](https://example.com/image.jpg)

```

### 代码

```markdown

行内代码:`const x = 1;`

代码块:

```

function hello() {

  console.log("Hello");

}

```

```

### 列表

```markdown

有序列表:

1. 第一项

2. 第二项

无序列表(三种方式):

* 项目一

+ 项目二

- 项目三

```

### 引用

```markdown

> 这是一个引用块

```

### 分隔线

```markdown

---

```

### 复杂组合

支持多种样式的组合,例如:

```markdown

**[加粗链接](https://example.com)**

*斜体加粗文本*

```

🛠️ 技术栈

  • TypeScript: 提供类型安全和更好的开发体验
  • Node.js: 运行环境
  • 正则表达式: 用于 Markdown 语法匹配

📄 许可证

本项目遵循 ISC 许可证。

👤 作者

Horizon

📅 版本历史

v0.0.5 (当前版本)

  • 完整的 Markdown 语法支持
  • 模块化架构设计
  • ESM 和 CommonJS 双模块支持

v0.0.2

  • 新增列表解析功能
  • 优化导入方式,支持多种导入模式

注意:本项目仍在积极开发中,欢迎提交 Issue 和 Pull Request!

你是楼外的蒹葭 也是今晚的明月
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇