zemdomu 1.3.10 โ†’ 1.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +229 -224
  2. package/out/cli.js +5 -3
  3. package/out/component-analyzer.d.ts +1 -0
  4. package/out/component-analyzer.js +437 -68
  5. package/out/component-path-resolver.js +6 -6
  6. package/out/index.d.ts +1 -0
  7. package/out/index.js +4 -1
  8. package/out/linter.d.ts +3 -0
  9. package/out/linter.js +41 -25
  10. package/out/project-linter.js +15 -3
  11. package/out/rule-codes.d.ts +25 -0
  12. package/out/rule-codes.js +36 -0
  13. package/out/rules/enforceListNesting.js +6 -44
  14. package/out/rules/requireAltText.js +20 -16
  15. package/out/rules/requireHrefOnAnchors.js +16 -5
  16. package/out/rules/requireLinkText.js +41 -16
  17. package/out/rules/utils.d.ts +6 -0
  18. package/out/rules/utils.js +114 -0
  19. package/out/sarif.js +8 -4
  20. package/out/src/cli.js +5 -3
  21. package/out/src/component-analyzer.js +437 -68
  22. package/out/src/component-path-resolver.js +6 -6
  23. package/out/src/index.js +4 -1
  24. package/out/src/linter.js +41 -25
  25. package/out/src/project-linter.js +15 -3
  26. package/out/src/rule-codes.js +36 -0
  27. package/out/src/sarif.js +8 -4
  28. package/out/src/utils/collectLocalDeps.js +38 -2
  29. package/out/src/utils/vue-sfc.js +93 -0
  30. package/out/tests/cross-heading-reversed.test.js +24 -0
  31. package/out/tests/crossComponent/cross-heading-order.test.js +5 -0
  32. package/out/tests/heading-order.test.js +24 -0
  33. package/out/tests/img-alt-dynamic.test.js +39 -0
  34. package/out/tests/link-href-text.test.js +52 -0
  35. package/out/tests/list-nesting-dynamic.test.js +27 -0
  36. package/out/tests/sarif-output.test.js +1 -1
  37. package/out/tests/vue-support.test.js +63 -0
  38. package/out/utils/collectLocalDeps.js +38 -2
  39. package/out/utils/vue-sfc.d.ts +9 -0
  40. package/out/utils/vue-sfc.js +93 -0
  41. package/package.json +74 -69
package/README.md CHANGED
@@ -1,224 +1,229 @@
1
- # ZemDomu
2
-
3
- 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.
4
-
5
- ## ๐Ÿง  What is ZemDomu?
6
-
7
- **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.
8
-
9
- ## ๐Ÿš€ Installation
10
-
11
- ```bash
12
- npm install zemdomu
13
- # or
14
- yarn add zemdomu
15
- ```
16
-
17
- ## โœจ Features
18
-
19
- - โœ… Lint semantic issues in HTML, JSX and TSX
20
- - ๐Ÿ“ฆ Works in Node.js, CI or any JS runtime
21
- - โš™๏ธ Extensible rule system with simple custom rules
22
- - ๐Ÿ”€ Cross-component analysis for React/JSX projects
23
- - ๐Ÿš€ Command line interface with `--custom` and `--cross`
24
- - โš ๏ธ Configurable rule severity (`error`, `warning`, `off`)
25
- - ๐Ÿ“ˆ Performance diagnostics for profiling lint runs
26
- - ๐Ÿ“š Shared by the extension and GitHub Action
27
- - ๐Ÿงช Simple API: `lint(content, options)`
28
-
29
- ## โš™๏ธ Usage Example
30
-
31
- ```ts
32
- import { lint } from "zemdomu";
33
-
34
- const html = "<img>";
35
- const results = lint(html, { rules: { requireAltText: true } });
36
-
37
- console.log(results);
38
- // [
39
- // {
40
- // line: 0,
41
- // column: 0,
42
- // message: '<img> tag missing alt attribute',
43
- // rule: 'requireAltText'
44
- // }
45
- // ]
46
-
47
- // Custom rules can be supplied via the `customRules` option
48
- // const myRule = { name: 'demo', test: node => false, message: 'demo' };
49
- // lint(html, { customRules: [myRule] });
50
- ```
51
-
52
- ## ๐Ÿ“– API
53
-
54
- `lint(content: string, options?: LinterOptions): LintResult[]`
55
-
56
- **Parameters**
57
-
58
- - `content` โ€” HTML, JSX or TSX string input
59
- - `options.rules` โ€” severity settings for built-in rules
60
- - `options.customRules` โ€” array of additional rules
61
- - `options.filePath` โ€” optional source file path
62
- - `options.perf` โ€” attach a `PerformanceRecorder` instance
63
-
64
- **Example `LinterOptions`**
65
-
66
- ```ts
67
- interface LinterOptions {
68
- rules?: Record<string, 'error' | 'warning' | 'off'>;
69
- customRules?: Rule[];
70
- filePath?: string;
71
- perf?: PerformanceRecorder;
72
- }
73
- ```
74
-
75
- Example enabling one rule as a warning:
76
-
77
- ```ts
78
- const results = lint(html, {
79
- rules: { requireAltText: 'warning', uniqueIds: 'error' }
80
- });
81
- ```
82
-
83
- **Example `LintResult`**
84
-
85
- ```ts
86
- interface LintResult {
87
- line: number;
88
- column: number;
89
- message: string;
90
- rule: string;
91
- }
92
- ```
93
-
94
- ## ๐Ÿ›  CLI Usage
95
-
96
- Run the linter from the command line by installing the package globally or using
97
- `npx`. Provide one or more glob patterns to specify the files to lint. Patterns
98
- may be separated by spaces, commas or newlines:
99
-
100
- ```bash
101
- npx zemdomu "src/**/*.{html,jsx,tsx}" --custom my-rule.js
102
- npx zemdomu "src/**/*.html,src/**/*.jsx"
103
- ```
104
-
105
- Use `--custom` (or `-c`) to provide a path to a JavaScript or TypeScript module
106
- exporting a custom rule or array of rules. Use `--cross` to enable cross
107
- component analysis.
108
-
109
- ### Cross-Component Analysis
110
-
111
- When analysing JSX projects you can track `<h1>` usage or similar patterns
112
- across component boundaries. Instantiate `ProjectLinter` with the
113
- `crossComponentAnalysis` option or pass `--cross` to the CLI. Use
114
- `crossComponentDepth` (or `--cross-depth`) to limit how deep component trees are
115
- traversed during analysis:
116
-
117
- ```ts
118
- import { ProjectLinter } from 'zemdomu';
119
- const linter = new ProjectLinter({ crossComponentAnalysis: true, crossComponentDepth: 2 });
120
- await linter.lintFile('App.jsx');
121
- ```
122
-
123
- ```bash
124
- npx zemdomu "src/**/*.{jsx,tsx}" --cross --cross-depth 2
125
- ```
126
-
127
- ### Performance Diagnostics
128
-
129
- Attach a `PerformanceDiagnostics` recorder to gather timing information for each
130
- file and rule:
131
-
132
- ```ts
133
- import { lint, PerformanceDiagnostics } from 'zemdomu';
134
- const perf = new PerformanceDiagnostics();
135
- lint(code, { perf });
136
- console.log(perf.getAsJSON());
137
- ```
138
-
139
- ## ๐Ÿ“ Writing Custom Rules
140
-
141
- Custom rules are simple objects implementing the `Rule` interface. At minimum
142
- provide a `name`, a `test` function that returns `true` when a node violates the
143
- rule and a `message` describing the problem:
144
-
145
- ```ts
146
- interface Rule {
147
- name: string;
148
- test(node: any): boolean;
149
- message: string;
150
- }
151
- ```
152
-
153
- ```js
154
- // my-rule.js
155
- module.exports = {
156
- name: 'noFooDiv',
157
- test: node => node.type === 'element' && node.tagName === 'foo',
158
- message: '<foo> is not allowed'
159
- };
160
- ```
161
-
162
- Use it programmatically:
163
-
164
- ```ts
165
- import { lint } from 'zemdomu';
166
- const results = lint('<foo></foo>', { customRules: [require('./my-rule')] });
167
- ```
168
-
169
- ### Helper Utilities
170
-
171
- For more advanced rules you may need direct access to the parsed HTML or JSX
172
- AST. ZemDomu exposes a few helpers to make this easier:
173
-
174
- ```ts
175
- import {
176
- parseHtml,
177
- visitHtml,
178
- getAttr,
179
- getJsxAttr,
180
- getTag,
181
- ElementNode,
182
- HtmlVisitor,
183
- } from 'zemdomu';
184
- ```
185
-
186
- `parseHtml` returns the root `ElementNode`. The `visitHtml` function performs a
187
- simple depthโ€‘first traversal using an `HtmlVisitor` with optional `enter` and
188
- `exit` callbacks. Utility functions like `getAttr` and `getJsxAttr` help reading
189
- attributes, while `getTag` resolves JSX element names.
190
-
191
- Or via the CLI:
192
-
193
- ```bash
194
- npx zemdomu file.html --custom my-rule.js
195
- ```
196
-
197
- ## ๐Ÿ”— Related Tools
198
-
199
- - [ZemDomu VS Code Extension](https://marketplace.visualstudio.com/items?itemName=ZachariasErydBerlin.zemdomu)
200
- - ZemDomu GitHub Action (coming soon)
201
-
202
- ## ๐Ÿ›  Development
203
-
204
- ```bash
205
- git clone https://github.com/Zemdomu/ZemDomu-core.git
206
- cd ZemDomu-core
207
- npm install
208
- npm run build
209
- ```
210
-
211
- Tests and coverage support coming soon.
212
-
213
- ## ๐Ÿค Contributing
214
-
215
- We welcome contributions! If you'd like to add rules, improve parsing or integrate new consumers:
216
-
217
- 1. Fork this repo
218
- 2. Add your logic inside `src/rules` or `src/linter.ts`
219
- 3. Write or update tests (if applicable)
220
- 4. Submit a pull request!
221
-
222
- ## ๐Ÿ“„ License
223
-
224
- MIT ยฉ 2025 Zacharias Eryd Berlin
1
+ # ZemDomu Core
2
+
3
+ Semantic HTML linting engine for clean, accessible, and SEO-friendly markup.
4
+ This package provides the shared core logic used by the ZemDomu VS Code
5
+ extension and the GitHub Action.
6
+
7
+ ## What it is
8
+
9
+ ZemDomu is a semantic-first linter that helps developers write better HTML and
10
+ JSX by catching accessibility and structural issues. It parses `.html`, `.jsx`,
11
+ `.tsx`, and `.vue` files and exposes a simple `lint()` function that returns
12
+ semantic violations.
13
+
14
+ ## Features
15
+
16
+ - Lint semantic issues in HTML, JSX, TSX, and Vue templates.
17
+ - Works in Node.js, CI, or any JS runtime.
18
+ - Extensible rule system with simple custom rules.
19
+ - Cross-component analysis for React/JSX and Vue projects.
20
+ - Command line interface with `--custom` and `--cross`.
21
+ - Configurable rule severity (`error`, `warning`, `off`).
22
+ - Performance diagnostics for profiling lint runs.
23
+ - Shared by the extension and GitHub Action.
24
+ - Simple API: `lint(content, options)`.
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ npm install zemdomu
30
+ # or
31
+ yarn add zemdomu
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ ```ts
37
+ import { lint } from "zemdomu";
38
+
39
+ const html = "<img>";
40
+ const results = lint(html, { rules: { requireAltText: true } });
41
+
42
+ console.log(results);
43
+ // [
44
+ // {
45
+ // line: 0,
46
+ // column: 0,
47
+ // message: '<img> tag missing alt attribute',
48
+ // rule: 'requireAltText'
49
+ // }
50
+ // ]
51
+
52
+ // Custom rules can be supplied via the `customRules` option
53
+ // const myRule = { name: 'demo', test: node => false, message: 'demo' };
54
+ // lint(html, { customRules: [myRule] });
55
+ ```
56
+
57
+ ## API
58
+
59
+ `lint(content: string, options?: LinterOptions): LintResult[]`
60
+
61
+ ### Parameters
62
+
63
+ - `content`: HTML, JSX, TSX, or Vue template string input.
64
+ - `options.rules`: severity settings for built-in rules.
65
+ - `options.customRules`: array of additional rules.
66
+ - `options.filePath`: optional source file path.
67
+ - `options.perf`: attach a `PerformanceRecorder` instance.
68
+
69
+ ### Example `LinterOptions`
70
+
71
+ ```ts
72
+ interface LinterOptions {
73
+ rules?: Record<string, "error" | "warning" | "off">;
74
+ customRules?: Rule[];
75
+ filePath?: string;
76
+ forceHtml?: boolean;
77
+ perf?: PerformanceRecorder;
78
+ }
79
+ ```
80
+
81
+ Example enabling one rule as a warning:
82
+
83
+ ```ts
84
+ const results = lint(html, {
85
+ rules: { requireAltText: "warning", uniqueIds: "error" }
86
+ });
87
+ ```
88
+
89
+ ### Example `LintResult`
90
+
91
+ ```ts
92
+ interface LintResult {
93
+ line: number;
94
+ column: number;
95
+ message: string;
96
+ rule: string;
97
+ }
98
+ ```
99
+
100
+ ## CLI usage
101
+
102
+ Run the linter from the command line by installing the package globally or
103
+ using `npx`. Provide one or more glob patterns to specify the files to lint.
104
+ Patterns may be separated by spaces, commas, or newlines:
105
+
106
+ ```bash
107
+ npx zemdomu "src/**/*.{html,jsx,tsx,vue}" --custom my-rule.js
108
+ npx zemdomu "src/**/*.html,src/**/*.jsx"
109
+ ```
110
+
111
+ Use `--custom` (or `-c`) to provide a path to a JavaScript or TypeScript module
112
+ exporting a custom rule or array of rules. Use `--cross` to enable cross
113
+ component analysis.
114
+
115
+ ### Cross-component analysis
116
+
117
+ When analyzing JSX or Vue projects you can track `<h1>` usage or similar
118
+ patterns across component boundaries. Instantiate `ProjectLinter` with the
119
+ `crossComponentAnalysis` option or pass `--cross` to the CLI. Use
120
+ `crossComponentDepth` (or `--cross-depth`) to limit how deep component trees are
121
+ traversed during analysis:
122
+
123
+ ```ts
124
+ import { ProjectLinter } from "zemdomu";
125
+ const linter = new ProjectLinter({
126
+ crossComponentAnalysis: true,
127
+ crossComponentDepth: 2
128
+ });
129
+ await linter.lintFile("App.jsx");
130
+ ```
131
+
132
+ ```bash
133
+ npx zemdomu "src/**/*.{jsx,tsx,vue}" --cross --cross-depth 2
134
+ ```
135
+
136
+ ### Performance diagnostics
137
+
138
+ Attach a `PerformanceDiagnostics` recorder to gather timing information for
139
+ each file and rule:
140
+
141
+ ```ts
142
+ import { lint, PerformanceDiagnostics } from "zemdomu";
143
+ const perf = new PerformanceDiagnostics();
144
+ lint(code, { perf });
145
+ console.log(perf.getAsJSON());
146
+ ```
147
+
148
+ ## Writing custom rules
149
+
150
+ Custom rules are simple objects implementing the `Rule` interface. At minimum
151
+ provide a `name`, a `test` function that returns `true` when a node violates the
152
+ rule, and a `message` describing the problem:
153
+
154
+ ```ts
155
+ interface Rule {
156
+ name: string;
157
+ test(node: any): boolean;
158
+ message: string;
159
+ }
160
+ ```
161
+
162
+ ```js
163
+ // my-rule.js
164
+ module.exports = {
165
+ name: "noFooDiv",
166
+ test: node => node.type === "element" && node.tagName === "foo",
167
+ message: "<foo> is not allowed"
168
+ };
169
+ ```
170
+
171
+ Use it programmatically:
172
+
173
+ ```ts
174
+ import { lint } from "zemdomu";
175
+ const results = lint("<foo></foo>", { customRules: [require("./my-rule")] });
176
+ ```
177
+
178
+ ### Helper utilities
179
+
180
+ For more advanced rules you may need direct access to the parsed HTML or JSX
181
+ AST. ZemDomu exposes a few helpers to make this easier:
182
+
183
+ ```ts
184
+ import {
185
+ parseHtml,
186
+ visitHtml,
187
+ getAttr,
188
+ getJsxAttr,
189
+ getTag,
190
+ ElementNode,
191
+ HtmlVisitor,
192
+ } from "zemdomu";
193
+ ```
194
+
195
+ `parseHtml` returns the root `ElementNode`. The `visitHtml` function performs a
196
+ simple depth-first traversal using an `HtmlVisitor` with optional `enter` and
197
+ `exit` callbacks. Utility functions like `getAttr` and `getJsxAttr` help reading
198
+ attributes, while `getTag` resolves JSX element names.
199
+
200
+ Or via the CLI:
201
+
202
+ ```bash
203
+ npx zemdomu file.html --custom my-rule.js
204
+ ```
205
+
206
+ ## Local development (monorepo)
207
+
208
+ From the core package:
209
+
210
+ ```bash
211
+ cd packages/ZemDomu-Core
212
+ npm install
213
+ npm run build
214
+ ```
215
+
216
+ ## Links
217
+
218
+ Development happens in a private monorepo; this repository is the public mirror
219
+ for issues and updates.
220
+
221
+ - NPM package: https://www.npmjs.com/package/zemdomu
222
+ - Public mirror: https://github.com/Zemdomu/ZemDomu-core
223
+ - Issues and suggestions: https://github.com/Zemdomu/ZemDomu-core/issues
224
+ - VS Code extension: https://marketplace.visualstudio.com/items?itemName=ZachariasErydBerlin.zemdomu
225
+ - GitHub Action: https://github.com/Zemdomu/ZemDomu-action
226
+
227
+ ## License
228
+
229
+ MIT (c) 2025 Zacharias Eryd Berlin
package/out/cli.js CHANGED
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const glob_1 = require("glob");
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const project_linter_1 = require("./project-linter");
10
+ const rule_codes_1 = require("./rule-codes");
10
11
  function parsePatterns(inputs) {
11
12
  const result = [];
12
13
  for (const input of inputs) {
@@ -19,7 +20,7 @@ function parsePatterns(inputs) {
19
20
  return result;
20
21
  }
21
22
  async function run() {
22
- var _a;
23
+ var _a, _b, _c;
23
24
  const args = process.argv.slice(2);
24
25
  const rawPatterns = [];
25
26
  const customRules = [];
@@ -62,7 +63,7 @@ async function run() {
62
63
  }
63
64
  const patterns = parsePatterns(rawPatterns);
64
65
  if (patterns.length === 0) {
65
- patterns.push('**/*.{html,jsx,tsx}');
66
+ patterns.push('**/*.{html,jsx,tsx,vue}');
66
67
  }
67
68
  const files = new Set();
68
69
  for (const pattern of patterns) {
@@ -75,7 +76,8 @@ async function run() {
75
76
  let hasIssues = false;
76
77
  for (const [file, issues] of results.entries()) {
77
78
  for (const issue of issues) {
78
- console.error(`${file}:${issue.line + 1}:${issue.column + 1} ${issue.rule}: ${issue.message}`);
79
+ const code = (_c = (_b = issue.code) !== null && _b !== void 0 ? _b : (0, rule_codes_1.getRuleCode)(issue.rule)) !== null && _c !== void 0 ? _c : issue.rule;
80
+ console.error(`${file}:${issue.line + 1}:${issue.column + 1} ${code}: ${issue.message}`);
79
81
  hasIssues = true;
80
82
  }
81
83
  }
@@ -58,6 +58,7 @@ export declare class ComponentAnalyzer {
58
58
  }, perf?: PerformanceRecorder);
59
59
  analyzeFile(filePath: string): Promise<ComponentDefinition | null>;
60
60
  private extractComponentInfo;
61
+ private extractVueComponentInfo;
61
62
  private resolveComponentPath;
62
63
  registerComponent(component: ComponentDefinition, issues: LintResult[]): void;
63
64
  private getRuleType;