Claude-skill-registry-data markdownlint-integration
Integrate markdownlint into development workflows including CLI usage, programmatic API, CI/CD pipelines, and editor integration.
git clone https://github.com/majiayu000/claude-skill-registry-data
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/markdownlint-integration" ~/.claude/skills/majiayu000-claude-skill-registry-data-markdownlint-integration && rm -rf "$T"
data/markdownlint-integration/SKILL.mdMarkdownlint Integration
Master integrating markdownlint into development workflows including CLI usage, programmatic API (sync/async/promise), CI/CD pipelines, pre-commit hooks, and editor integration.
Overview
Markdownlint can be integrated into various parts of your development workflow to ensure consistent markdown quality. This includes command-line tools, programmatic usage in Node.js, continuous integration pipelines, Git hooks, and editor plugins.
Command-Line Interface
markdownlint-cli Installation
npm install -g markdownlint-cli # or as dev dependency npm install --save-dev markdownlint-cli
Basic CLI Usage
# Lint all markdown files in current directory markdownlint '**/*.md' # Lint specific files markdownlint README.md CONTRIBUTING.md # Lint with configuration file markdownlint -c .markdownlint.json '**/*.md' # Ignore specific files markdownlint '**/*.md' --ignore node_modules # Fix violations automatically markdownlint -f '**/*.md' # Output to file markdownlint '**/*.md' -o linting-results.txt
Advanced CLI Options
# Use custom config markdownlint --config config/markdown-lint.json docs/ # Ignore patterns from file markdownlint --ignore-path .gitignore '**/*.md' # Use multiple ignore patterns markdownlint --ignore node_modules --ignore dist '**/*.md' # Enable specific rules only markdownlint --rules MD001,MD003,MD013 '**/*.md' # Disable specific rules markdownlint --disable MD013 '**/*.md' # Show output in JSON format markdownlint --json '**/*.md' # Quiet mode (exit code only) markdownlint -q '**/*.md' # Verbose output markdownlint --verbose '**/*.md'
CLI Configuration File
.markdownlint-cli.json:
{ "config": { "default": true, "MD013": { "line_length": 100 } }, "files": ["**/*.md"], "ignores": [ "node_modules/**", "dist/**", "build/**" ] }
Use with:
markdownlint --config .markdownlint-cli.json
Programmatic API
Callback-Based 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); } });
Promise-Based 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); }
Synchronous API
import { lint as lintSync } from 'markdownlint/sync'; const options = { files: ['README.md'], strings: { 'inline-content': '# Test\n\nContent here.' }, config: { default: true } }; const results = lintSync(options); console.log(results.toString());
Linting Strings
const markdownlint = require('markdownlint'); const options = { strings: { 'content-1': '# Heading\n\nParagraph text.', 'content-2': '## Another heading\n\nMore content.' }, config: { default: true, 'first-line-heading': { level: 1 } } }; markdownlint(options, (err, result) => { if (!err) { const resultString = result.toString(); console.log(resultString); } });
Working with Results
import { lint } from 'markdownlint/promise'; const results = await lint({ files: ['docs/**/*.md'], config: { default: true } }); // Results is an object keyed by filename 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}`); } }); });
Reading Configuration
const markdownlint = require('markdownlint'); const { readConfigSync } = require('markdownlint/sync'); // Read configuration from file const config = readConfigSync('.markdownlint.json'); const options = { files: ['**/*.md'], config: config }; const results = markdownlint.sync(options); console.log(results.toString());
Using Custom Rules
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()); } });
Applying Fixes Programmatically
applyFix Function
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 Function
const { applyFixes } = require('markdownlint'); const input = '# Heading\n\n\nParagraph'; const errors = [ { lineNumber: 3, ruleNames: ['MD012'], ruleDescription: 'Multiple blank lines', fixInfo: { lineNumber: 3, deleteCount: -1 } } ]; const fixed = applyFixes(input, errors); console.log(fixed); // '# Heading\n\nParagraph'
Auto-Fix Workflow
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 Integration
GitHub Actions
.github/workflows/markdownlint.yml:
name: Markdownlint 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
GitHub Actions with markdownlint-cli2
name: Markdownlint 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'
Pre-commit Hooks
Using Husky
Install Husky:
npm install --save-dev husky npx husky install
Create pre-commit hook:
npx husky add .husky/pre-commit "npm run lint:md"
Add script to
package.json:
{ "scripts": { "lint:md": "markdownlint '**/*.md' --ignore node_modules", "lint:md:fix": "markdownlint -f '**/*.md' --ignore node_modules" } }
Using lint-staged
Install lint-staged:
npm install --save-dev lint-staged
Configure in
package.json:
{ "lint-staged": { "*.md": [ "markdownlint --fix", "git add" ] } }
Update pre-commit hook:
npx husky add .husky/pre-commit "npx lint-staged"
Using pre-commit Framework
.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']
Install and use:
pip install pre-commit pre-commit install pre-commit run --all-files
Editor Integration
Visual Studio Code
Install the markdownlint extension:
- Open VS Code
- Go to Extensions (Cmd+Shift+X)
- Search for "markdownlint"
- Install "markdownlint" by David Anson
Configure in
.vscode/settings.json:
{ "markdownlint.config": { "default": true, "MD013": { "line_length": 100 } }, "markdownlint.ignore": [ "node_modules/**", "dist/**" ], "editor.codeActionsOnSave": { "source.fixAll.markdownlint": true } }
Vim/Neovim
Using ALE (Asynchronous Lint Engine):
" In .vimrc or init.vim let g:ale_linters = { \ 'markdown': ['markdownlint'], \} let g:ale_fixers = { \ 'markdown': ['markdownlint'], \} let g:ale_markdown_markdownlint_options = '-c .markdownlint.json' " Enable fixing on save let g:ale_fix_on_save = 1
Sublime Text
Install via Package Control:
- Install Package Control
- Install "SublimeLinter"
- Install "SublimeLinter-contrib-markdownlint"
Configure in preferences:
{ "linters": { "markdownlint": { "args": ["-c", ".markdownlint.json"] } } }
Atom
Install packages:
apm install linter-markdownlint
Configure in Atom settings or
.atom/config.cson:
"linter-markdownlint": configPath: ".markdownlint.json"
npm Scripts Integration
package.json Scripts
{ "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-Platform Compatibility
Using cross-env for environment variables:
{ "scripts": { "lint:md": "cross-env NODE_ENV=development markdownlint '**/*.md'" }, "devDependencies": { "cross-env": "^7.0.3" } }
Docker Integration
Dockerfile
FROM node:18-alpine WORKDIR /app # Install markdownlint globally RUN npm install -g markdownlint-cli # Copy markdown files COPY . . # Run linter 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"
Run with:
docker-compose run markdownlint
Monorepo Integration
Workspace Configuration
Root
.markdownlint.json:
{ "default": true, "line-length": { "line_length": 100 } }
Root
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" } }
Package-level
packages/api/package.json:
{ "scripts": { "lint:md": "markdownlint '**/*.md'" } }
Using Lerna
{ "scripts": { "lint:md": "lerna run lint:md --stream" } }
Using Turborepo
turbo.json:
{ "pipeline": { "lint:md": { "outputs": [] } } }
Reporting and Metrics
Generate HTML Report
Using a custom script:
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 Results</h1>'; Object.keys(results).forEach(file => { html += `<h2>${file}</h2>`; html += '<ul>'; results[file].forEach(result => { html += `<li>Line ${result.lineNumber}: ${result.ruleDescription}</li>`; }); html += '</ul>'; }); html += '</body></html>'; return html; }
JSON Output for Tooling
markdownlint '**/*.md' --json > results.json
Process with jq:
markdownlint '**/*.md' --json | jq '.[] | select(length > 0)'
When to Use This Skill
- Setting up markdownlint in new projects
- Integrating linting into CI/CD pipelines
- Configuring pre-commit hooks
- Automating documentation quality checks
- Setting up editor integration
- Building custom linting workflows
- Creating automated fix scripts
- Implementing documentation standards
Best Practices
- CI/CD Integration - Always run linting in continuous integration
- Pre-commit Hooks - Catch issues before they reach version control
- Editor Integration - Get real-time feedback while writing
- Consistent Configuration - Use same config across all environments
- Auto-fix When Possible - Use -f flag to automatically fix violations
- Fail Fast - Configure CI to fail on linting errors
- Ignore Generated Files - Exclude build artifacts and dependencies
- Version Lock - Pin markdownlint version in package.json
- Document Standards - Keep documentation on linting rules
- Progressive Enhancement - Start with relaxed rules, tighten over time
- Team Communication - Discuss rule changes before applying
- Regular Updates - Keep markdownlint updated for bug fixes
- Performance Optimization - Use appropriate glob patterns
- Error Reporting - Configure meaningful error output
- Backup Before Auto-fix - Always commit before running fixes
Common Pitfalls
- Missing Ignore Patterns - Linting node_modules or build directories
- Wrong Glob Patterns - Incorrect file matching in CLI
- Config Not Found - Configuration file in wrong location
- Async/Sync Mismatch - Using sync API with async rules
- CI Timeout - Linting too many files without optimization
- No Exit Code Check - Not failing CI on linting errors
- Overwriting Files - Using auto-fix without version control
- Missing Dependencies - Not installing markdownlint in CI
- Platform Differences - Path separators differ between OS
- Large Binary Files - Accidentally linting non-markdown files
- Outdated Cache - Cached node_modules with old markdownlint
- Silent Failures - Not capturing error output in CI
- Config Conflicts - Multiple config files conflicting
- Missing Editor Config - Local linting differs from CI
- No Pre-commit Hook - Issues not caught before commit