Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/markdown.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: markdown

on:
push:
pull_request:

permissions:
contents: read

jobs:
markdownlint:
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .node-version
cache: npm
- name: Install pinned dependencies
run: npm ci
- name: Lint repository markdown
run: npm run lint:md
- name: Markdown module fixtures test
run: bash harness/shell/run-tests.sh modules/markdown/markdown.test.sh
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ Thumbs.db

# Claude Code worktrees (per-checkout; PR worktree workflow)
.claude/worktrees/

# Node
node_modules/
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24.17.0
21 changes: 21 additions & 0 deletions fixtures/markdown/bad/Violations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Bad sample
==========

A document that violates the ruleset.

## Wrong bullets

+ plus bullet
+ another plus

## Wrong emphasis

Here is _underscore emphasis_ and __underscore strong__.

## Wrong code

indented code block, not fenced

~~~
tilde fence, not backtick
~~~
26 changes: 26 additions & 0 deletions fixtures/markdown/good/Clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Clean sample

A conforming GitHub Flavored Markdown document — it must lint clean.

## Lists

- First item
- Second item
- Third item

## Emphasis

Use *emphasis* and **strong**, both with asterisks.

## Code

```bash
echo "fenced, backtick"
```

## Table

| Name | Value |
| ---- | ----- |
| one | 1 |
| two | 2 |
37 changes: 37 additions & 0 deletions modules/markdown/.markdownlint-cli2.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
// GitHub Flavored Markdown (GFM) ruleset for markdownlint-cli2.
// Schema pinned to markdownlint-cli2 v0.22.1 — bump together on upgrade.
// Rules reference: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md
// All rules are enabled by default; only deviations are listed below.
// Globs are passed by the caller (CLI / CI), not declared here.
"$schema": "https://raw.githubusercontent.com/DavidAnson/markdownlint-cli2/v0.22.1/schema/markdownlint-cli2-config-schema.json",
"ignores": [
// Build, dependency, and cache trees — not authored markdown.
"**/node_modules/**",
"**/.venv/**",
"**/bin/**",
"**/obj/**"
],
"config": {
// --- GFM-aligned style ---
"MD003": { "style": "atx" }, // ATX headings (# Heading)
"MD004": { "style": "dash" }, // Dash unordered-list bullets
"MD049": { "style": "asterisk" }, // *emphasis*
"MD050": { "style": "asterisk" }, // **strong**
"MD046": { "style": "fenced" }, // Fenced (not indented) code blocks
"MD048": { "style": "backtick" }, // Backtick (not tilde) code fences
"MD024": { "siblings_only": true }, // Allow duplicate headings under different parents
"MD055": { "style": "consistent" }, // Consistent table pipe style within a file
"MD060": false, // Don't enforce one table-column style across mixed compact/padded tables

// --- Relaxed for GFM / prose ---
"MD013": false, // No hard line-length limit (tables and code exceed 80)
"MD025": false, // Allow multiple top-level (H1) sections
"MD028": false, // Allow blank lines between adjacent blockquotes
"MD033": false, // Allow inline HTML (<details>, <summary>, <br>, ...)
"MD034": false, // Allow bare URLs (GFM autolinks them)
"MD036": false, // Allow bold text used as a pseudo-heading
"MD040": false, // Fenced code need not declare a language
"MD041": false // First line need not be a top-level heading (frontmatter)
}
}
29 changes: 29 additions & 0 deletions modules/markdown/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Markdown module

GitHub Flavored Markdown linting via [markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2).

## Contents

- `.markdownlint-cli2.jsonc` — the GFM ruleset: ATX headings, dash bullets, asterisk emphasis, fenced backtick code, GFM table rules. Schema-pinned to markdownlint-cli2 0.22.1.

## Engine

Requires Node (pinned per-repo via `.node-version`, provided by fnm) and `markdownlint-cli2` (pinned as an npm devDependency). It exits `0` when clean and `1` on findings.

## Adopt in a repo

Two ways to apply the ruleset:

- **By reference (no copy):** keep this file in the module and point the linter at it —

```bash
npx markdownlint-cli2 --config modules/markdown/.markdownlint-cli2.jsonc "**/*.md"
```

- **Drop-in:** copy `.markdownlint-cli2.jsonc` to the consuming repo's root, where markdownlint-cli2 and the VS Code extension auto-discover it.

Pin `markdownlint-cli2` as a devDependency and Node via `.node-version` for reproducibility.

## Test

`fixtures/markdown/{good,bad}` exercise the ruleset; `markdown.test.sh` runs them on the shell harness.
32 changes: 32 additions & 0 deletions modules/markdown/markdown.test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# Tests the Markdown module: the GFM ruleset passes the good fixture and flags
# the bad fixture. Skips cleanly when markdownlint-cli2 is absent.
set -uo pipefail
# shellcheck source=harness/shell/lib.sh
source "$(git rev-parse --show-toplevel)/harness/shell/lib.sh"

root="$(git rev-parse --show-toplevel)"
cd "$root" || exit 1
config='modules/markdown/.markdownlint-cli2.jsonc'

if [ -x node_modules/.bin/markdownlint-cli2 ]; then
ml() { node_modules/.bin/markdownlint-cli2 "$@"; }
elif command -v markdownlint-cli2 >/dev/null 2>&1; then
ml() { markdownlint-cli2 "$@"; }
else
skip_suite 'markdownlint-cli2 not installed (run: npm ci)'
fi

FAILED=0
CASE_NUM=0

ml --config "$config" fixtures/markdown/good/Clean.md >/dev/null 2>&1
rc=$?
assert_exit 'good fixture exits 0' 0 "$rc"

out="$(ml --config "$config" fixtures/markdown/bad/Violations.md 2>&1)"
rc=$?
assert_exit 'bad fixture exits 1' 1 "$rc"
assert_contains 'bad fixture reports a rule' "$out" 'MD0'

[[ $FAILED -eq 0 ]] || exit 1
Loading