zemdomu 1.3.10 โ 1.3.14
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.
- package/README.md +229 -224
- package/out/cli.js +5 -3
- package/out/component-analyzer.d.ts +1 -0
- package/out/component-analyzer.js +437 -68
- package/out/component-path-resolver.js +6 -6
- package/out/index.d.ts +1 -0
- package/out/index.js +4 -1
- package/out/linter.d.ts +3 -0
- package/out/linter.js +41 -25
- package/out/project-linter.js +15 -3
- package/out/rule-codes.d.ts +25 -0
- package/out/rule-codes.js +36 -0
- package/out/sarif.js +8 -4
- package/out/src/cli.js +5 -3
- package/out/src/component-analyzer.js +437 -68
- package/out/src/component-path-resolver.js +6 -6
- package/out/src/index.js +4 -1
- package/out/src/linter.js +41 -25
- package/out/src/project-linter.js +15 -3
- package/out/src/rule-codes.js +36 -0
- package/out/src/sarif.js +8 -4
- package/out/src/utils/collectLocalDeps.js +38 -2
- package/out/src/utils/vue-sfc.js +93 -0
- package/out/tests/cross-heading-reversed.test.js +24 -0
- package/out/tests/crossComponent/cross-heading-order.test.js +5 -0
- package/out/tests/heading-order.test.js +24 -0
- package/out/tests/sarif-output.test.js +1 -1
- package/out/tests/vue-support.test.js +63 -0
- package/out/utils/collectLocalDeps.js +38 -2
- package/out/utils/vue-sfc.d.ts +9 -0
- package/out/utils/vue-sfc.js +93 -0
- 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.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
name:
|
|
157
|
-
test:
|
|
158
|
-
message:
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
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;
|