Markdownlint集成Skill markdownlint-integration

此技能旨在将Markdownlint工具集成到开发工作流中,包括命令行界面使用、编程API调用、CI/CD管道设置、预提交钩子和编辑器集成,以提升Markdown文档质量。关键词:Markdownlint,文档检查,开发工作流,自动化,SEO。

DevOps 0 次安装 0 次浏览 更新于 3/25/2026

name: markdownlint-integration user-invocable: false description: 集成markdownlint到开发工作流中,包括CLI使用、编程API、CI/CD管道和编辑器集成。 allowed-tools: [Bash, Read]

Markdownlint 集成

掌握将markdownlint集成到开发工作流中,包括CLI使用、编程API(同步/异步/承诺)、CI/CD管道、预提交钩子和编辑器集成。

概述

Markdownlint可以集成到开发工作流的各个部分,以确保Markdown质量的一致性。这包括命令行工具、Node.js中的编程使用、持续集成管道、Git钩子和编辑器插件。

命令行界面

markdownlint-cli 安装

npm install -g markdownlint-cli
# 或作为开发依赖
npm install --save-dev markdownlint-cli

基本CLI使用

# 检查当前目录下所有Markdown文件
markdownlint '**/*.md'

# 检查特定文件
markdownlint README.md CONTRIBUTING.md

# 使用配置文件进行检查
markdownlint -c .markdownlint.json '**/*.md'

# 忽略特定文件
markdownlint '**/*.md' --ignore node_modules

# 自动修复违规
markdownlint -f '**/*.md'

# 输出到文件
markdownlint '**/*.md' -o linting-results.txt

高级CLI选项

# 使用自定义配置
markdownlint --config config/markdown-lint.json docs/

# 从文件忽略模式
markdownlint --ignore-path .gitignore '**/*.md'

# 使用多个忽略模式
markdownlint --ignore node_modules --ignore dist '**/*.md'

# 仅启用特定规则
markdownlint --rules MD001,MD003,MD013 '**/*.md'

# 禁用特定规则
markdownlint --disable MD013 '**/*.md'

# 以JSON格式显示输出
markdownlint --json '**/*.md'

# 静默模式(仅退出码)
markdownlint -q '**/*.md'

# 详细输出
markdownlint --verbose '**/*.md'

CLI配置文件

.markdownlint-cli.json:

{
  "config": {
    "default": true,
    "MD013": {
      "line_length": 100
    }
  },
  "files": ["**/*.md"],
  "ignores": [
    "node_modules/**",
    "dist/**",
    "build/**"
  ]
}

使用方式:

markdownlint --config .markdownlint-cli.json

编程API

基于回调的API

const markdownlint = require('markdownlint');

const options = {
  files: ['good.md', 'bad.md'],
  config: {
    default: true,
    'line-length': {
      line_length: 100
    }
  }
};

markdownlint(options, (err, result) => {
  if (!err) {
    console.log(result.toString());
  } else {
    console.error(err);
  }
});

基于承诺的API

import { lint as lintPromise } from 'markdownlint/promise';

const options = {
  files: ['README.md', 'docs/**/*.md'],
  config: {
    default: true,
    'no-inline-html': {
      allowed_elements: ['br', 'img']
    }
  }
};

try {
  const results = await lintPromise(options);
  console.dir(results, { colors: true, depth: null });
} catch (err) {
  console.error(err);
}

同步API

import { lint as lintSync } from 'markdownlint/sync';

const options = {
  files: ['README.md'],
  strings: {
    'inline-content': '# Test

Content here.'
  },
  config: {
    default: true
  }
};

const results = lintSync(options);
console.log(results.toString());

检查字符串

const markdownlint = require('markdownlint');

const options = {
  strings: {
    'content-1': '# Heading

Paragraph text.',
    'content-2': '## Another heading

More content.'
  },
  config: {
    default: true,
    'first-line-heading': {
      level: 1
    }
  }
};

markdownlint(options, (err, result) => {
  if (!err) {
    const resultString = result.toString();
    console.log(resultString);
  }
});

处理结果

import { lint } from 'markdownlint/promise';

const results = await lint({
  files: ['docs/**/*.md'],
  config: { default: true }
});

// 结果是以文件名为键的对象
Object.keys(results).forEach(file => {
  const fileResults = results[file];

  fileResults.forEach(result => {
    console.log(`${file}:${result.lineNumber} ${result.ruleNames.join('/')} ${result.ruleDescription}`);

    if (result.errorDetail) {
      console.log(`  Detail: ${result.errorDetail}`);
    }

    if (result.errorContext) {
      console.log(`  Context: ${result.errorContext}`);
    }
  });
});

读取配置

const markdownlint = require('markdownlint');
const { readConfigSync } = require('markdownlint/sync');

// 从文件读取配置
const config = readConfigSync('.markdownlint.json');

const options = {
  files: ['**/*.md'],
  config: config
};

const results = markdownlint.sync(options);
console.log(results.toString());

使用自定义规则

const markdownlint = require('markdownlint');
const customRule = require('./custom-rules/heading-capitalization');

const options = {
  files: ['README.md'],
  config: {
    default: true,
    'heading-capitalization': true
  },
  customRules: [customRule]
};

markdownlint(options, (err, result) => {
  if (!err) {
    console.log(result.toString());
  }
});

程序化应用修复

applyFix 函数

const { applyFix } = require('markdownlint');

const line = '  Text with extra spaces  ';
const fixInfo = {
  editColumn: 1,
  deleteCount: 2,
  insertText: ''
};

const fixed = applyFix(line, fixInfo);
console.log(fixed); // 'Text with extra spaces  '

applyFixes 函数

const { applyFixes } = require('markdownlint');

const input = '# Heading


Paragraph';
const errors = [
  {
    lineNumber: 3,
    ruleNames: ['MD012'],
    ruleDescription: 'Multiple blank lines',
    fixInfo: {
      lineNumber: 3,
      deleteCount: -1
    }
  }
];

const fixed = applyFixes(input, errors);
console.log(fixed); // '# Heading

Paragraph'

自动修复工作流

const fs = require('fs');
const markdownlint = require('markdownlint');
const { applyFixes } = require('markdownlint');

const file = 'README.md';
const content = fs.readFileSync(file, 'utf8');

const options = {
  strings: {
    [file]: content
  },
  config: {
    default: true
  }
};

markdownlint(options, (err, result) => {
  if (!err) {
    const errors = result[file] || [];

    if (errors.length > 0) {
      const fixed = applyFixes(content, errors);
      fs.writeFileSync(file, fixed, 'utf8');
      console.log(`Fixed ${errors.length} issues in ${file}`);
    }
  }
});

CI/CD 集成

GitHub Actions

.github/workflows/markdownlint.yml:

name: Markdownlint
user-invocable: false

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Run markdownlint
        run: npx markdownlint '**/*.md' --ignore node_modules

      - name: Annotate PR with results
        if: failure()
        run: |
          npx markdownlint '**/*.md' --ignore node_modules -o markdownlint-results.txt
          cat markdownlint-results.txt

使用markdownlint-cli2的GitHub Actions

name: Markdownlint
user-invocable: false

on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Run markdownlint-cli2
        uses: DavidAnson/markdownlint-cli2-action@v9
        with:
          paths: '**/*.md'

GitLab CI

.gitlab-ci.yml:

markdownlint:
  image: node:18-alpine
  stage: test
  before_script:
    - npm install -g markdownlint-cli
  script:
    - markdownlint '**/*.md' --ignore node_modules
  only:
    - merge_requests
    - main
  artifacts:
    when: on_failure
    paths:
      - markdownlint-results.txt

CircleCI

.circleci/config.yml:

version: 2.1

jobs:
  markdownlint:
    docker:
      - image: cimg/node:18.0
    steps:
      - checkout
      - run:
          name: Install markdownlint
          command: npm install -g markdownlint-cli
      - run:
          name: Run linter
          command: markdownlint '**/*.md' --ignore node_modules

workflows:
  version: 2
  build_and_test:
    jobs:
      - markdownlint

Jenkins Pipeline

Jenkinsfile:

pipeline {
    agent any

    stages {
        stage('Lint Markdown') {
            steps {
                sh 'npm install -g markdownlint-cli'
                sh 'markdownlint "**/*.md" --ignore node_modules'
            }
        }
    }

    post {
        always {
            cleanWs()
        }
        failure {
            echo 'Markdownlint found issues!'
        }
    }
}

Azure Pipelines

azure-pipelines.yml:

trigger:
  - main

pool:
  vmImage: 'ubuntu-latest'

steps:
  - task: NodeTool@0
    inputs:
      versionSpec: '18.x'
    displayName: 'Install Node.js'

  - script: |
      npm install -g markdownlint-cli
    displayName: 'Install markdownlint'

  - script: |
      markdownlint '**/*.md' --ignore node_modules
    displayName: 'Run markdownlint'

预提交钩子

使用Husky

安装Husky:

npm install --save-dev husky
npx husky install

创建预提交钩子:

npx husky add .husky/pre-commit "npm run lint:md"

添加脚本到package.json

{
  "scripts": {
    "lint:md": "markdownlint '**/*.md' --ignore node_modules",
    "lint:md:fix": "markdownlint -f '**/*.md' --ignore node_modules"
  }
}

使用lint-staged

安装lint-staged:

npm install --save-dev lint-staged

package.json中配置:

{
  "lint-staged": {
    "*.md": [
      "markdownlint --fix",
      "git add"
    ]
  }
}

更新预提交钩子:

npx husky add .husky/pre-commit "npx lint-staged"

使用pre-commit框架

.pre-commit-config.yaml:

repos:
  - repo: https://github.com/igorshubovych/markdownlint-cli
    rev: v0.37.0
    hooks:
      - id: markdownlint
        args: ['--fix']

  - repo: https://github.com/DavidAnson/markdownlint-cli2
    rev: v0.10.0
    hooks:
      - id: markdownlint-cli2
        args: ['--fix']

安装和使用:

pip install pre-commit
pre-commit install
pre-commit run --all-files

编辑器集成

Visual Studio Code

安装markdownlint扩展:

  1. 打开VS Code
  2. 转到扩展(Cmd+Shift+X)
  3. 搜索“markdownlint”
  4. 安装David Anson的“markdownlint”

.vscode/settings.json中配置:

{
  "markdownlint.config": {
    "default": true,
    "MD013": {
      "line_length": 100
    }
  },
  "markdownlint.ignore": [
    "node_modules/**",
    "dist/**"
  ],
  "editor.codeActionsOnSave": {
    "source.fixAll.markdownlint": true
  }
}

Vim/Neovim

使用ALE(异步检查引擎):

" 在.vimrc或init.vim中
let g:ale_linters = {
\   'markdown': ['markdownlint'],
\}

let g:ale_fixers = {
\   'markdown': ['markdownlint'],
\}

let g:ale_markdown_markdownlint_options = '-c .markdownlint.json'

" 启用保存时修复
let g:ale_fix_on_save = 1

Sublime Text

通过Package Control安装:

  1. 安装Package Control
  2. 安装“SublimeLinter”
  3. 安装“SublimeLinter-contrib-markdownlint”

在首选项中配置:

{
  "linters": {
    "markdownlint": {
      "args": ["-c", ".markdownlint.json"]
    }
  }
}

Atom

安装包:

apm install linter-markdownlint

在Atom设置或.atom/config.cson中配置:

"linter-markdownlint":
  configPath: ".markdownlint.json"

npm脚本集成

package.json脚本

{
  "scripts": {
    "lint": "npm run lint:md",
    "lint:md": "markdownlint '**/*.md' --ignore node_modules",
    "lint:md:fix": "markdownlint -f '**/*.md' --ignore node_modules",
    "lint:md:ci": "markdownlint '**/*.md' --ignore node_modules -o markdownlint-report.txt",
    "test": "npm run lint && npm run test:unit",
    "precommit": "lint-staged"
  }
}

跨平台兼容性

使用cross-env处理环境变量:

{
  "scripts": {
    "lint:md": "cross-env NODE_ENV=development markdownlint '**/*.md'"
  },
  "devDependencies": {
    "cross-env": "^7.0.3"
  }
}

Docker集成

Dockerfile

FROM node:18-alpine

WORKDIR /app

# 全局安装markdownlint
RUN npm install -g markdownlint-cli

# 复制Markdown文件
COPY . .

# 运行检查器
CMD ["markdownlint", "**/*.md", "--ignore", "node_modules"]

docker-compose.yml

version: '3.8'

services:
  markdownlint:
    image: node:18-alpine
    working_dir: /app
    volumes:
      - .:/app
    command: >
      sh -c "npm install -g markdownlint-cli &&
             markdownlint '**/*.md' --ignore node_modules"

运行方式:

docker-compose run markdownlint

单体仓库集成

工作空间配置

根目录.markdownlint.json

{
  "default": true,
  "line-length": {
    "line_length": 100
  }
}

根目录package.json

{
  "scripts": {
    "lint:md": "markdownlint '**/*.md' --ignore node_modules",
    "lint:md:packages": "lerna run lint:md",
    "lint:md:all": "npm run lint:md && npm run lint:md:packages"
  }
}

包级别packages/api/package.json

{
  "scripts": {
    "lint:md": "markdownlint '**/*.md'"
  }
}

使用Lerna

{
  "scripts": {
    "lint:md": "lerna run lint:md --stream"
  }
}

使用Turborepo

turbo.json

{
  "pipeline": {
    "lint:md": {
      "outputs": []
    }
  }
}

报告和指标

生成HTML报告

使用自定义脚本:

const fs = require('fs');
const markdownlint = require('markdownlint');

const options = {
  files: ['**/*.md'],
  config: { default: true }
};

markdownlint(options, (err, results) => {
  if (!err) {
    const html = generateHtmlReport(results);
    fs.writeFileSync('markdownlint-report.html', html);
  }
});

function generateHtmlReport(results) {
  let html = '<html><head><title>Markdownlint Report</title></head><body>';
  html += '<h1>Markdownlint结果</h1>';

  Object.keys(results).forEach(file => {
    html += `<h2>${file}</h2>`;
    html += '<ul>';

    results[file].forEach(result => {
      html += `<li>行 ${result.lineNumber}: ${result.ruleDescription}</li>`;
    });

    html += '</ul>';
  });

  html += '</body></html>';
  return html;
}

工具使用的JSON输出

markdownlint '**/*.md' --json > results.json

使用jq处理:

markdownlint '**/*.md' --json | jq '.[] | select(length > 0)'

何时使用此技能

  • 在新项目中设置markdownlint
  • 将检查集成到CI/CD管道中
  • 配置预提交钩子
  • 自动化文档质量检查
  • 设置编辑器集成
  • 构建自定义检查工作流
  • 创建自动修复脚本
  • 实施文档标准

最佳实践

  1. CI/CD集成 - 始终在持续集成中运行检查
  2. 预提交钩子 - 在进入版本控制前捕获问题
  3. 编辑器集成 - 在编写时获得实时反馈
  4. 一致配置 - 在所有环境中使用相同的配置
  5. 尽可能自动修复 - 使用-f标志自动修复违规
  6. 快速失败 - 配置CI在检查错误时失败
  7. 忽略生成文件 - 排除构建产物和依赖
  8. 版本锁定 - 在package.json中固定markdownlint版本
  9. 文档标准 - 保持关于检查规则的文档
  10. 渐进式增强 - 从宽松规则开始,逐步收紧
  11. 团队沟通 - 在应用前讨论规则变更
  12. 定期更新 - 更新markdownlint以获取错误修复
  13. 性能优化 - 使用适当的通配符模式
  14. 错误报告 - 配置有意义的错误输出
  15. 自动修复前备份 - 运行修复前始终提交

常见陷阱

  1. 缺失忽略模式 - 检查node_modules或构建目录
  2. 错误的通配符模式 - CLI中不正确的文件匹配
  3. 配置未找到 - 配置文件位置错误
  4. 异步/同步不匹配 - 将同步API与异步规则一起使用
  5. CI超时 - 未优化检查过多文件
  6. 无退出码检查 - 未在检查错误时失败CI
  7. 覆盖文件 - 使用自动修复而无版本控制
  8. 缺失依赖 - 未在CI中安装markdownlint
  9. 平台差异 - 不同操作系统间的路径分隔符不同
  10. 大型二进制文件 - 意外检查非Markdown文件
  11. 过时缓存 - 缓存node_modules中的旧markdownlint
  12. 静默失败 - 在CI中未捕获错误输出
  13. 配置冲突 - 多个配置文件冲突
  14. 缺失编辑器配置 - 本地检查与CI不同
  15. 无预提交钩子 - 提交前未捕获问题

资源