zemdomu
v1.3.10
Published
Semantic HTML linter for HTML, JSX, and TSX. Detects accessibility, SEO, and structure issues before deployment.
Maintainers
Readme
ZemDomu
Semantic HTML linting engine for clean, accessible and SEO-friendly markup. This package provides the shared core logic used by the ZemDomu VS Code extension and upcoming GitHub Action.
🧠 What is ZemDomu?
ZemDomu is a semantic-first linter that helps developers write better HTML and JSX by catching accessibility and structural issues. It parses .html, .jsx and .tsx files and exposes a simple lint() function that returns semantic violations.
🚀 Installation
npm install zemdomu
# or
yarn add zemdomu✨ Features
- ✅ Lint semantic issues in HTML, JSX and TSX
- 📦 Works in Node.js, CI or any JS runtime
- ⚙️ Extensible rule system with simple custom rules
- 🔀 Cross-component analysis for React/JSX projects
- 🚀 Command line interface with
--customand--cross - ⚠️ Configurable rule severity (
error,warning,off) - 📈 Performance diagnostics for profiling lint runs
- 📚 Shared by the extension and GitHub Action
- 🧪 Simple API:
lint(content, options)
⚙️ Usage Example
import { lint } from "zemdomu";
const html = "<img>";
const results = lint(html, { rules: { requireAltText: true } });
console.log(results);
// [
// {
// line: 0,
// column: 0,
// message: '<img> tag missing alt attribute',
// rule: 'requireAltText'
// }
// ]
// Custom rules can be supplied via the `customRules` option
// const myRule = { name: 'demo', test: node => false, message: 'demo' };
// lint(html, { customRules: [myRule] });📖 API
lint(content: string, options?: LinterOptions): LintResult[]
Parameters
content— HTML, JSX or TSX string inputoptions.rules— severity settings for built-in rulesoptions.customRules— array of additional rulesoptions.filePath— optional source file pathoptions.perf— attach aPerformanceRecorderinstance
Example LinterOptions
interface LinterOptions {
rules?: Record<string, 'error' | 'warning' | 'off'>;
customRules?: Rule[];
filePath?: string;
perf?: PerformanceRecorder;
}Example enabling one rule as a warning:
const results = lint(html, {
rules: { requireAltText: 'warning', uniqueIds: 'error' }
});Example LintResult
interface LintResult {
line: number;
column: number;
message: string;
rule: string;
}🛠 CLI Usage
Run the linter from the command line by installing the package globally or using
npx. Provide one or more glob patterns to specify the files to lint. Patterns
may be separated by spaces, commas or newlines:
npx zemdomu "src/**/*.{html,jsx,tsx}" --custom my-rule.js
npx zemdomu "src/**/*.html,src/**/*.jsx"Use --custom (or -c) to provide a path to a JavaScript or TypeScript module
exporting a custom rule or array of rules. Use --cross to enable cross
component analysis.
Cross-Component Analysis
When analysing JSX projects you can track <h1> usage or similar patterns
across component boundaries. Instantiate ProjectLinter with the
crossComponentAnalysis option or pass --cross to the CLI. Use
crossComponentDepth (or --cross-depth) to limit how deep component trees are
traversed during analysis:
import { ProjectLinter } from 'zemdomu';
const linter = new ProjectLinter({ crossComponentAnalysis: true, crossComponentDepth: 2 });
await linter.lintFile('App.jsx');npx zemdomu "src/**/*.{jsx,tsx}" --cross --cross-depth 2Performance Diagnostics
Attach a PerformanceDiagnostics recorder to gather timing information for each
file and rule:
import { lint, PerformanceDiagnostics } from 'zemdomu';
const perf = new PerformanceDiagnostics();
lint(code, { perf });
console.log(perf.getAsJSON());📝 Writing Custom Rules
Custom rules are simple objects implementing the Rule interface. At minimum
provide a name, a test function that returns true when a node violates the
rule and a message describing the problem:
interface Rule {
name: string;
test(node: any): boolean;
message: string;
}// my-rule.js
module.exports = {
name: 'noFooDiv',
test: node => node.type === 'element' && node.tagName === 'foo',
message: '<foo> is not allowed'
};Use it programmatically:
import { lint } from 'zemdomu';
const results = lint('<foo></foo>', { customRules: [require('./my-rule')] });Helper Utilities
For more advanced rules you may need direct access to the parsed HTML or JSX AST. ZemDomu exposes a few helpers to make this easier:
import {
parseHtml,
visitHtml,
getAttr,
getJsxAttr,
getTag,
ElementNode,
HtmlVisitor,
} from 'zemdomu';parseHtml returns the root ElementNode. The visitHtml function performs a
simple depth‑first traversal using an HtmlVisitor with optional enter and
exit callbacks. Utility functions like getAttr and getJsxAttr help reading
attributes, while getTag resolves JSX element names.
Or via the CLI:
npx zemdomu file.html --custom my-rule.js🔗 Related Tools
- ZemDomu VS Code Extension
- ZemDomu GitHub Action (coming soon)
🛠 Development
git clone https://github.com/Zemdomu/ZemDomu-core.git
cd ZemDomu-core
npm install
npm run buildTests and coverage support coming soon.
🤝 Contributing
We welcome contributions! If you'd like to add rules, improve parsing or integrate new consumers:
- Fork this repo
- Add your logic inside
src/rulesorsrc/linter.ts - Write or update tests (if applicable)
- Submit a pull request!
📄 License
MIT © 2025 Zacharias Eryd Berlin
