# @bernierllc/validators-markdown-structure

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

## Installation

```bash
npm install @bernierllc/validators-markdown-structure
```

## Usage

### Basic Validation

```typescript
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

```typescript
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:

```markdown
<!-- ✓ 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:

```markdown
<!-- ✓ 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:

```markdown
<!-- ✓ 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:

````markdown
<!-- ✓ 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

```typescript
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:

```typescript
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:

```typescript
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

```typescript
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

```typescript
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

```typescript
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

- [@bernierllc/validators-core](../validators-core) - Core validation types and utilities
- [@bernierllc/validators-runner](../validators-runner) - Validation orchestration
- [@bernierllc/validators-reporters](../validators-reporters) - Result formatting
- [@bernierllc/markdown-detector](../../core/markdown-detector) - Markdown flavor detection

## Contributing

See the [BernierLLC validators principles](../../../docs/validators-principles.md) 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.
