npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bernierllc/validators-markdown-structure

v0.3.0

Published

Markdown structure validation primitive - heading hierarchy, links, lists, code blocks

Readme

@bernierllc/validators-markdown-structure

Primitive validator for Markdown document structure validation - heading hierarchy, link references, list formatting, and code block syntax.

Installation

npm install @bernierllc/validators-markdown-structure

Usage

Basic Validation

import { validateMarkdownStructure } from '@bernierllc/validators-markdown-structure';
import { createSharedUtils } from '@bernierllc/validators-utils';

const markdown = `
# Project Title
## Introduction
### Getting Started

- Feature 1
- Feature 2

\`\`\`javascript
const example = true;
\`\`\`
`;

const utils = createSharedUtils();
const result = await validateMarkdownStructure(markdown, {}, utils);

if (result.problems.length > 0) {
  console.log('Structure issues found:');
  result.problems.forEach(problem => {
    console.log(`${problem.severity}: ${problem.message} (line ${problem.location?.line})`);
  });
}

Custom Configuration

import { createMarkdownStructureValidator } from '@bernierllc/validators-markdown-structure';

const validator = createMarkdownStructureValidator({
  checkHeadingHierarchy: true,
  checkLinkReferences: true,
  checkListFormatting: true,
  checkCodeBlocks: true,
  allowAnyFirstHeading: false,  // Require h1 first
  maxHeadingLevel: 4,            // Only allow h1-h4
  flavor: 'gfm',                 // GitHub Flavored Markdown
});

const result = await validator.validate(markdown, utils);

Features

Heading Hierarchy Validation

Ensures proper heading level progression:

<!-- ✓ Valid -->
# Title
## Section
### Subsection

<!-- ✗ Invalid - skipped level -->
# Title
### Subsection (should be h2)

<!-- ✗ Invalid - first heading not h1 -->
## Starting with h2

Rules:

  • First heading should be h1 (configurable)
  • No skipping heading levels
  • Respects maximum heading level setting

Link Reference Validation

Validates link and image references:

<!-- ✓ Valid -->
[Link text](https://example.com)
![Alt text](image.png)

[Reference link][ref]
[ref]: https://example.com

<!-- ✗ Invalid - undefined reference -->
[Broken link][missing-ref]

<!-- ✗ Invalid - empty URL -->
[Link]()

<!-- ⚠ Warning - missing alt text -->
![](image.png)

Rules:

  • Reference links must have matching definitions
  • URLs cannot be empty
  • Images should have alt text (accessibility)
  • Anchor links validated for structure

List Formatting Validation

Checks list structure and consistency:

<!-- ✓ Valid -->
- Item 1
- Item 2
  - Nested item
  - Another nested
- Item 3

<!-- ✗ Invalid - inconsistent markers -->
- Item 1
* Item 2  (mixed - and *)
- Item 3

<!-- ✗ Invalid - inconsistent indentation -->
- Item 1
  - Nested 2 spaces
   - Nested 3 spaces (inconsistent)

Rules:

  • Consistent markers within a list (-, *, or +)
  • Consistent indentation for nested items
  • Proper spacing after markers

Code Block Validation

Validates fenced code blocks:

<!-- ✓ Valid -->
```javascript
const x = 1;
```

<!-- ✗ Invalid - unclosed block -->
```javascript
const x = 1;

<!-- ⚠ Warning - missing language -->
```
plain code
```

<!-- ⚠ Warning - invalid language specifier -->
```java script with spaces
code
```

Rules:

  • Code blocks must be properly closed
  • Language specifiers recommended
  • Valid language identifier format

API Reference

validateMarkdownStructure(markdown, options, utils)

Validates Markdown document structure.

Parameters:

  • markdown (string): Markdown content to validate
  • options (MarkdownStructureOptions): Validation options
  • utils (SharedUtils): Shared utilities from validators-utils

Returns: Promise<ValidationResult>

createMarkdownStructureValidator(options)

Creates a configured validator instance.

Parameters:

  • options (MarkdownStructureOptions): Validation options

Returns: Validator object with validate() and getMeta() methods

MarkdownStructureOptions

interface MarkdownStructureOptions {
  checkHeadingHierarchy?: boolean;    // Default: true
  checkLinkReferences?: boolean;      // Default: true
  checkListFormatting?: boolean;      // Default: true
  checkCodeBlocks?: boolean;          // Default: true
  allowAnyFirstHeading?: boolean;     // Default: false
  maxHeadingLevel?: number;           // Default: 6
  flavor?: 'commonmark' | 'gfm' | 'github';  // Default: 'commonmark'
}

Parser Utilities (Advanced)

Low-level parsing functions for advanced use cases:

import {
  parseHeadings,
  parseLinks,
  parseListItems,
  parseCodeBlocks
} from '@bernierllc/validators-markdown-structure';

const headings = parseHeadings(markdown);
const links = parseLinks(markdown);
const listItems = parseListItems(markdown);
const codeBlocks = parseCodeBlocks(markdown);

Individual Rules (Advanced)

Access individual validation rules:

import {
  headingHierarchyRule,
  linkReferencesRule,
  listFormattingRule,
  codeBlocksRule
} from '@bernierllc/validators-markdown-structure';

Validation Rules

markdown-structure/heading-hierarchy

Validates proper heading level progression without skipping levels.

Severity: error (first heading), warn (skipped levels)

markdown-structure/link-references

Validates that link and image references are properly defined.

Severity: error (undefined references, empty URLs), warn (missing alt text)

markdown-structure/list-formatting

Validates consistent list formatting and indentation.

Severity: warn (inconsistent markers/indentation), info (odd indentation)

markdown-structure/code-blocks

Validates fenced code block syntax and closure.

Severity: error (unclosed blocks), warn (invalid language), info (missing language)

Integration Status

Logger Integration

  • Status: not-applicable
  • Justification: Pure validation primitive with no logging requirements. As a stateless validator, all diagnostic information is returned in the ValidationResult structure. Users can integrate with @bernierllc/logger in their consuming code if needed.

Docs-Suite

  • Status: ready
  • Format: Markdown format with TypeDoc API documentation
  • Compatibility: All documentation is exportable and compatible with docs-suite standards

NeverHub Integration

  • Status: not-applicable
  • Justification: Stateless validation primitive with no service discovery or event bus requirements. This package performs synchronous validation with no external dependencies or state. Consuming services may integrate this validator with @bernierllc/neverhub-adapter if needed for distributed validation workflows.

Examples

Strict Documentation Validation

const validator = createMarkdownStructureValidator({
  checkHeadingHierarchy: true,
  checkLinkReferences: true,
  checkListFormatting: true,
  checkCodeBlocks: true,
  allowAnyFirstHeading: false,  // Must start with h1
  maxHeadingLevel: 4,            // Limit depth
  flavor: 'gfm',
});

const result = await validator.validate(docContent, utils);
const errors = result.problems.filter(p => p.severity === 'error');

if (errors.length > 0) {
  throw new Error(`Documentation validation failed: ${errors.length} errors`);
}

Lenient Blog Post Validation

const result = await validateMarkdownStructure(blogPost, {
  checkHeadingHierarchy: true,
  checkLinkReferences: true,
  checkListFormatting: false,   // Allow flexible lists
  checkCodeBlocks: true,
  allowAnyFirstHeading: true,   // Any starting level OK
  maxHeadingLevel: 6,
}, utils);

CI/CD Integration

import { validateMarkdownStructure } from '@bernierllc/validators-markdown-structure';
import { readFileSync } from 'fs';
import { glob } from 'glob';

const files = await glob('docs/**/*.md');
let totalErrors = 0;

for (const file of files) {
  const content = readFileSync(file, 'utf-8');
  const result = await validateMarkdownStructure(content, {}, utils);

  const errors = result.problems.filter(p => p.severity === 'error');
  if (errors.length > 0) {
    console.error(`${file}: ${errors.length} errors`);
    errors.forEach(err => {
      console.error(`  Line ${err.location?.line}: ${err.message}`);
    });
    totalErrors += errors.length;
  }
}

if (totalErrors > 0) {
  process.exit(1);
}

Architecture

This is a primitive validator in the BernierLLC validators architecture:

  • Pure validation logic - No policy enforcement
  • Composable rules - Each rule has single responsibility
  • Evidence-rich results - Provides actionable error information
  • Tool-agnostic - Works in CLI, web, CI/CD, IDE plugins

Principles

  1. Validators return problems, never throw - Results are structured data
  2. Single responsibility per rule - Each rule checks one aspect
  3. Configurable severity - Implementors decide what constitutes failure
  4. Performance budgets - Fast validation for real-time feedback

Performance

  • Parsing: Single-pass with minimal overhead
  • Validation: Parallel rule execution where possible
  • Memory: Streaming-friendly for large documents
  • Target: <100ms for typical documentation files

Related Packages

Contributing

See the BernierLLC validators principles for architecture guidelines.

License

Copyright (c) 2025 Bernier LLC. All rights reserved.

This file is licensed to the client under a limited-use license. The client may use and modify this code only within the scope of the project it was delivered for. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.