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-syntaxUsage
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 validateoptions(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
- @bernierllc/validators-core - Core types and interfaces
- @bernierllc/validators-utils - Shared utilities for parsing
- @bernierllc/validators-runner - Validation orchestration
License
Copyright (c) 2025 Bernier LLC. All rights reserved.