JSPM

@bernierllc/validators-html-syntax

0.1.1
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 7
  • Score
    100M100P100Q70648F
  • License UNLICENSED

HTML syntax validation primitive - malformed tags, nesting, duplicate IDs, unclosed tags

Package Exports

  • @bernierllc/validators-html-syntax
  • @bernierllc/validators-html-syntax/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@bernierllc/validators-html-syntax) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

@bernierllc/validators-html-syntax

HTML syntax validation primitive - validates HTML for well-formedness, proper nesting, duplicate IDs, unclosed tags, and malformed attributes.

Installation

npm install @bernierllc/validators-html-syntax

Usage

Basic Validation

import { validateHtmlSyntax } from '@bernierllc/validators-html-syntax';
import { parseHtml } from '@bernierllc/validators-utils';

const html = `
  <!DOCTYPE html>
  <html>
    <body>
      <div id="header">Header</div>
      <div id="header">Duplicate ID!</div>
    </body>
  </html>
`;

const utils = { parseHtml, /* ... other utils */ };
const result = await validateHtmlSyntax(html, {}, utils);

if (result.problems.length > 0) {
  console.log('HTML syntax issues found:');
  result.problems.forEach(problem => {
    console.log(`- ${problem.message}`);
    console.log(`  Severity: ${problem.severity}`);
    console.log(`  Rule: ${problem.ruleId}`);
  });
}

Creating a Configured Validator

import { createHtmlSyntaxValidator } from '@bernierllc/validators-html-syntax';

const validator = createHtmlSyntaxValidator({
  checkDuplicateIds: true,
  checkUnclosedTags: true,
  checkInvalidNesting: true,
  checkMalformedAttributes: true,
});

// Reuse the validator
const result1 = await validator.validate(html1, utils);
const result2 = await validator.validate(html2, utils);

// Get validator metadata
const meta = validator.getMeta();
console.log(`Validator: ${meta.name} v${meta.version}`);
console.log(`Enabled rules: ${meta.enabledRules.join(', ')}`);

Using Individual Rules

import { duplicateIdsRule, unclosedTagsRule } from '@bernierllc/validators-html-syntax';
import { createRuleContext } from '@bernierllc/validators-core';

const problems = [];
const context = createRuleContext(
  'html-syntax/duplicate-ids',
  {},
  utils,
  {},
  (problem) => problems.push(problem)
);

const validator = duplicateIdsRule.create(context);
await validator(html);

console.log(`Found ${problems.length} duplicate ID issues`);

API Reference

validateHtmlSyntax(html, options?, utils)

Validates HTML syntax and returns validation results.

Parameters:

  • html (string): The HTML content to validate
  • options (HtmlSyntaxOptions): Validation options (optional)
  • utils (SharedUtils): Utility functions for parsing and validation

Returns: Promise<ValidationResult>

Example:

const result = await validateHtmlSyntax(html, {
  checkDuplicateIds: true,
  checkUnclosedTags: true,
}, utils);

createHtmlSyntaxValidator(options?)

Creates a reusable HTML syntax validator with configured options.

Parameters:

  • options (HtmlSyntaxOptions): Validation options (optional)

Returns: Object with validate() and getMeta() methods

Example:

const validator = createHtmlSyntaxValidator({
  checkInvalidNesting: false, // Disable nesting validation
});

HtmlSyntaxOptions

Configuration options for HTML syntax validation:

interface HtmlSyntaxOptions {
  /** Check for duplicate IDs (default: true) */
  checkDuplicateIds?: boolean;

  /** Check for unclosed tags (default: true) */
  checkUnclosedTags?: boolean;

  /** Check for invalid nesting (default: true) */
  checkInvalidNesting?: boolean;

  /** Check for malformed attributes (default: true) */
  checkMalformedAttributes?: boolean;

  /** Check for invalid self-closing tags (default: true) */
  checkSelfClosingTags?: boolean;

  /** Check for invalid entity references (default: true) */
  checkEntityReferences?: boolean;

  /** Check for missing or invalid DOCTYPE (default: false) */
  checkDoctype?: boolean;
}

Validation Rules

html-syntax/duplicate-ids

Detects duplicate ID attributes in the HTML document. Each ID must be unique.

Example violations:

<!-- INVALID: Duplicate IDs -->
<div id="main">First</div>
<div id="main">Second</div>

<!-- VALID: Unique IDs -->
<div id="header">Header</div>
<div id="content">Content</div>

html-syntax/unclosed-tags

Detects unclosed HTML tags and mismatched closing tags.

Example violations:

<!-- INVALID: Unclosed tag -->
<div>
  <p>Unclosed paragraph
</div>

<!-- INVALID: Mismatched tags -->
<div>
  <span>Content</div>
</span>

<!-- VALID: Properly closed -->
<div>
  <p>Closed paragraph</p>
</div>

html-syntax/invalid-nesting

Detects invalid HTML element nesting per HTML5 specification.

Example violations:

<!-- INVALID: Block element in paragraph -->
<p>
  <div>Block element</div>
</p>

<!-- INVALID: Nested paragraphs -->
<p>Outer <p>Inner</p></p>

<!-- INVALID: Nested anchors -->
<a href="/outer">
  <a href="/inner">Nested link</a>
</a>

<!-- VALID: Proper nesting -->
<div>
  <p>Paragraph</p>
  <a href="/link">Link</a>
</div>

html-syntax/malformed-attributes

Detects malformed or invalid HTML attributes.

Example violations:

<!-- INVALID: Duplicate attributes -->
<div class="first" class="second">Content</div>

<!-- INVALID: Multiple equals signs -->
<div id=="broken">Content</div>

<!-- INVALID: Invalid attribute name -->
<div 123name="value">Content</div>

<!-- VALID: Proper attributes -->
<div class="test" id="main" data-value="123">Content</div>

Validation Results

The validation result includes detailed problem information:

interface ValidationResult {
  problems: Problem[];
  stats: {
    targets: number;
    durationMs: number;
    rulesApplied: string[];
  };
}

interface Problem {
  ruleId: string;           // e.g., "html-syntax/duplicate-ids"
  message: string;          // Human-readable description
  severity: 'error' | 'warn' | 'info' | 'off';
  domain: 'parsing';
  location?: {
    file?: string;
    line?: number;
    column?: number;
    selector?: string;
  };
  suggestion?: string;      // How to fix the issue
  fixable?: boolean;        // Whether auto-fix is available
  tags?: string[];          // e.g., ['html', 'duplicate-id']
  evidence?: {
    snippet?: string;       // Code snippet showing the issue
    context?: Record<string, unknown>;
  };
}

Examples

Comprehensive Validation

import { validateHtmlSyntax } from '@bernierllc/validators-html-syntax';

const html = `
  <div id="container">
    <p>
      <div id="container">Invalid nesting and duplicate ID</div>
    </p>
    <span class="test" class="test">Duplicate attribute</span>
  </div>
  <section>
    <p>Unclosed paragraph
  </section>
`;

const result = await validateHtmlSyntax(html, {}, utils);

// Group problems by severity
const errors = result.problems.filter(p => p.severity === 'error');
const warnings = result.problems.filter(p => p.severity === 'warn');

console.log(`Found ${errors.length} errors and ${warnings.length} warnings`);
console.log(`Validated in ${result.stats.durationMs}ms`);

Selective Validation

// Only check for duplicate IDs and unclosed tags
const validator = createHtmlSyntaxValidator({
  checkDuplicateIds: true,
  checkUnclosedTags: true,
  checkInvalidNesting: false,
  checkMalformedAttributes: false,
});

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

Integration with CI/CD

import { validateHtmlSyntax } from '@bernierllc/validators-html-syntax';
import * as fs from 'fs';

async function validateHtmlFiles(files: string[]) {
  let hasErrors = false;

  for (const file of files) {
    const html = fs.readFileSync(file, 'utf-8');
    const result = await validateHtmlSyntax(html, {}, utils);

    const errors = result.problems.filter(p => p.severity === 'error');
    if (errors.length > 0) {
      console.error(`${file}: ${errors.length} errors`);
      errors.forEach(error => {
        console.error(`   ${error.message}`);
      });
      hasErrors = true;
    } else {
      console.log(`${file}: No errors`);
    }
  }

  if (hasErrors) {
    process.exit(1);
  }
}

// Run validation
validateHtmlFiles(process.argv.slice(2));

Performance

This validator is designed for high performance:

  • Incremental parsing: Only parses HTML once
  • Efficient rule execution: Rules run in parallel where possible
  • Sub-100ms target: Targets sub-100ms validation for typical HTML files
  • Memory efficient: Minimal memory overhead for large documents

Architecture

This package follows the BernierLLC validators architecture:

  • Pure validation: Returns structured results without enforcing policy
  • Composable rules: Individual rules can be used independently
  • Framework-agnostic: Works in Node.js, browsers, CI/CD, etc.
  • Evidence-rich: Provides actionable information for debugging

Integration Status

  • Logger integration: not-applicable - Pure validation primitive with no logging needs. This is a stateless validator that returns structured results without side effects. Consumers can integrate @bernierllc/logger if needed for their use case.
  • Docs-Suite: ready - Full TypeDoc documentation exported for docs-suite compatibility
  • NeverHub integration: not-applicable - Stateless validation primitive with no service discovery or event bus needs. This package uses detectNeverHub() pattern but is designed as a pure function validator that operates independently.

See Also

License

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