AbdulElahGwaith's picture
Upload folder using huggingface_hub
88df9e4 verified

Content Linter

For an overview of what the content linter is and how to use it, see Using the content linter.

This README shows you how to contribute to the content linter code by adding new rules, modifying existing rules, or updating the scripts used to run the content linter.

Step-by-step workflow

Before creating a new rule, check that it doesn't already exist in Markdownlint or open-source plugins.

1. Create rule file

Create a new file in src/content-linter/lib/linting-rules directory. File name should match the rule name (e.g., no-whitespace.ts). Use the template above or review existing rules for patterns.

2. Add to custom rules array

Import the rule and add it to the rules array in src/content-linter/lib/linting-rules/index.ts.

3. Configure the rule

Add configuration to src/content-linter/style/github-docs.ts:

  • githubDocsConfig - Primary area for new rules
  • githubDocsFrontmatterConfig - Rules that check frontmatter and need frontmatter line numbers
  • searchReplaceConfig - Simple string/regex checks

Required properties:

  • severity: 'error' (default) or 'warning'
  • 'partial-markdown-files': true if rule can run on data directory files
  • 'precommitSeverity': Optional different severity for local commits

4. Add unit test

Create test file in src/content-linter/tests/unit with same name as rule file. Test positive/negative cases, line numbers, ranges, and auto-fixes.

Quick reference

Rule creation checklist:

  • Create rule file in src/content-linter/lib/linting-rules/
  • Import and add to src/content-linter/lib/linting-rules/index.ts
  • Register in src/content-linter/style/github-docs.ts
  • Add unit tests in src/content-linter/tests/unit/

Locations:

  • Rule logic: src/content-linter/lib/linting-rules/*.ts
  • Rule registration: src/content-linter/lib/linting-rules/index.ts
  • Rule configuration: src/content-linter/style/github-docs.ts
  • Unit tests: src/content-linter/tests/unit/*.ts

Common patterns:

  • Rule IDs: GHD### format (start with GHD030+ for upstream candidates)
  • Frontmatter rules: Use githubDocsFrontmatterConfig section
  • Simple string checks: Use searchReplaceConfig section
  • Error severity: Default to 'error', use 'warning' sparingly

Rule template:

import { addError } from 'markdownlint-rule-helpers'

export const ruleNameHere = {
  names: ['GHD###', 'descriptive-rule-name'],
  description: 'One sentence description without ending punctuation',
  tags: ['appropriate', 'tags'],
  parser: 'markdownit',
  function: (params, onError) => {
    // Rule logic here
    addError(onError, lineNumber, description, line, range, fixInfo)
  },
}

Rule development details

Helper utilities

Use helper functions from markdownlint-rule-helpers instead of custom logic. Review utils and liquid-utils for GitHub Docs-specific helpers.

Setting errors

Import error functions from markdownlint-rule-helpers. Use addError for most cases, addErrorContext for specific ranges, addErrorDetailIf for expected vs actual results.

Async rules

To use asynchronous code, set asynchronous: true in the exported object. See Markdownlint async documentation.

Reading the data directory

Use getDataByLanguage or getDeepDataByLanguage from lib/get-data.ts for testable data access. See liquid-data-tags.ts for examples.

Rule metadata

names: First name is rule ID (GHD### format), second is readable name matching file name. Rules for upstream use start with GHD03X.

description: One sentence describing the violation without end punctuation.

tags: Categorize rules using existing tags (see table below).

Tags for rule categories

Tag Description
code Rules that check for violations in code blocks.
images Rules that check for violations in image tags.
links Rules that check for violations in links.
url Rules that check for violations in URLs.
ul Rules that check for violations in unordered lists.
ol Rules that check for violations in ordered lists.
accessibility Rules that check for accessibility violations.
format Rules that check for formatting violations.
single-source Rules that check for violations in single-sourced content (e.g., data reusable or variable usage enforcement).
frontmatter Rules that check for violations in frontmatter.
liquid Rules that check for violations in Liquid.
versioning Rules that check for violations in Liquid versioning. Rules with this tag typically have the liquid tag too.
feature Rules that check for violations specific to a feature in the docs platform (e.g., early-access, code annotations) or a GitHub feature (e.g., GitHub Actions). Rules with this tag should also include a tag with the feature name.
annotate Rules that check for violations in code annotations. Rules with this tag should also include the feature tag.
actions Rules that check for violations in GitHub Actions. Rules with this tag should also include the feature tag.
early-access Rules that check for violations in early-access content. Rules with this tag should also include the feature tag.

Configuration reference

Rules are configured in src/content-linter/style/github-docs.ts with these sections:

  • githubDocsConfig - Primary area for new rules (frontmatter separated automatically)
  • githubDocsFrontmatterConfig - Rules that check frontmatter and need frontmatter line numbers
  • githubMarkdownlintConfig - Rules from markdownlint-github
  • searchReplaceConfig - Simple search/replace checks

Configuration options

severity: 'error' (enforced) or 'warning' (displayed but not enforced). Default to 'error'.

partial-markdown-files: true if rule can run on data directory files, false otherwise.

precommitSeverity: Optional different severity for local commits vs CI. Rarely needed.

Testing rules

Test on real content:

npm run lint-content -- --paths <file-path> --rules <rule-name>

Unit tests must include positive/negative cases, line numbers, ranges, and auto-fix testing.

Updating content for new rules

When adding error-level rules with many existing violations:

  1. Autofix: Use the rule's auto-fix if available
  2. Disable comments: Use disable-rules.ts to add disable comments
  3. Manual fixes: Fix violations manually (most time-consuming)
  4. Warning severity: Temporarily set to warning if too many violations exist

Scripts and tools

Using the search-replace plugin

Add simple string/regex checks to the searchReplaceConfig rules array in github-docs.ts.

Note: Regexes must be double-escaped (e.g., /\\./ not /\./). Test regexes at regexr.com.

Limitation: Cannot disable individual search-replace rules - must disable all with <!-- markdownlint-disable-line search-replace -->.

Adding context to base rules

To add context to base rule error messages, add a context property in base.ts:

'fenced-code-language': {
  severity: 'error',
  context: 'When you add a fenced code block, you must specify the code language...',
},

System architecture

The linter system has multiple moving parts:

Three reporting surfaces

  1. CI - runs lint-content.ts on diffed paths
  2. precommit - runs lint-content.ts with --precommit flag on diffed paths
  3. automated report - runs lint-content.ts on all paths, then lint-report.ts

Severity system

  • Two severities: warning and error
  • Two severity types: severity and precommitSeverity

Four linter types

  1. Native markdownlint (in base.ts)
  2. GitHub markdown linters (in github-docs.ts)
  3. Markdownlint search-replace (in github-docs.ts)
  4. Custom docs linters (in github-docs.ts + individual files in src/content-linter/lib/linting-rules/)

Only type #4 requires individual rule files - the rest are imports.