@markuplint/rules 5.0.0-rc.7 → 5.0.1
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/CHANGELOG.md +12 -0
- package/CLAUDE.md +39 -4
- package/lib/attr-order/index.d.ts +1 -1
- package/lib/attr-order/index.js +7 -0
- package/lib/index.d.ts +1 -1
- package/lib/no-event-handler-attr/index.js +7 -0
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [5.0.1](https://github.com/markuplint/markuplint/compare/v5.0.0...v5.0.1) (2026-09-22)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- **rules:** skip framework directives in no-event-handler-attr ([1da97ed](https://github.com/markuplint/markuplint/commit/1da97ed5ff6a17aeabd9dbe7077ebe057a3b674d)), closes [#4044](https://github.com/markuplint/markuplint/issues/4044)
|
|
11
|
+
|
|
12
|
+
# [5.0.0](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.7...v5.0.0) (2026-09-11)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
- **rules:** add role predefined group to attr-order ([ed07019](https://github.com/markuplint/markuplint/commit/ed07019cafaf5dc85ce5c5e6f4ac56f908b93b54)), closes [#4033](https://github.com/markuplint/markuplint/issues/4033)
|
|
17
|
+
|
|
6
18
|
# [5.0.0-rc.7](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.6...v5.0.0-rc.7) (2026-08-31)
|
|
7
19
|
|
|
8
20
|
### Bug Fixes
|
package/CLAUDE.md
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## Adding a New Rule (checklist — steps 2–4 have NO enforcing test; forgetting them fails silently)
|
|
4
4
|
|
|
5
|
-
1. `src/<rule-name>/`: `index.ts`, `meta.ts`, `schema.json`, spec file(s), `README.md` **and** `README.ja.md` — both languages are website source and
|
|
5
|
+
1. `src/<rule-name>/`: `index.ts`, `meta.ts`, `schema.json`, spec file(s), `README.md` **and** `README.ja.md` — both languages are website source and must stay in sync; updating only one is a recurring mistake
|
|
6
6
|
- `meta.ts`'s `category` must be one of the v5 9-category scheme: `syntax`, `structure`, `attributes`, `references`, `forms`, `a11y`, `style`, `maintainability`, `compat` (see the [Categories section](https://markuplint.dev/docs/migration/v4-to-v5/rules/rule-names#categories) of the website's rule-names guide for what each covers)
|
|
7
7
|
- `meta.ts` should also declare `specConformance` (`sources`/`level`/`cites`) once you know the rule's governing spec and requirement strength — `level: 'must'` or `'should'` requires a non-empty `cites`. The rollout across pre-existing rules is incremental and partial by design (enforced only for rules that declare it — see `spec-conformance.spec.ts` and `@markuplint/config-presets`'s `html-standard-entries.spec.ts`), but a **new** rule should declare it from the start
|
|
8
8
|
2. Register the rule in `src/index.ts` (import + registry entry)
|
|
9
9
|
3. Add a `$ref` entry to `packages/@markuplint/rules/schema.json` — this file is a **manually maintained registry** (no generator produces it, despite looking generated)
|
|
10
10
|
4. If the rule belongs in a preset, update `packages/@markuplint/config-presets/src/`
|
|
11
11
|
|
|
12
|
-
## Test ID Convention
|
|
12
|
+
## Test ID Convention
|
|
13
13
|
|
|
14
|
-
Every `test()` block in rule spec files — `src/<rule-name>/**/*.spec.ts` —
|
|
14
|
+
Every `test()` block in rule spec files — `src/<rule-name>/**/*.spec.ts` — has a unique ID prefix:
|
|
15
15
|
|
|
16
16
|
```
|
|
17
17
|
[rule-name-category-NNN] description
|
|
@@ -37,7 +37,42 @@ Repo-wide meta specs directly under `src/` (e.g. `mirrors-parse-error-codes.spec
|
|
|
37
37
|
- When adding a new test, assign the next available number in the appropriate category
|
|
38
38
|
- Run `/list-rule-test` (or `node .claude/skills/list-rule-test/scripts/list-rule-test.mjs --no-id`) to check for missing IDs — the only expected hits are the exempt meta specs noted above
|
|
39
39
|
|
|
40
|
-
##
|
|
40
|
+
## Sample identifiers in specs
|
|
41
|
+
|
|
42
|
+
<!-- cspell:ignore myform mymap -->
|
|
43
|
+
|
|
44
|
+
Sample `id` / `name` values in test markup must be kebab-case (`my-form`), suffixed with a digit
|
|
45
|
+
(`form1`), or a plain dictionary word (`target`). Never a camelCase coinage (`myform`, `mymap`,
|
|
46
|
+
`targetEl`): CSpell decomposes compound words only when every part is at least three characters,
|
|
47
|
+
so a two-letter prefix glued to a word is looked up whole, misses the dictionary, and fails the
|
|
48
|
+
lint — on the `dev` line the same one-line fix has been made in four separate PRs (#3826, #3831,
|
|
49
|
+
#3833, #3932). The v6 line has no CSpell, so a coinage introduced there surfaces only once the
|
|
50
|
+
branch merges somewhere that does.
|
|
51
|
+
|
|
52
|
+
## Writing a rule's README and `schema.json` description
|
|
53
|
+
|
|
54
|
+
Both files feed the website build (`website/scripts/prebuild/rule-content.mts` injects the
|
|
55
|
+
description into MDX), which breaks in two ways that no rule test catches:
|
|
56
|
+
|
|
57
|
+
- **An attribute-bearing tag must be wrapped in backticks.** `escapeMdx` only escapes bare tags
|
|
58
|
+
(`<head>`); `<input type="button">` reaches the MDX parser as unclosed JSX and crashes the
|
|
59
|
+
Docusaurus build.
|
|
60
|
+
- **A YAML `description:` may not start with a backtick** — `gray-matter` fails with "stream/document
|
|
61
|
+
separator expected". Wrap the whole value in single quotes instead:
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
description: '`<input type="button">` must not have a value attribute'
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Deliberately malformed markup in an ❌ example needs `<!-- prettier-ignore -->` immediately before
|
|
68
|
+
the fence: oxfmt formats ` ```html ` blocks as real HTML and will close the tag you left open,
|
|
69
|
+
turning the incorrect example into a copy of the correct one. Apply it to `README.md` and
|
|
70
|
+
`README.ja.md` separately, and read the diff after `yarn lint` to confirm the breakage survived.
|
|
71
|
+
|
|
72
|
+
The CI website check only runs when a PR already touches `website/`, so a new rule can land with a
|
|
73
|
+
broken description and detonate in someone else's PR. Run `yarn site:build` before pushing.
|
|
74
|
+
|
|
75
|
+
## Assertion Convention
|
|
41
76
|
|
|
42
77
|
When asserting reported violations in rule specs, use `toStrictEqual` with the exact violation object `{ severity, line, col, message, raw }`. Never loose or partial matchers for violation objects. (Assertions on other values — counts, fixed code strings, registry invariants — use whatever matcher fits.)
|
|
43
78
|
|
package/lib/attr-order/index.js
CHANGED
|
@@ -112,6 +112,13 @@ eventAttrs) {
|
|
|
112
112
|
match: (name) => /^aria-.+$/.test(name),
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
|
+
case 'role': {
|
|
116
|
+
return {
|
|
117
|
+
entryIndex,
|
|
118
|
+
order: groupOrder,
|
|
119
|
+
match: (name) => name === 'role',
|
|
120
|
+
};
|
|
121
|
+
}
|
|
115
122
|
case 'data': {
|
|
116
123
|
return {
|
|
117
124
|
entryIndex,
|
package/lib/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ declare const rules: {
|
|
|
16
16
|
readonly 'attr-order': Readonly<import("@markuplint/ml-core").RuleSeed<(string | {
|
|
17
17
|
name?: string;
|
|
18
18
|
pattern?: string;
|
|
19
|
-
group?: "data" | "aria" | "global" | "event" | "spread";
|
|
19
|
+
group?: "data" | "aria" | "global" | "event" | "role" | "spread";
|
|
20
20
|
order?: string[] | "alphabetical" | "source-order";
|
|
21
21
|
})[], {
|
|
22
22
|
alphabetical?: boolean;
|
|
@@ -29,6 +29,13 @@ export default createRule({
|
|
|
29
29
|
if (attr.ownerElement.elementType !== 'html') {
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
|
+
// Framework directives that resolve to an `onXxx` name (Vue `@click`, Alpine
|
|
33
|
+
// `x-on:click`, htmx `hx-on:click`, Svelte `on:click`) are excluded: they never
|
|
34
|
+
// reach the DOM as a literal inline-handler attribute, and each framework
|
|
35
|
+
// documents them as its recommended event-binding idiom.
|
|
36
|
+
if (attr.isDirective) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
32
39
|
const ignoreList = Array.isArray(attr.rule.options.ignore)
|
|
33
40
|
? attr.rule.options.ignore
|
|
34
41
|
: attr.rule.options.ignore
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/rules",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.1",
|
|
4
4
|
"description": "Built-in rules of markuplint",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
"./lib/permitted-contents/debug.js": "./lib/permitted-contents/debug.browser.js"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@markuplint/html-spec": "5.0.
|
|
35
|
-
"@markuplint/ml-config": "5.0.
|
|
36
|
-
"@markuplint/ml-core": "5.0.
|
|
37
|
-
"@markuplint/ml-spec": "5.0.
|
|
38
|
-
"@markuplint/selector": "5.0.
|
|
39
|
-
"@markuplint/shared": "5.0.
|
|
40
|
-
"@markuplint/types": "5.0.
|
|
34
|
+
"@markuplint/html-spec": "5.0.1",
|
|
35
|
+
"@markuplint/ml-config": "5.0.1",
|
|
36
|
+
"@markuplint/ml-core": "5.0.1",
|
|
37
|
+
"@markuplint/ml-spec": "5.0.1",
|
|
38
|
+
"@markuplint/selector": "5.0.1",
|
|
39
|
+
"@markuplint/shared": "5.0.1",
|
|
40
|
+
"@markuplint/types": "5.0.1",
|
|
41
41
|
"@mdn/browser-compat-data": "^7.3.2",
|
|
42
42
|
"@types/debug": "4.1.13",
|
|
43
43
|
"ansi-colors": "4.1.3",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"image-size": "^2.0.2",
|
|
48
48
|
"type-fest": "5.6.0"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "edbaeedca5588fb291ea9d4e21a4ab2bf41fc9cb"
|
|
51
51
|
}
|