@markuplint/rules 4.11.2 → 4.18.0
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 -1
- package/SKILL.md +76 -0
- package/lib/attr-check.d.ts +41 -5
- package/lib/attr-check.js +29 -5
- package/lib/attr-duplication/index.d.ts +7 -0
- package/lib/attr-duplication/index.js +7 -0
- package/lib/attr-duplication/meta.d.ts +1 -0
- package/lib/attr-duplication/meta.js +1 -0
- package/lib/attr-value-quotes/index.d.ts +10 -0
- package/lib/attr-value-quotes/index.js +10 -0
- package/lib/attr-value-quotes/meta.d.ts +1 -0
- package/lib/attr-value-quotes/meta.js +1 -0
- package/lib/case-sensitive-attr-name/index.d.ts +9 -0
- package/lib/case-sensitive-attr-name/index.js +8 -0
- package/lib/case-sensitive-attr-name/meta.d.ts +1 -0
- package/lib/case-sensitive-attr-name/meta.js +1 -0
- package/lib/case-sensitive-tag-name/index.d.ts +9 -0
- package/lib/case-sensitive-tag-name/index.js +8 -0
- package/lib/case-sensitive-tag-name/meta.d.ts +1 -0
- package/lib/case-sensitive-tag-name/meta.js +1 -0
- package/lib/character-reference/index.d.ts +8 -0
- package/lib/character-reference/index.js +16 -0
- package/lib/character-reference/meta.d.ts +1 -0
- package/lib/character-reference/meta.js +1 -0
- package/lib/class-naming/index.d.ts +9 -0
- package/lib/class-naming/index.js +8 -0
- package/lib/class-naming/meta.d.ts +1 -0
- package/lib/class-naming/meta.js +1 -0
- package/lib/create-message.d.ts +27 -0
- package/lib/create-message.js +56 -1
- package/lib/debug.d.ts +9 -0
- package/lib/debug.js +5 -0
- package/lib/deprecated-attr/index.d.ts +6 -0
- package/lib/deprecated-attr/index.js +6 -0
- package/lib/deprecated-attr/meta.d.ts +1 -0
- package/lib/deprecated-attr/meta.js +1 -0
- package/lib/deprecated-element/index.d.ts +8 -0
- package/lib/deprecated-element/index.js +8 -0
- package/lib/deprecated-element/meta.d.ts +1 -0
- package/lib/deprecated-element/meta.js +1 -0
- package/lib/disallowed-element/index.d.ts +7 -0
- package/lib/disallowed-element/index.js +7 -0
- package/lib/disallowed-element/meta.d.ts +1 -0
- package/lib/disallowed-element/meta.js +1 -0
- package/lib/doctype/index.d.ts +10 -0
- package/lib/doctype/index.js +8 -0
- package/lib/doctype/meta.d.ts +1 -0
- package/lib/doctype/meta.js +1 -0
- package/lib/end-tag/index.d.ts +7 -0
- package/lib/end-tag/index.js +7 -0
- package/lib/end-tag/meta.d.ts +1 -0
- package/lib/end-tag/meta.js +1 -0
- package/lib/heading-levels/index.d.ts +6 -0
- package/lib/heading-levels/index.js +6 -0
- package/lib/heading-levels/meta.d.ts +1 -0
- package/lib/heading-levels/meta.js +1 -0
- package/lib/helpers.d.ts +104 -0
- package/lib/helpers.js +105 -2
- package/lib/id-duplication/index.d.ts +7 -0
- package/lib/id-duplication/index.js +7 -0
- package/lib/id-duplication/meta.d.ts +1 -0
- package/lib/id-duplication/meta.js +1 -0
- package/lib/index.d.ts +23 -10
- package/lib/index.js +12 -0
- package/lib/ineffective-attr/index.d.ts +7 -0
- package/lib/ineffective-attr/index.js +7 -0
- package/lib/ineffective-attr/meta.d.ts +1 -0
- package/lib/ineffective-attr/meta.js +1 -0
- package/lib/invalid-attr/index.d.ts +24 -0
- package/lib/invalid-attr/index.js +17 -0
- package/lib/invalid-attr/meta.d.ts +1 -0
- package/lib/invalid-attr/meta.js +1 -0
- package/lib/label-has-control/index.d.ts +7 -0
- package/lib/label-has-control/index.js +11 -0
- package/lib/label-has-control/meta.d.ts +1 -0
- package/lib/label-has-control/meta.js +1 -0
- package/lib/landmark-roles/index.d.ts +14 -0
- package/lib/landmark-roles/index.js +21 -0
- package/lib/landmark-roles/meta.d.ts +1 -0
- package/lib/landmark-roles/meta.js +1 -0
- package/lib/neighbor-popovers/index.d.ts +8 -0
- package/lib/neighbor-popovers/index.js +26 -2
- package/lib/neighbor-popovers/meta.d.ts +1 -0
- package/lib/neighbor-popovers/meta.js +1 -0
- package/lib/no-ambiguous-navigable-target-names/index.d.ts +8 -0
- package/lib/no-ambiguous-navigable-target-names/index.js +8 -0
- package/lib/no-ambiguous-navigable-target-names/meta.d.ts +1 -0
- package/lib/no-ambiguous-navigable-target-names/meta.js +1 -0
- package/lib/no-boolean-attr-value/index.d.ts +7 -0
- package/lib/no-boolean-attr-value/index.js +7 -0
- package/lib/no-boolean-attr-value/meta.d.ts +1 -0
- package/lib/no-boolean-attr-value/meta.js +1 -0
- package/lib/no-consecutive-br/index.d.ts +8 -0
- package/lib/no-consecutive-br/index.js +8 -0
- package/lib/no-consecutive-br/meta.d.ts +1 -0
- package/lib/no-consecutive-br/meta.js +1 -0
- package/lib/no-default-value/index.d.ts +7 -0
- package/lib/no-default-value/index.js +7 -0
- package/lib/no-default-value/meta.d.ts +1 -0
- package/lib/no-default-value/meta.js +1 -0
- package/lib/no-duplicate-dt/index.d.ts +6 -0
- package/lib/no-duplicate-dt/index.js +6 -0
- package/lib/no-duplicate-dt/meta.d.ts +1 -0
- package/lib/no-duplicate-dt/meta.js +1 -0
- package/lib/no-empty-palpable-content/index.d.ts +13 -0
- package/lib/no-empty-palpable-content/index.js +12 -0
- package/lib/no-empty-palpable-content/meta.d.ts +1 -0
- package/lib/no-empty-palpable-content/meta.js +1 -0
- package/lib/no-hard-code-id/index.d.ts +8 -0
- package/lib/no-hard-code-id/index.js +8 -0
- package/lib/no-hard-code-id/meta.d.ts +1 -0
- package/lib/no-hard-code-id/meta.js +1 -0
- package/lib/no-orphaned-end-tag/index.d.ts +7 -0
- package/lib/no-orphaned-end-tag/index.js +7 -0
- package/lib/no-orphaned-end-tag/meta.d.ts +1 -0
- package/lib/no-orphaned-end-tag/meta.js +1 -0
- package/lib/no-refer-to-non-existent-id/index.d.ts +8 -0
- package/lib/no-refer-to-non-existent-id/index.js +9 -0
- package/lib/no-refer-to-non-existent-id/meta.d.ts +1 -0
- package/lib/no-refer-to-non-existent-id/meta.js +1 -0
- package/lib/no-use-event-handler-attr/index.d.ts +10 -0
- package/lib/no-use-event-handler-attr/index.js +8 -0
- package/lib/no-use-event-handler-attr/meta.d.ts +1 -0
- package/lib/no-use-event-handler-attr/meta.js +1 -0
- package/lib/permitted-contents/choice.d.ts +17 -0
- package/lib/permitted-contents/choice.js +30 -0
- package/lib/permitted-contents/complex-branch.d.ts +11 -7
- package/lib/permitted-contents/complex-branch.js +11 -7
- package/lib/permitted-contents/content-model.d.ts +11 -0
- package/lib/permitted-contents/content-model.js +32 -0
- package/lib/permitted-contents/count-pattern.d.ts +13 -7
- package/lib/permitted-contents/count-pattern.js +23 -7
- package/lib/permitted-contents/debug.browser.d.ts +12 -0
- package/lib/permitted-contents/debug.browser.js +12 -0
- package/lib/permitted-contents/debug.d.ts +12 -0
- package/lib/permitted-contents/debug.js +12 -0
- package/lib/permitted-contents/index.d.ts +12 -0
- package/lib/permitted-contents/index.js +21 -0
- package/lib/permitted-contents/matches-selector.d.ts +19 -0
- package/lib/permitted-contents/matches-selector.js +33 -0
- package/lib/permitted-contents/meta.d.ts +1 -0
- package/lib/permitted-contents/meta.js +1 -0
- package/lib/permitted-contents/order.d.ts +14 -7
- package/lib/permitted-contents/order.js +14 -7
- package/lib/permitted-contents/recursive-branch.d.ts +17 -0
- package/lib/permitted-contents/recursive-branch.js +17 -0
- package/lib/permitted-contents/represent-transparent-nodes.d.ts +29 -0
- package/lib/permitted-contents/represent-transparent-nodes.js +24 -0
- package/lib/permitted-contents/start.d.ts +12 -6
- package/lib/permitted-contents/start.js +12 -6
- package/lib/permitted-contents/transparent.d.ts +12 -0
- package/lib/permitted-contents/transparent.js +12 -0
- package/lib/permitted-contents/types.d.ts +67 -0
- package/lib/permitted-contents/utils.d.ts +160 -0
- package/lib/permitted-contents/utils.js +194 -0
- package/lib/placeholder-label-option/index.d.ts +7 -0
- package/lib/placeholder-label-option/index.js +19 -15
- package/lib/placeholder-label-option/meta.d.ts +1 -0
- package/lib/placeholder-label-option/meta.js +1 -0
- package/lib/require-accessible-name/index.d.ts +11 -0
- package/lib/require-accessible-name/index.js +7 -0
- package/lib/require-accessible-name/meta.d.ts +1 -0
- package/lib/require-accessible-name/meta.js +1 -0
- package/lib/require-datetime/index.d.ts +12 -0
- package/lib/require-datetime/index.js +8 -0
- package/lib/require-datetime/meta.d.ts +1 -0
- package/lib/require-datetime/meta.js +1 -0
- package/lib/require-datetime/types.d.ts +7 -0
- package/lib/require-datetime/utils.d.ts +18 -5
- package/lib/require-datetime/utils.js +53 -9
- package/lib/required-attr/index.d.ts +13 -0
- package/lib/required-attr/index.js +7 -0
- package/lib/required-attr/meta.d.ts +1 -0
- package/lib/required-attr/meta.js +1 -0
- package/lib/required-element/index.d.ts +14 -0
- package/lib/required-element/index.js +14 -2
- package/lib/required-element/meta.d.ts +1 -0
- package/lib/required-element/meta.js +1 -0
- package/lib/required-h1/index.d.ts +12 -0
- package/lib/required-h1/index.js +7 -0
- package/lib/required-h1/meta.d.ts +1 -0
- package/lib/required-h1/meta.js +1 -0
- package/lib/table-row-column-alignment/find-children.d.ts +10 -0
- package/lib/table-row-column-alignment/find-children.js +11 -0
- package/lib/table-row-column-alignment/grid.d.ts +60 -0
- package/lib/table-row-column-alignment/grid.js +85 -0
- package/lib/table-row-column-alignment/index.d.ts +8 -0
- package/lib/table-row-column-alignment/index.js +8 -0
- package/lib/table-row-column-alignment/meta.d.ts +1 -0
- package/lib/table-row-column-alignment/meta.js +1 -0
- package/lib/table-row-column-alignment/types.d.ts +10 -0
- package/lib/use-list/index.d.ts +16 -0
- package/lib/use-list/index.js +20 -0
- package/lib/use-list/meta.d.ts +1 -0
- package/lib/use-list/meta.js +1 -0
- package/lib/wai-aria/checkings/abstract-role.d.ts +9 -0
- package/lib/wai-aria/checkings/abstract-role.js +9 -0
- package/lib/wai-aria/checkings/default-value.d.ts +11 -0
- package/lib/wai-aria/checkings/default-value.js +11 -0
- package/lib/wai-aria/checkings/deprecated-props.d.ts +11 -0
- package/lib/wai-aria/checkings/deprecated-props.js +11 -0
- package/lib/wai-aria/checkings/deprecated-role.d.ts +10 -0
- package/lib/wai-aria/checkings/deprecated-role.js +10 -0
- package/lib/wai-aria/checkings/disallowed-prop.d.ts +14 -0
- package/lib/wai-aria/checkings/disallowed-prop.js +14 -0
- package/lib/wai-aria/checkings/implicit-props.d.ts +13 -0
- package/lib/wai-aria/checkings/implicit-props.js +13 -0
- package/lib/wai-aria/checkings/implicit-role.d.ts +9 -0
- package/lib/wai-aria/checkings/implicit-role.js +9 -0
- package/lib/wai-aria/checkings/interaction-in-hidden.d.ts +9 -0
- package/lib/wai-aria/checkings/interaction-in-hidden.js +15 -4
- package/lib/wai-aria/checkings/no-global-prop.d.ts +10 -0
- package/lib/wai-aria/checkings/no-global-prop.js +10 -0
- package/lib/wai-aria/checkings/non-existent-role.d.ts +10 -0
- package/lib/wai-aria/checkings/non-existent-role.js +10 -0
- package/lib/wai-aria/checkings/permitted-roles.d.ts +10 -0
- package/lib/wai-aria/checkings/permitted-roles.js +10 -0
- package/lib/wai-aria/checkings/presentational-children.d.ts +7 -1
- package/lib/wai-aria/checkings/presentational-children.js +14 -1
- package/lib/wai-aria/checkings/required-owned-elements.d.ts +9 -1
- package/lib/wai-aria/checkings/required-owned-elements.js +16 -1
- package/lib/wai-aria/checkings/required-prop.d.ts +13 -0
- package/lib/wai-aria/checkings/required-prop.js +13 -0
- package/lib/wai-aria/checkings/value.d.ts +23 -0
- package/lib/wai-aria/checkings/value.js +32 -0
- package/lib/wai-aria/index.d.ts +10 -0
- package/lib/wai-aria/index.js +10 -0
- package/lib/wai-aria/meta.d.ts +1 -0
- package/lib/wai-aria/meta.js +1 -0
- package/lib/wai-aria/types.d.ts +17 -0
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -3,13 +3,24 @@
|
|
|
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
|
-
|
|
6
|
+
# [4.18.0](https://github.com/markuplint/markuplint/compare/v4.14.1...v4.18.0) (2026-04-22)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @markuplint/rules
|
|
9
|
+
|
|
10
|
+
## [4.12.1](https://github.com/markuplint/markuplint/compare/@markuplint/rules@4.12.0...@markuplint/rules@4.12.1) (2026-04-21)
|
|
7
11
|
|
|
8
12
|
**Note:** Version bump only for package @markuplint/rules
|
|
9
13
|
|
|
14
|
+
# [4.12.0](https://github.com/markuplint/markuplint/compare/@markuplint/rules@4.11.2...@markuplint/rules@4.12.0) (2026-02-10)
|
|
10
15
|
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
- **rules:** add ignoreOmittedElements option to required-element ([0cc879c](https://github.com/markuplint/markuplint/commit/0cc879ca175491da7eda4d6f4d0638b74fe528e5)), closes [#2066](https://github.com/markuplint/markuplint/issues/2066)
|
|
19
|
+
- **rules:** support Invoker Commands API in neighbor-popovers rule ([963853f](https://github.com/markuplint/markuplint/commit/963853f9f3701ab552d7d03fe5712a671c50d444)), closes [#3065](https://github.com/markuplint/markuplint/issues/3065)
|
|
11
20
|
|
|
21
|
+
## [4.11.2](https://github.com/markuplint/markuplint/compare/@markuplint/rules@4.11.1...@markuplint/rules@4.11.2) (2025-11-05)
|
|
12
22
|
|
|
23
|
+
**Note:** Version bump only for package @markuplint/rules
|
|
13
24
|
|
|
14
25
|
## [4.11.1](https://github.com/markuplint/markuplint/compare/@markuplint/rules@4.11.0...@markuplint/rules@4.11.1) (2025-08-24)
|
|
15
26
|
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Perform maintenance tasks for @markuplint/rules
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# rules-maintenance
|
|
6
|
+
|
|
7
|
+
Maintain rule test suites, especially when `@markuplint/html-spec` changes.
|
|
8
|
+
|
|
9
|
+
## Input
|
|
10
|
+
|
|
11
|
+
`$ARGUMENTS` specifies the task:
|
|
12
|
+
|
|
13
|
+
| Task | Description |
|
|
14
|
+
| --------------------------------- | ------------------------------------- |
|
|
15
|
+
| `add-spec-tests <rule> <element>` | Add tests after a spec change |
|
|
16
|
+
| `update-test-expectations` | Fix tests broken by spec data changes |
|
|
17
|
+
|
|
18
|
+
## Task: add-spec-tests
|
|
19
|
+
|
|
20
|
+
### Which test file?
|
|
21
|
+
|
|
22
|
+
| Spec change | Test file |
|
|
23
|
+
| ----------------------------------- | -------------------------------------- |
|
|
24
|
+
| ARIA (implicitRole, permittedRoles) | `src/wai-aria/index.spec.ts` |
|
|
25
|
+
| Attributes (new/changed/enum) | `src/invalid-attr/index.spec.ts` |
|
|
26
|
+
| Content model | `src/permitted-contents/index.spec.ts` |
|
|
27
|
+
|
|
28
|
+
### Test Pattern
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { mlRuleTest } from 'markuplint';
|
|
32
|
+
import rule from './index.js';
|
|
33
|
+
|
|
34
|
+
// Valid case — no violations
|
|
35
|
+
const { violations } = await mlRuleTest(rule, '<img src="x.png" alt="desc" role="math">');
|
|
36
|
+
expect(violations).toStrictEqual([]);
|
|
37
|
+
|
|
38
|
+
// Invalid case — exact violation object
|
|
39
|
+
const { violations } = await mlRuleTest(rule, '<img src="x.png" alt="desc" role="navigation">');
|
|
40
|
+
expect(violations).toStrictEqual([
|
|
41
|
+
{
|
|
42
|
+
severity: 'error',
|
|
43
|
+
line: 1,
|
|
44
|
+
col: 38,
|
|
45
|
+
message: 'Cannot overwrite the "navigation" role to the "img" element according to ARIA in HTML specification',
|
|
46
|
+
raw: 'navigation',
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
// ARIA version test
|
|
51
|
+
const { violations } = await mlRuleTest(rule, '<button role="separator" ...>', {
|
|
52
|
+
rule: { options: { version: '1.1' } },
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Conventions
|
|
57
|
+
|
|
58
|
+
- `toStrictEqual` with exact `{ severity, line, col, message, raw }` — **never** loose assertions
|
|
59
|
+
- Always include both valid and invalid cases
|
|
60
|
+
- Some roles need ARIA attributes in HTML: `separator` → `aria-valuenow`, `meter` → `aria-valuenow`
|
|
61
|
+
|
|
62
|
+
## Task: update-test-expectations
|
|
63
|
+
|
|
64
|
+
When `html-spec` data changes break existing tests:
|
|
65
|
+
|
|
66
|
+
1. Run `yarn test` to find failures
|
|
67
|
+
2. Verify the new behavior is correct (not a regression)
|
|
68
|
+
3. Update expected violation objects (message strings, etc.)
|
|
69
|
+
4. Common cause: adding enum values changes error message strings
|
|
70
|
+
|
|
71
|
+
## Rules
|
|
72
|
+
|
|
73
|
+
1. **Always run `yarn test` (full suite)**, not just the rules package
|
|
74
|
+
2. **Use `toStrictEqual` with exact objects** — no loose assertions
|
|
75
|
+
3. **Check `ml-spec` algorithm tests** when changing ARIA mappings —
|
|
76
|
+
`ml-spec/src/algorithm/aria/get-permitted-roles-spec.spec.ts` has hardcoded role arrays
|
package/lib/attr-check.d.ts
CHANGED
|
@@ -1,25 +1,61 @@
|
|
|
1
1
|
import type { Translator } from '@markuplint/i18n';
|
|
2
2
|
import type { Attribute as AttrSpec, AttributeType } from '@markuplint/ml-spec';
|
|
3
3
|
import type { ReadonlyDeep } from 'type-fest';
|
|
4
|
+
/**
|
|
5
|
+
* Discriminated union tag representing the kind of attribute invalidity.
|
|
6
|
+
*/
|
|
4
7
|
type InvalidTYpe = 'non-existent' | 'invalid-value' | 'disallowed-attr';
|
|
8
|
+
/**
|
|
9
|
+
* Describes a single attribute validation failure, including the kind
|
|
10
|
+
* of invalidity, a human-readable message, and an optional source location.
|
|
11
|
+
*
|
|
12
|
+
* @template T - The specific invalidity tag (defaults to any `InvalidTYpe`)
|
|
13
|
+
*/
|
|
5
14
|
type Invalid<T extends InvalidTYpe = InvalidTYpe> = {
|
|
6
15
|
invalidType: T;
|
|
7
16
|
message: string;
|
|
8
17
|
loc?: Loc;
|
|
9
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* Source location information pointing to the invalid portion of an attribute value.
|
|
21
|
+
*/
|
|
10
22
|
type Loc = {
|
|
11
23
|
raw: string;
|
|
12
24
|
line: number;
|
|
13
25
|
col: number;
|
|
14
26
|
};
|
|
15
27
|
/**
|
|
16
|
-
*
|
|
28
|
+
* Validates an attribute against its specification. Used by the `invalid-attr`
|
|
29
|
+
* and `wai-aria` rules.
|
|
30
|
+
*
|
|
31
|
+
* Performs the following checks in order:
|
|
32
|
+
* 1. Skips `data-*`, `aria-*`/`role`, and `adapt-*` attributes (unless `isCustomRule` is `true`)
|
|
33
|
+
* 2. Verifies the attribute exists in the spec
|
|
34
|
+
* 3. Checks case-sensitive name matching
|
|
35
|
+
* 4. Checks whether the attribute is marked as `noUse` (disallowed)
|
|
36
|
+
* 5. Validates the attribute value against all declared types
|
|
17
37
|
*
|
|
18
|
-
* @param
|
|
19
|
-
* @param
|
|
20
|
-
* @param
|
|
21
|
-
* @param
|
|
38
|
+
* @param t - The i18n translator for generating localized error messages
|
|
39
|
+
* @param name - The attribute name to check
|
|
40
|
+
* @param value - The attribute value to validate
|
|
41
|
+
* @param isCustomRule - When `true`, skips the built-in bypass for `data-*`, `aria-*`, and `adapt-*` attributes
|
|
42
|
+
* @param spec - The attribute specification to validate against; if absent, the attribute is considered non-existent
|
|
43
|
+
* @returns `false` if the attribute is valid, a single `Invalid` object for existence/disallowed errors,
|
|
44
|
+
* or an array of `Invalid<'invalid-value'>` objects for value validation failures
|
|
22
45
|
*/
|
|
23
46
|
export declare function attrCheck(t: Translator, name: string, value: string, isCustomRule: boolean, spec?: AttrSpec): Invalid | Invalid<'invalid-value'>[] | false;
|
|
47
|
+
/**
|
|
48
|
+
* Validates an attribute value against a single attribute type definition.
|
|
49
|
+
* Returns `false` if the value is valid, or a tuple of `[message, location]`
|
|
50
|
+
* describing the mismatch.
|
|
51
|
+
*
|
|
52
|
+
* Boolean attributes are always considered valid (their mere presence is sufficient).
|
|
53
|
+
*
|
|
54
|
+
* @param t - The i18n translator for generating localized error messages
|
|
55
|
+
* @param name - The attribute name (used in error messages)
|
|
56
|
+
* @param value - The attribute value to validate
|
|
57
|
+
* @param type - The attribute type definition to validate against
|
|
58
|
+
* @returns `false` if the value is valid, or a `[message, location]` tuple on failure
|
|
59
|
+
*/
|
|
24
60
|
export declare function valueCheck(t: Translator, name: string, value: string, type: ReadonlyDeep<AttributeType>): [string, Loc] | false;
|
|
25
61
|
export {};
|
package/lib/attr-check.js
CHANGED
|
@@ -3,12 +3,23 @@ import { check } from '@markuplint/types';
|
|
|
3
3
|
import { createMessageValueExpected } from './create-message.js';
|
|
4
4
|
import { log } from './debug.js';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Validates an attribute against its specification. Used by the `invalid-attr`
|
|
7
|
+
* and `wai-aria` rules.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Performs the following checks in order:
|
|
10
|
+
* 1. Skips `data-*`, `aria-*`/`role`, and `adapt-*` attributes (unless `isCustomRule` is `true`)
|
|
11
|
+
* 2. Verifies the attribute exists in the spec
|
|
12
|
+
* 3. Checks case-sensitive name matching
|
|
13
|
+
* 4. Checks whether the attribute is marked as `noUse` (disallowed)
|
|
14
|
+
* 5. Validates the attribute value against all declared types
|
|
15
|
+
*
|
|
16
|
+
* @param t - The i18n translator for generating localized error messages
|
|
17
|
+
* @param name - The attribute name to check
|
|
18
|
+
* @param value - The attribute value to validate
|
|
19
|
+
* @param isCustomRule - When `true`, skips the built-in bypass for `data-*`, `aria-*`, and `adapt-*` attributes
|
|
20
|
+
* @param spec - The attribute specification to validate against; if absent, the attribute is considered non-existent
|
|
21
|
+
* @returns `false` if the attribute is valid, a single `Invalid` object for existence/disallowed errors,
|
|
22
|
+
* or an array of `Invalid<'invalid-value'>` objects for value validation failures
|
|
12
23
|
*/
|
|
13
24
|
export function attrCheck(t, name, value, isCustomRule, spec) {
|
|
14
25
|
if (!isCustomRule) {
|
|
@@ -68,6 +79,19 @@ export function attrCheck(t, name, value, isCustomRule, spec) {
|
|
|
68
79
|
}
|
|
69
80
|
return [...invalidMap.values()];
|
|
70
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Validates an attribute value against a single attribute type definition.
|
|
84
|
+
* Returns `false` if the value is valid, or a tuple of `[message, location]`
|
|
85
|
+
* describing the mismatch.
|
|
86
|
+
*
|
|
87
|
+
* Boolean attributes are always considered valid (their mere presence is sufficient).
|
|
88
|
+
*
|
|
89
|
+
* @param t - The i18n translator for generating localized error messages
|
|
90
|
+
* @param name - The attribute name (used in error messages)
|
|
91
|
+
* @param value - The attribute value to validate
|
|
92
|
+
* @param type - The attribute type definition to validate against
|
|
93
|
+
* @returns `false` if the value is valid, or a `[message, location]` tuple on failure
|
|
94
|
+
*/
|
|
71
95
|
export function valueCheck(t, name, value, type) {
|
|
72
96
|
if (type === 'Boolean') {
|
|
73
97
|
// Valid because an attribute is exist
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule that checks for duplicate attributes on the same element.
|
|
3
|
+
*
|
|
4
|
+
* Walks all elements and reports when two or more attributes share the same
|
|
5
|
+
* name (case-insensitive for HTML elements). Attributes marked as duplicatable
|
|
6
|
+
* (e.g., template-engine directives) are excluded from this check.
|
|
7
|
+
*/
|
|
1
8
|
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
|
|
2
9
|
export default _default;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { createRule } from '@markuplint/ml-core';
|
|
2
2
|
import meta from './meta.js';
|
|
3
|
+
/**
|
|
4
|
+
* Rule that checks for duplicate attributes on the same element.
|
|
5
|
+
*
|
|
6
|
+
* Walks all elements and reports when two or more attributes share the same
|
|
7
|
+
* name (case-insensitive for HTML elements). Attributes marked as duplicatable
|
|
8
|
+
* (e.g., template-engine directives) are excluded from this check.
|
|
9
|
+
*/
|
|
3
10
|
export default createRule({
|
|
4
11
|
meta: meta,
|
|
5
12
|
async verify({ document, report, t }) {
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
+
/** The accepted quote style: double or single. */
|
|
1
2
|
export type Type = 'double' | 'single';
|
|
3
|
+
/** A literal quotation mark character. */
|
|
2
4
|
export type Quote = '"' | "'";
|
|
5
|
+
/** Maps each quote style name to its corresponding character. */
|
|
3
6
|
export type QuoteMap = {
|
|
4
7
|
[P in Type]: Quote;
|
|
5
8
|
};
|
|
9
|
+
/**
|
|
10
|
+
* Rule that enforces consistent quotation marks around attribute values.
|
|
11
|
+
*
|
|
12
|
+
* Verifies that all attribute values use the configured quote style (double
|
|
13
|
+
* or single). Attributes without values, dynamic values, and directives are
|
|
14
|
+
* skipped. Includes an auto-fix that replaces mismatched quotes.
|
|
15
|
+
*/
|
|
6
16
|
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<Type, undefined>>;
|
|
7
17
|
export default _default;
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { createRule } from '@markuplint/ml-core';
|
|
2
2
|
import meta from './meta.js';
|
|
3
|
+
/**
|
|
4
|
+
* Mapping from quote type names to their literal characters.
|
|
5
|
+
*/
|
|
3
6
|
const quoteList = {
|
|
4
7
|
double: '"',
|
|
5
8
|
single: "'",
|
|
6
9
|
};
|
|
10
|
+
/**
|
|
11
|
+
* Rule that enforces consistent quotation marks around attribute values.
|
|
12
|
+
*
|
|
13
|
+
* Verifies that all attribute values use the configured quote style (double
|
|
14
|
+
* or single). Attributes without values, dynamic values, and directives are
|
|
15
|
+
* skipped. Includes an auto-fix that replaces mismatched quotes.
|
|
16
|
+
*/
|
|
7
17
|
export default createRule({
|
|
8
18
|
meta: meta,
|
|
9
19
|
defaultSeverity: 'warning',
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/** The enforced letter case for attribute names. */
|
|
1
2
|
export type Value = 'lower' | 'upper';
|
|
3
|
+
/**
|
|
4
|
+
* Rule that enforces consistent letter case for HTML attribute names.
|
|
5
|
+
*
|
|
6
|
+
* Reports attribute names that do not match the configured case (lower or upper)
|
|
7
|
+
* on HTML elements. Foreign elements and case-sensitive attributes (per spec)
|
|
8
|
+
* are excluded. Includes an auto-fix that converts attribute names to the
|
|
9
|
+
* configured case.
|
|
10
|
+
*/
|
|
2
11
|
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<Value, undefined>>;
|
|
3
12
|
export default _default;
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { createRule, getAttrSpecs } from '@markuplint/ml-core';
|
|
2
2
|
import meta from './meta.js';
|
|
3
|
+
/**
|
|
4
|
+
* Rule that enforces consistent letter case for HTML attribute names.
|
|
5
|
+
*
|
|
6
|
+
* Reports attribute names that do not match the configured case (lower or upper)
|
|
7
|
+
* on HTML elements. Foreign elements and case-sensitive attributes (per spec)
|
|
8
|
+
* are excluded. Includes an auto-fix that converts attribute names to the
|
|
9
|
+
* configured case.
|
|
10
|
+
*/
|
|
3
11
|
export default createRule({
|
|
4
12
|
meta: meta,
|
|
5
13
|
defaultSeverity: 'warning',
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/** The enforced letter case for tag names. */
|
|
1
2
|
export type Value = 'lower' | 'upper';
|
|
3
|
+
/**
|
|
4
|
+
* Rule that enforces consistent letter case for HTML tag names.
|
|
5
|
+
*
|
|
6
|
+
* Reports opening and closing tag names that do not match the configured
|
|
7
|
+
* case (lower or upper) on HTML elements. Skipped when the document is
|
|
8
|
+
* tag-name-case-sensitive or for foreign elements. Includes an auto-fix
|
|
9
|
+
* that converts tag names to the configured case.
|
|
10
|
+
*/
|
|
2
11
|
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<Value, undefined>>;
|
|
3
12
|
export default _default;
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { createRule } from '@markuplint/ml-core';
|
|
2
2
|
import meta from './meta.js';
|
|
3
|
+
/**
|
|
4
|
+
* Rule that enforces consistent letter case for HTML tag names.
|
|
5
|
+
*
|
|
6
|
+
* Reports opening and closing tag names that do not match the configured
|
|
7
|
+
* case (lower or upper) on HTML elements. Skipped when the document is
|
|
8
|
+
* tag-name-case-sensitive or for foreign elements. Includes an auto-fix
|
|
9
|
+
* that converts tag names to the configured case.
|
|
10
|
+
*/
|
|
3
11
|
export default createRule({
|
|
4
12
|
meta: meta,
|
|
5
13
|
defaultSeverity: 'warning',
|
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
import type { RuleConfigValue } from '@markuplint/ml-config';
|
|
2
|
+
/**
|
|
3
|
+
* Rule that checks whether special characters are properly escaped as
|
|
4
|
+
* character references.
|
|
5
|
+
*
|
|
6
|
+
* Scans text nodes and attribute values for the characters `"`, `&`, `<`,
|
|
7
|
+
* and `>` that are not already part of a valid character reference. Text
|
|
8
|
+
* inside `<script>` and `<style>` elements is excluded.
|
|
9
|
+
*/
|
|
2
10
|
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<RuleConfigValue, undefined>>;
|
|
3
11
|
export default _default;
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
import { createRule, getLocationFromChars } from '@markuplint/ml-core';
|
|
2
2
|
import meta from './meta.js';
|
|
3
|
+
/**
|
|
4
|
+
* Characters that must be escaped using character references in HTML text
|
|
5
|
+
* and attribute values.
|
|
6
|
+
*/
|
|
3
7
|
const defaultChars = ['"', '&', '<', '>'];
|
|
8
|
+
/**
|
|
9
|
+
* Parent elements whose text content is exempt from character reference checks
|
|
10
|
+
* because their content is not parsed as HTML.
|
|
11
|
+
*/
|
|
4
12
|
const ignoreParentElement = new Set(['script', 'style']);
|
|
13
|
+
/**
|
|
14
|
+
* Rule that checks whether special characters are properly escaped as
|
|
15
|
+
* character references.
|
|
16
|
+
*
|
|
17
|
+
* Scans text nodes and attribute values for the characters `"`, `&`, `<`,
|
|
18
|
+
* and `>` that are not already part of a valid character reference. Text
|
|
19
|
+
* inside `<script>` and `<style>` elements is excluded.
|
|
20
|
+
*/
|
|
5
21
|
export default createRule({
|
|
6
22
|
meta: meta,
|
|
7
23
|
async verify({ document, report, t }) {
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/** One or more regex or glob patterns that class names must match, or `null` to disable. */
|
|
1
2
|
export type Value = string | string[] | null;
|
|
3
|
+
/**
|
|
4
|
+
* Rule that validates class attribute values against configured naming patterns.
|
|
5
|
+
*
|
|
6
|
+
* Splits the `class` attribute into individual class names and checks each
|
|
7
|
+
* one against the provided string or regex patterns. Reports any class name
|
|
8
|
+
* that does not match at least one of the configured patterns. Dynamic
|
|
9
|
+
* values are excluded from the check.
|
|
10
|
+
*/
|
|
2
11
|
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<Value, undefined>>;
|
|
3
12
|
export default _default;
|
|
@@ -2,6 +2,14 @@ import { createRule } from '@markuplint/ml-core';
|
|
|
2
2
|
import { toNoEmptyStringArrayFromStringOrArray } from '@markuplint/shared';
|
|
3
3
|
import { match } from '../helpers.js';
|
|
4
4
|
import meta from './meta.js';
|
|
5
|
+
/**
|
|
6
|
+
* Rule that validates class attribute values against configured naming patterns.
|
|
7
|
+
*
|
|
8
|
+
* Splits the `class` attribute into individual class names and checks each
|
|
9
|
+
* one against the provided string or regex patterns. Reports any class name
|
|
10
|
+
* that does not match at least one of the configured patterns. Dynamic
|
|
11
|
+
* values are excluded from the check.
|
|
12
|
+
*/
|
|
5
13
|
export default createRule({
|
|
6
14
|
meta: meta,
|
|
7
15
|
defaultSeverity: 'warning',
|
package/lib/class-naming/meta.js
CHANGED
package/lib/create-message.d.ts
CHANGED
|
@@ -2,5 +2,32 @@ import type { Translator } from '@markuplint/i18n';
|
|
|
2
2
|
import type { AttributeType } from '@markuplint/ml-spec';
|
|
3
3
|
import type { UnmatchedResult } from '@markuplint/types';
|
|
4
4
|
import type { ReadonlyDeep } from 'type-fest';
|
|
5
|
+
/**
|
|
6
|
+
* Builds a human-readable error message explaining why an attribute value
|
|
7
|
+
* does not match its expected type. Handles both plain types and list types
|
|
8
|
+
* (space-separated or comma-separated).
|
|
9
|
+
*
|
|
10
|
+
* @param t - The i18n translator for generating localized messages
|
|
11
|
+
* @param baseTarget - A human-readable description of the attribute being validated
|
|
12
|
+
* (e.g. `'the "href" attribute'`)
|
|
13
|
+
* @param type - The attribute type definition that the value was validated against
|
|
14
|
+
* @param matches - The result object from a failed type check, containing
|
|
15
|
+
* details about the mismatch (reason, candidate, part name, etc.)
|
|
16
|
+
* @returns A localized error message describing the expected value
|
|
17
|
+
*/
|
|
5
18
|
export declare function createMessageValueExpected(t: Translator, baseTarget: string, type: ReadonlyDeep<AttributeType>, matches: UnmatchedResult): string;
|
|
19
|
+
/**
|
|
20
|
+
* Assembles the detailed portion of a value-expected error message by
|
|
21
|
+
* inspecting the mismatch reason and composing reason, expectation,
|
|
22
|
+
* candidate suggestion, and fallback parts into a single string.
|
|
23
|
+
*
|
|
24
|
+
* This is an internal helper exposed for testing and advanced use.
|
|
25
|
+
* The double-underscore prefix indicates it is not part of the stable public API.
|
|
26
|
+
*
|
|
27
|
+
* @param t - The i18n translator for generating localized messages
|
|
28
|
+
* @param baseTarget - A human-readable description of the validation target
|
|
29
|
+
* @param expected - A description of the expected value(s), or `null` if unknown
|
|
30
|
+
* @param matches - Partial match result containing reason, candidate, and other details
|
|
31
|
+
* @returns A localized error message string
|
|
32
|
+
*/
|
|
6
33
|
export declare function __createMessageValueExpected(t: Translator, baseTarget: string, expected: string | null, matches: Pick<UnmatchedResult, 'partName' | 'reason' | 'raw' | 'candidate' | 'ref' | 'extra' | 'fallbackTo'>): string;
|
package/lib/create-message.js
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import { isList, isKeyword, isEnum, isNumber, isDirective } from '@markuplint/types';
|
|
2
|
+
/**
|
|
3
|
+
* Builds a human-readable error message explaining why an attribute value
|
|
4
|
+
* does not match its expected type. Handles both plain types and list types
|
|
5
|
+
* (space-separated or comma-separated).
|
|
6
|
+
*
|
|
7
|
+
* @param t - The i18n translator for generating localized messages
|
|
8
|
+
* @param baseTarget - A human-readable description of the attribute being validated
|
|
9
|
+
* (e.g. `'the "href" attribute'`)
|
|
10
|
+
* @param type - The attribute type definition that the value was validated against
|
|
11
|
+
* @param matches - The result object from a failed type check, containing
|
|
12
|
+
* details about the mismatch (reason, candidate, part name, etc.)
|
|
13
|
+
* @returns A localized error message describing the expected value
|
|
14
|
+
*/
|
|
2
15
|
export function createMessageValueExpected(t, baseTarget, type, matches) {
|
|
3
16
|
let target = baseTarget;
|
|
4
17
|
let listDescriptionPart;
|
|
@@ -17,6 +30,20 @@ export function createMessageValueExpected(t, baseTarget, type, matches) {
|
|
|
17
30
|
.join(t('. '));
|
|
18
31
|
return message;
|
|
19
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Assembles the detailed portion of a value-expected error message by
|
|
35
|
+
* inspecting the mismatch reason and composing reason, expectation,
|
|
36
|
+
* candidate suggestion, and fallback parts into a single string.
|
|
37
|
+
*
|
|
38
|
+
* This is an internal helper exposed for testing and advanced use.
|
|
39
|
+
* The double-underscore prefix indicates it is not part of the stable public API.
|
|
40
|
+
*
|
|
41
|
+
* @param t - The i18n translator for generating localized messages
|
|
42
|
+
* @param baseTarget - A human-readable description of the validation target
|
|
43
|
+
* @param expected - A description of the expected value(s), or `null` if unknown
|
|
44
|
+
* @param matches - Partial match result containing reason, candidate, and other details
|
|
45
|
+
* @returns A localized error message string
|
|
46
|
+
*/
|
|
20
47
|
export function __createMessageValueExpected(t, baseTarget, expected, matches) {
|
|
21
48
|
let target = baseTarget;
|
|
22
49
|
let reasonPart;
|
|
@@ -132,7 +159,7 @@ export function __createMessageValueExpected(t, baseTarget, expected, matches) {
|
|
|
132
159
|
switch (matches.reason.type) {
|
|
133
160
|
case 'out-of-range-length-digit': {
|
|
134
161
|
const { gte, lte } = matches.reason;
|
|
135
|
-
let expectedDigits
|
|
162
|
+
let expectedDigits;
|
|
136
163
|
if (lte != null && gte === lte) {
|
|
137
164
|
expectedDigits = t('{0} digits', gte);
|
|
138
165
|
}
|
|
@@ -199,6 +226,17 @@ export function __createMessageValueExpected(t, baseTarget, expected, matches) {
|
|
|
199
226
|
}
|
|
200
227
|
return message;
|
|
201
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Derives a human-readable description of the expected value from an attribute
|
|
231
|
+
* type definition and the unmatched result. Inspects keywords, enums, numbers,
|
|
232
|
+
* directives, and explicit `expects` entries from the match result.
|
|
233
|
+
*
|
|
234
|
+
* @param type - The attribute type (excluding list wrappers)
|
|
235
|
+
* @param matches - The unmatched result containing optional `expects` hints
|
|
236
|
+
* @param t - The i18n translator
|
|
237
|
+
* @returns A localized string describing the expected value(s), or `null` if
|
|
238
|
+
* no expectation can be determined
|
|
239
|
+
*/
|
|
202
240
|
function createExpectedObject(type, matches, t) {
|
|
203
241
|
const expectedObject = [];
|
|
204
242
|
if (matches.expects && matches.expects.length > 0) {
|
|
@@ -227,6 +265,14 @@ function createExpectedObject(type, matches, t) {
|
|
|
227
265
|
: (expectedObject[0] ?? null);
|
|
228
266
|
return expects;
|
|
229
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* Converts a single `Expect` descriptor into a human-readable word or phrase.
|
|
270
|
+
*
|
|
271
|
+
* @param t - The i18n translator
|
|
272
|
+
* @param expect - The expectation descriptor from a type-check result
|
|
273
|
+
* @param type - The attribute type context for determining phrasing (e.g. CSS syntax)
|
|
274
|
+
* @returns A localized word or phrase describing the expected value
|
|
275
|
+
*/
|
|
230
276
|
function expectValueToWord(t, expect, type) {
|
|
231
277
|
switch (expect.type) {
|
|
232
278
|
case 'common': {
|
|
@@ -249,6 +295,15 @@ function expectValueToWord(t, expect, type) {
|
|
|
249
295
|
}
|
|
250
296
|
}
|
|
251
297
|
}
|
|
298
|
+
/**
|
|
299
|
+
* Builds a human-readable description of an expected numeric range
|
|
300
|
+
* from a `Number` type definition (e.g. "integer greater than or equal to 0").
|
|
301
|
+
*
|
|
302
|
+
* @param t - The i18n translator
|
|
303
|
+
* @param type - The number type definition containing range constraints
|
|
304
|
+
* (`gt`, `gte`, `lt`, `lte`) and the numeric type label
|
|
305
|
+
* @returns A localized description of the expected numeric range
|
|
306
|
+
*/
|
|
252
307
|
function createExpectedNumber(t, type) {
|
|
253
308
|
if (type.gt != null) {
|
|
254
309
|
if (type.lt != null) {
|
package/lib/debug.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
import debug from 'debug';
|
|
2
|
+
/**
|
|
3
|
+
* Type alias for the debug logger function provided by the `debug` package.
|
|
4
|
+
* Used throughout the rules package for conditional diagnostic logging.
|
|
5
|
+
*/
|
|
2
6
|
export type Log = debug.Debugger;
|
|
7
|
+
/**
|
|
8
|
+
* Shared debug logger instance for the `@markuplint/rules` package.
|
|
9
|
+
* Enable by setting the `DEBUG` environment variable to include `ml-rules`
|
|
10
|
+
* (e.g. `DEBUG=ml-rules`).
|
|
11
|
+
*/
|
|
3
12
|
export declare const log: debug.Debugger;
|
package/lib/debug.js
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule that reports the use of deprecated or obsolete HTML attributes.
|
|
3
|
+
*
|
|
4
|
+
* Checks each attribute against the HTML spec and reports any that are
|
|
5
|
+
* marked as deprecated or obsolete.
|
|
6
|
+
*/
|
|
1
7
|
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
|
|
2
8
|
export default _default;
|