@bernierllc/validators-html-syntax
Version:
HTML syntax validation primitive - malformed tags, nesting, duplicate IDs, unclosed tags
122 lines (120 loc) • 4.34 kB
JavaScript
;
/*
Copyright (c) 2025 Bernier LLC
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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateHtmlSyntax = validateHtmlSyntax;
exports.createHtmlSyntaxValidator = createHtmlSyntaxValidator;
const validators_core_1 = require("@bernierllc/validators-core");
const duplicate_ids_1 = require("./rules/duplicate-ids");
const unclosed_tags_1 = require("./rules/unclosed-tags");
const invalid_nesting_1 = require("./rules/invalid-nesting");
const malformed_attributes_1 = require("./rules/malformed-attributes");
const types_1 = require("./types");
/**
* HTML Syntax Validator
*
* Validates HTML syntax for well-formedness, proper nesting, duplicate IDs,
* unclosed tags, and malformed attributes. Pure parsing validation without
* semantic or accessibility concerns.
*
* @example
* ```typescript
* import { validateHtmlSyntax } from '@bernierllc/validators-html-syntax';
*
* const html = '<div><p>Hello</div>';
* const result = await validateHtmlSyntax(html);
*
* if (result.problems.length > 0) {
* console.log('HTML syntax issues found:', result.problems);
* }
* ```
*/
async function validateHtmlSyntax(html, options = {}, utils) {
const startTime = Date.now();
const opts = { ...types_1.DEFAULT_HTML_SYNTAX_OPTIONS, ...options };
const problems = [];
// Collect enabled rules based on options
const enabledRules = [];
if (opts.checkDuplicateIds) {
enabledRules.push(duplicate_ids_1.duplicateIdsRule);
}
if (opts.checkUnclosedTags) {
enabledRules.push(unclosed_tags_1.unclosedTagsRule);
}
if (opts.checkInvalidNesting) {
enabledRules.push(invalid_nesting_1.invalidNestingRule);
}
if (opts.checkMalformedAttributes) {
enabledRules.push(malformed_attributes_1.malformedAttributesRule);
}
// Run each enabled rule
for (const rule of enabledRules) {
const context = (0, validators_core_1.createRuleContext)(rule.meta.id, {}, // Rules operate on string (HTML), options are passed via env/options separately
utils, {}, (problem) => {
problems.push(problem);
});
const ruleValidator = rule.create(context);
await ruleValidator(html);
}
const durationMs = Date.now() - startTime;
return {
problems,
stats: {
targets: 1,
durationMs,
rulesApplied: enabledRules.map((rule) => rule.meta.id),
},
};
}
/**
* Create a configured HTML syntax validator
*
* @example
* ```typescript
* import { createHtmlSyntaxValidator } from '@bernierllc/validators-html-syntax';
*
* const validator = createHtmlSyntaxValidator({
* checkDuplicateIds: true,
* checkUnclosedTags: true,
* checkInvalidNesting: false, // Disable nesting checks
* });
*
* const result = await validator.validate('<div id="test"><p>Content</p></div>', utils);
* ```
*/
function createHtmlSyntaxValidator(options = {}) {
return {
/**
* Validate HTML syntax
*/
async validate(html, utils) {
return validateHtmlSyntax(html, options, utils);
},
/**
* Get validator metadata
*/
getMeta() {
const opts = { ...types_1.DEFAULT_HTML_SYNTAX_OPTIONS, ...options };
const enabledRules = [];
if (opts.checkDuplicateIds)
enabledRules.push('html-syntax/duplicate-ids');
if (opts.checkUnclosedTags)
enabledRules.push('html-syntax/unclosed-tags');
if (opts.checkInvalidNesting)
enabledRules.push('html-syntax/invalid-nesting');
if (opts.checkMalformedAttributes)
enabledRules.push('html-syntax/malformed-attributes');
return {
name: '@bernierllc/validators-html-syntax',
version: '0.1.0',
description: 'HTML syntax validation primitive',
domain: 'parsing',
enabledRules,
};
},
};
}