@markuplint/rules 3.0.0-alpha.2 → 3.0.0-alpha.27
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 +10 -44
- package/lib/attr-check.d.ts +2 -2
- package/lib/attr-value-quotes/index.d.ts +3 -3
- package/lib/case-sensitive-attr-name/index.d.ts +1 -1
- package/lib/case-sensitive-tag-name/index.d.ts +1 -1
- package/lib/class-naming/index.d.ts +1 -1
- package/lib/class-naming/index.js +1 -1
- package/lib/debug.d.ts +1 -1
- package/lib/doctype/index.d.ts +1 -1
- package/lib/doctype/index.js +1 -1
- package/lib/end-tag/index.js +2 -17
- package/lib/helpers.d.ts +2 -31
- package/lib/helpers.js +1 -71
- package/lib/index.d.ts +2 -58
- package/lib/index.js +4 -0
- package/lib/invalid-attr/index.d.ts +3 -2
- package/lib/invalid-attr/index.js +16 -11
- package/lib/label-has-control/index.d.ts +2 -0
- package/lib/label-has-control/index.js +28 -0
- package/lib/landmark-roles/index.d.ts +3 -3
- package/lib/landmark-roles/index.js +2 -2
- package/lib/no-empty-palpable-content/index.d.ts +6 -0
- package/lib/no-empty-palpable-content/index.js +34 -0
- package/lib/no-refer-to-non-existent-id/index.js +1 -1
- package/lib/no-use-event-handler-attr/index.d.ts +1 -1
- package/lib/no-use-event-handler-attr/index.js +4 -4
- package/lib/permitted-contents/debug.browser.d.ts +30 -0
- package/lib/permitted-contents/debug.browser.js +14 -0
- package/lib/permitted-contents/debug.d.ts +1 -0
- package/lib/permitted-contents/debug.js +9 -1
- package/lib/permitted-contents/index.js +4 -4
- package/lib/permitted-contents/matches-selector.d.ts +1 -1
- package/lib/permitted-contents/represent-transparent-nodes.d.ts +1 -1
- package/lib/permitted-contents/represent-transparent-nodes.js +0 -3
- package/lib/permitted-contents/start.js +1 -1
- package/lib/permitted-contents/transparent.js +6 -11
- package/lib/permitted-contents/types.d.ts +12 -12
- package/lib/permitted-contents/utils.d.ts +4 -4
- package/lib/permitted-contents/utils.js +8 -8
- package/lib/require-accessible-name/index.d.ts +1 -1
- package/lib/require-accessible-name/index.js +7 -3
- package/lib/required-attr/index.d.ts +2 -2
- package/lib/required-element/index.d.ts +1 -1
- package/lib/required-element/index.js +1 -1
- package/lib/required-h1/index.js +2 -2
- package/lib/use-list/index.d.ts +2 -2
- package/lib/use-list/index.js +1 -1
- package/lib/wai-aria/checkings/abstract-role.js +1 -1
- package/lib/wai-aria/checkings/implicit-role.js +1 -1
- package/lib/wai-aria/checkings/{non-existant-role.d.ts → non-existent-role.d.ts} +1 -1
- package/lib/wai-aria/checkings/{non-existant-role.js → non-existent-role.js} +4 -4
- package/lib/wai-aria/checkings/permitted-roles.js +1 -1
- package/lib/wai-aria/checkings/presentational-children.js +1 -1
- package/lib/wai-aria/checkings/required-owned-elements.js +40 -10
- package/lib/wai-aria/checkings/value.d.ts +6 -0
- package/lib/wai-aria/checkings/value.js +74 -4
- package/lib/wai-aria/index.js +14 -14
- package/lib/wai-aria/types.d.ts +1 -1
- package/package.json +11 -8
- package/schema.json +6 -0
- package/tsconfig.test.json +0 -3
- package/tsconfig.tsbuildinfo +0 -1
package/README.md
CHANGED
|
@@ -1,58 +1,24 @@
|
|
|
1
1
|
# @markuplint/rules
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@markuplint/rules)
|
|
4
|
-
[](https://travis-ci.org/markuplint/markuplint)
|
|
5
|
-
[](https://coveralls.io/github/markuplint/markuplint?branch=main)
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
**Built-in rules**
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
## Documentation
|
|
10
8
|
|
|
11
|
-
- [
|
|
12
|
-
- [`character-reference`](./src/character-reference)
|
|
13
|
-
- [`deprecated-attr`](./src/deprecated-attr)
|
|
14
|
-
- [`deprecated-element`](./src/deprecated-element)
|
|
15
|
-
- [`disallowed-element`](./src/disallowed-element)
|
|
16
|
-
- [`doctype`](./src/doctype)
|
|
17
|
-
- [`id-duplication`](./src/id-duplication)
|
|
18
|
-
- [`ineffective-attr`](./src/ineffective-attr)
|
|
19
|
-
- [`invalid-attr`](./src/invalid-attr)
|
|
20
|
-
- [`permitted-contents`](./src/permitted-contents)
|
|
21
|
-
- [`required-attr`](./src/required-attr)
|
|
22
|
-
- [`required-element`](./src/required-element)
|
|
23
|
-
|
|
24
|
-
### Accessibility
|
|
25
|
-
|
|
26
|
-
- [`landmark-roles`](./src/landmark-roles)
|
|
27
|
-
- [`no-refer-to-non-existent-id`](./src/no-refer-to-non-existent-id)
|
|
28
|
-
- [`required-h1`](./src/required-h1)
|
|
29
|
-
- [`use-list`](./src/use-list)
|
|
30
|
-
- [`wai-aria`](./src/wai-aria)
|
|
31
|
-
|
|
32
|
-
### Naming Convention
|
|
33
|
-
|
|
34
|
-
- [`class-naming`](./src/class-naming)
|
|
35
|
-
|
|
36
|
-
### Maintainability
|
|
37
|
-
|
|
38
|
-
- [`no-hard-code-id`](./src/no-hard-code-id)
|
|
39
|
-
- [`no-use-event-handler-attr`](./src/no-use-event-handler-attr)
|
|
40
|
-
|
|
41
|
-
### Style
|
|
42
|
-
|
|
43
|
-
- [`attr-value-quotes`](./src/attr-value-quotes)
|
|
44
|
-
- [`case-sensitive-attr-name`](./src/case-sensitive-attr-name)
|
|
45
|
-
- [`case-sensitive-tag-name`](./src/case-sensitive-tag-name)
|
|
46
|
-
- [`end-tag`](./src/end-tag)
|
|
47
|
-
- [`no-boolean-attr-value`](./src/no-boolean-attr-value)
|
|
48
|
-
- [`no-default-value`](./src/no-default-value)
|
|
9
|
+
- [Rules](https://markuplint.dev/rules/)
|
|
49
10
|
|
|
50
11
|
## Install
|
|
51
12
|
|
|
52
|
-
|
|
13
|
+
[`markuplint`](https://www.npmjs.com/package/markuplint) package includes this package.
|
|
53
14
|
|
|
54
|
-
|
|
15
|
+
<details>
|
|
16
|
+
<summary>If you are installing purposely, how below:</summary>
|
|
17
|
+
|
|
18
|
+
```shell
|
|
55
19
|
$ npm install -D @markuplint/rules
|
|
56
20
|
|
|
57
21
|
$ yarn add -D @markuplint/rules
|
|
58
22
|
```
|
|
23
|
+
|
|
24
|
+
</details>
|
package/lib/attr-check.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Translator } from '@markuplint/i18n';
|
|
2
2
|
import type { Attribute as AttrSpec, AttributeType } from '@markuplint/ml-spec';
|
|
3
|
-
|
|
3
|
+
type Invalid = {
|
|
4
4
|
invalidType: 'non-existent' | 'invalid-value';
|
|
5
5
|
message: string;
|
|
6
6
|
loc?: Loc;
|
|
7
7
|
};
|
|
8
|
-
|
|
8
|
+
type Loc = {
|
|
9
9
|
raw: string;
|
|
10
10
|
line: number;
|
|
11
11
|
col: number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
1
|
+
export type Type = 'double' | 'single';
|
|
2
|
+
export type Quote = '"' | "'";
|
|
3
|
+
export type QuoteMap = {
|
|
4
4
|
[P in Type]: Quote;
|
|
5
5
|
};
|
|
6
6
|
declare const _default: import("@markuplint/ml-core").RuleSeed<Type, null>;
|
|
@@ -10,7 +10,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
10
10
|
if (!el.rule.value) {
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
|
-
const classPatterns = Array.isArray(el.rule.value) ? el.rule.value : [el.rule.value];
|
|
13
|
+
const classPatterns = (Array.isArray(el.rule.value) ? el.rule.value : [el.rule.value]).filter(className => className && typeof className === 'string');
|
|
14
14
|
const attrs = el.getAttributeToken('class');
|
|
15
15
|
for (const attr of attrs) {
|
|
16
16
|
if (attr.isDynamicValue) {
|
package/lib/debug.d.ts
CHANGED
package/lib/doctype/index.d.ts
CHANGED
package/lib/doctype/index.js
CHANGED
|
@@ -23,7 +23,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
23
23
|
if ((doctype.name.toLowerCase() === 'html' && doctype.publicId) || doctype.systemId) {
|
|
24
24
|
report({
|
|
25
25
|
scope: doctype,
|
|
26
|
-
message: t('Never {0} {1}', '
|
|
26
|
+
message: t('Never {0} {1}', 'declare', 'obsolete doctype'),
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
},
|
package/lib/end-tag/index.js
CHANGED
|
@@ -1,22 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
-
const
|
|
5
|
-
'area',
|
|
6
|
-
'base',
|
|
7
|
-
'br',
|
|
8
|
-
'col',
|
|
9
|
-
'embed',
|
|
10
|
-
'hr',
|
|
11
|
-
'img',
|
|
12
|
-
'input',
|
|
13
|
-
'link',
|
|
14
|
-
'meta',
|
|
15
|
-
'param',
|
|
16
|
-
'source',
|
|
17
|
-
'track',
|
|
18
|
-
'wbr',
|
|
19
|
-
];
|
|
4
|
+
const ml_spec_1 = require("@markuplint/ml-spec");
|
|
20
5
|
exports.default = (0, ml_core_1.createRule)({
|
|
21
6
|
defaultSeverity: 'warning',
|
|
22
7
|
async verify({ document, report, t }) {
|
|
@@ -28,7 +13,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
28
13
|
if (el.isOmitted) {
|
|
29
14
|
return;
|
|
30
15
|
}
|
|
31
|
-
if (
|
|
16
|
+
if ((0, ml_spec_1.isVoidElement)(el)) {
|
|
32
17
|
return;
|
|
33
18
|
}
|
|
34
19
|
if (el.closeTag != null) {
|
package/lib/helpers.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Log } from './debug';
|
|
2
2
|
import type { Translator } from '@markuplint/i18n';
|
|
3
3
|
import type { Element, RuleConfigValue, Document } from '@markuplint/ml-core';
|
|
4
|
-
import type {
|
|
4
|
+
import type { Attribute } from '@markuplint/ml-spec';
|
|
5
5
|
export declare function attrMatches<T extends RuleConfigValue, R>(node: Element<T, R>, condition: Attribute['condition']): boolean;
|
|
6
6
|
export declare function match(needle: string, pattern: string): boolean;
|
|
7
7
|
/**
|
|
@@ -30,35 +30,6 @@ export declare function isValidAttr(t: Translator, name: string, value: string,
|
|
|
30
30
|
} | undefined;
|
|
31
31
|
};
|
|
32
32
|
export declare function toNormalizedValue(value: string, spec: Attribute): string;
|
|
33
|
-
/**
|
|
34
|
-
*
|
|
35
|
-
* @see https://www.w3.org/TR/wai-aria-1.2/#propcharacteristic_value
|
|
36
|
-
*
|
|
37
|
-
* @param type
|
|
38
|
-
* @param value
|
|
39
|
-
* @param tokenEnum
|
|
40
|
-
*/
|
|
41
|
-
export declare function checkAriaValue(type: string, value: string, tokenEnum: string[]): boolean;
|
|
42
|
-
export declare function checkAria(specs: Readonly<MLMLSpec>, attrName: string, currentValue: string, version: ARIAVersion, role?: string): {
|
|
43
|
-
currentValue: string;
|
|
44
|
-
isValid: boolean;
|
|
45
|
-
} | {
|
|
46
|
-
currentValue: string;
|
|
47
|
-
isValid: boolean;
|
|
48
|
-
name: string;
|
|
49
|
-
type: "property" | "state";
|
|
50
|
-
deprecated?: true | undefined;
|
|
51
|
-
isGlobal?: true | undefined;
|
|
52
|
-
value: import("@markuplint/ml-spec").ARIAAttributeValue;
|
|
53
|
-
conditionalValue?: {
|
|
54
|
-
role: string[];
|
|
55
|
-
value: import("@markuplint/ml-spec").ARIAAttributeValue;
|
|
56
|
-
}[] | undefined;
|
|
57
|
-
enum: string[];
|
|
58
|
-
defaultValue?: string | undefined;
|
|
59
|
-
equivalentHtmlAttrs?: import("@markuplint/ml-spec").EquivalentHtmlAttr[] | undefined;
|
|
60
|
-
valueDescriptions?: Record<string, string> | undefined;
|
|
61
|
-
};
|
|
62
33
|
export declare function accnameMayBeMutable(el: Element<any, any>, document: Document<any, any>): boolean;
|
|
63
34
|
export declare function getOwnedLabel<V extends RuleConfigValue, O>(el: Element<V, O>, document: Document<V, O>): Element<V, O> | null;
|
|
64
35
|
export declare function decodeCharRef(characterReference: string): string;
|
|
@@ -69,7 +40,7 @@ export declare class Collection<T> {
|
|
|
69
40
|
add(...items: (T | null | undefined)[]): void;
|
|
70
41
|
toArray(): readonly T[];
|
|
71
42
|
}
|
|
72
|
-
|
|
43
|
+
type Writeable<T> = {
|
|
73
44
|
-readonly [P in keyof T]: T[P];
|
|
74
45
|
};
|
|
75
46
|
export declare function deepCopy<T>(value: T): Writeable<T>;
|
package/lib/helpers.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var _Collection_items;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.deepCopy = exports.Collection = exports.decodeCharRef = exports.getOwnedLabel = exports.accnameMayBeMutable = exports.
|
|
4
|
+
exports.deepCopy = exports.Collection = exports.decodeCharRef = exports.getOwnedLabel = exports.accnameMayBeMutable = exports.toNormalizedValue = exports.isValidAttr = exports.rePCENChar = exports.match = exports.attrMatches = void 0;
|
|
5
5
|
const tslib_1 = require("tslib");
|
|
6
|
-
const ml_core_1 = require("@markuplint/ml-core");
|
|
7
6
|
// @ts-ignore
|
|
8
7
|
const structured_clone_1 = tslib_1.__importDefault(require("@ungap/structured-clone"));
|
|
9
8
|
const html_entities_1 = require("html-entities");
|
|
@@ -107,75 +106,6 @@ function toNormalizedValue(value, spec) {
|
|
|
107
106
|
return normalized;
|
|
108
107
|
}
|
|
109
108
|
exports.toNormalizedValue = toNormalizedValue;
|
|
110
|
-
/**
|
|
111
|
-
*
|
|
112
|
-
* @see https://www.w3.org/TR/wai-aria-1.2/#propcharacteristic_value
|
|
113
|
-
*
|
|
114
|
-
* @param type
|
|
115
|
-
* @param value
|
|
116
|
-
* @param tokenEnum
|
|
117
|
-
*/
|
|
118
|
-
function checkAriaValue(type, value, tokenEnum) {
|
|
119
|
-
switch (type) {
|
|
120
|
-
case 'token': {
|
|
121
|
-
return tokenEnum.includes(value);
|
|
122
|
-
}
|
|
123
|
-
case 'token list': {
|
|
124
|
-
const list = value.split(/\s+/g).map(s => s.trim());
|
|
125
|
-
return list.every(token => tokenEnum.includes(token));
|
|
126
|
-
}
|
|
127
|
-
case 'string':
|
|
128
|
-
case 'ID reference':
|
|
129
|
-
case 'ID reference list': {
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
case 'true/false': {
|
|
133
|
-
return ['true', 'false'].includes(value);
|
|
134
|
-
}
|
|
135
|
-
case 'tristate': {
|
|
136
|
-
return ['mixed', 'true', 'false', 'undefined'].includes(value);
|
|
137
|
-
}
|
|
138
|
-
case 'true/false/undefined': {
|
|
139
|
-
return ['true', 'false', 'undefined'].includes(value);
|
|
140
|
-
}
|
|
141
|
-
case 'integer': {
|
|
142
|
-
return parseInt(value).toString() === value;
|
|
143
|
-
}
|
|
144
|
-
case 'number': {
|
|
145
|
-
return parseFloat(value).toString() === value;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
// For skipping checking
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
exports.checkAriaValue = checkAriaValue;
|
|
152
|
-
function checkAria(specs, attrName, currentValue, version, role) {
|
|
153
|
-
const ariaAttrs = (0, ml_core_1.ariaSpecs)(specs, version).props;
|
|
154
|
-
const aria = ariaAttrs.find(a => a.name === attrName);
|
|
155
|
-
if (!aria) {
|
|
156
|
-
return {
|
|
157
|
-
currentValue,
|
|
158
|
-
// For skipping checking
|
|
159
|
-
isValid: true,
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
let valueType = aria.value;
|
|
163
|
-
if (role && aria.conditionalValue) {
|
|
164
|
-
for (const cond of aria.conditionalValue) {
|
|
165
|
-
if (cond.role.includes(role)) {
|
|
166
|
-
valueType = cond.value;
|
|
167
|
-
break;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
const isValid = checkAriaValue(valueType, currentValue, aria.enum);
|
|
172
|
-
return {
|
|
173
|
-
...aria,
|
|
174
|
-
currentValue,
|
|
175
|
-
isValid,
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
exports.checkAria = checkAria;
|
|
179
109
|
function accnameMayBeMutable(el, document) {
|
|
180
110
|
if (el.hasMutableAttributes() || el.hasMutableChildren(true)) {
|
|
181
111
|
return true;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,59 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
'attr-value-quotes': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./attr-value-quotes").Type, null>;
|
|
4
|
-
'case-sensitive-attr-name': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./case-sensitive-attr-name").Value, null>;
|
|
5
|
-
'case-sensitive-tag-name': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./case-sensitive-tag-name").Value, null>;
|
|
6
|
-
'character-reference': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
7
|
-
'class-naming': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./class-naming").Value, null>;
|
|
8
|
-
'deprecated-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
9
|
-
'deprecated-element': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
10
|
-
'disallowed-element': import("packages/@markuplint/ml-core/lib").RuleSeed<string[], null>;
|
|
11
|
-
doctype: import("packages/@markuplint/ml-core/lib").RuleSeed<"always", {
|
|
12
|
-
denyObsoleteType: boolean;
|
|
13
|
-
}>;
|
|
14
|
-
'end-tag': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, null>;
|
|
15
|
-
'id-duplication': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
16
|
-
'ineffective-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
17
|
-
'invalid-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, {
|
|
18
|
-
attrs?: Record<string, {
|
|
19
|
-
enum: [string, ...string[]];
|
|
20
|
-
} | {
|
|
21
|
-
pattern: string;
|
|
22
|
-
} | {
|
|
23
|
-
type: import("packages/@markuplint/ml-spec/lib").AttributeType;
|
|
24
|
-
} | {
|
|
25
|
-
disallowed: true;
|
|
26
|
-
}> | undefined;
|
|
27
|
-
ignoreAttrNamePrefix?: string | string[] | undefined;
|
|
28
|
-
}>;
|
|
29
|
-
'landmark-roles': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, {
|
|
30
|
-
ignoreRoles: (("banner" | "main" | "complementary" | "contentinfo") | "form" | "navigation" | "region")[];
|
|
31
|
-
labelEachArea: boolean;
|
|
32
|
-
}>;
|
|
33
|
-
'no-boolean-attr-value': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
34
|
-
'no-default-value': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
35
|
-
'no-hard-code-id': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
|
|
36
|
-
'no-refer-to-non-existent-id': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, {
|
|
37
|
-
ariaVersion: import("packages/@markuplint/ml-spec/lib").ARIAVersion;
|
|
38
|
-
}>;
|
|
39
|
-
'no-use-event-handler-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, {
|
|
40
|
-
ignore?: string | string[] | undefined;
|
|
41
|
-
}>;
|
|
42
|
-
'permitted-contents': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./permitted-contents/types").TagRule[], import("./permitted-contents/types").Options>;
|
|
43
|
-
'require-accessible-name': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, {
|
|
44
|
-
ariaVersion: import("packages/@markuplint/ml-spec/lib").ARIAVersion;
|
|
45
|
-
}>;
|
|
46
|
-
'required-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<string | (string | {
|
|
47
|
-
name: string;
|
|
48
|
-
value: string | string[];
|
|
49
|
-
})[], null>;
|
|
50
|
-
'required-element': import("packages/@markuplint/ml-core/lib").RuleSeed<string[], {
|
|
51
|
-
ignoreHasMutableContents: boolean;
|
|
52
|
-
}>;
|
|
53
|
-
'required-h1': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, import("./required-h1").Options>;
|
|
54
|
-
'use-list': import("packages/@markuplint/ml-core/lib").RuleSeed<string[], {
|
|
55
|
-
spaceNeededBullets?: string[] | undefined;
|
|
56
|
-
}>;
|
|
57
|
-
'wai-aria': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, import("./wai-aria/types").Options>;
|
|
58
|
-
};
|
|
1
|
+
import type { AnyRuleSeed } from '@markuplint/ml-core';
|
|
2
|
+
declare const _default: Record<string, AnyRuleSeed>;
|
|
59
3
|
export default _default;
|
package/lib/index.js
CHANGED
|
@@ -15,9 +15,11 @@ const end_tag_1 = tslib_1.__importDefault(require("./end-tag"));
|
|
|
15
15
|
const id_duplication_1 = tslib_1.__importDefault(require("./id-duplication"));
|
|
16
16
|
const ineffective_attr_1 = tslib_1.__importDefault(require("./ineffective-attr"));
|
|
17
17
|
const invalid_attr_1 = tslib_1.__importDefault(require("./invalid-attr"));
|
|
18
|
+
const label_has_control_1 = tslib_1.__importDefault(require("./label-has-control"));
|
|
18
19
|
const landmark_roles_1 = tslib_1.__importDefault(require("./landmark-roles"));
|
|
19
20
|
const no_boolean_attr_value_1 = tslib_1.__importDefault(require("./no-boolean-attr-value"));
|
|
20
21
|
const no_default_value_1 = tslib_1.__importDefault(require("./no-default-value"));
|
|
22
|
+
const no_empty_palpable_content_1 = tslib_1.__importDefault(require("./no-empty-palpable-content"));
|
|
21
23
|
const no_hard_code_id_1 = tslib_1.__importDefault(require("./no-hard-code-id"));
|
|
22
24
|
const no_refer_to_non_existent_id_1 = tslib_1.__importDefault(require("./no-refer-to-non-existent-id"));
|
|
23
25
|
const no_use_event_handler_attr_1 = tslib_1.__importDefault(require("./no-use-event-handler-attr"));
|
|
@@ -43,9 +45,11 @@ exports.default = {
|
|
|
43
45
|
'id-duplication': id_duplication_1.default,
|
|
44
46
|
'ineffective-attr': ineffective_attr_1.default,
|
|
45
47
|
'invalid-attr': invalid_attr_1.default,
|
|
48
|
+
'label-has-control': label_has_control_1.default,
|
|
46
49
|
'landmark-roles': landmark_roles_1.default,
|
|
47
50
|
'no-boolean-attr-value': no_boolean_attr_value_1.default,
|
|
48
51
|
'no-default-value': no_default_value_1.default,
|
|
52
|
+
'no-empty-palpable-content': no_empty_palpable_content_1.default,
|
|
49
53
|
'no-hard-code-id': no_hard_code_id_1.default,
|
|
50
54
|
'no-refer-to-non-existent-id': no_refer_to_non_existent_id_1.default,
|
|
51
55
|
'no-use-event-handler-attr': no_use_event_handler_attr_1.default,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { AttributeType } from '@markuplint/ml-spec';
|
|
2
|
-
|
|
2
|
+
type Option = {
|
|
3
3
|
attrs?: Record<string, Rule>;
|
|
4
4
|
ignoreAttrNamePrefix?: string | string[];
|
|
5
|
+
allowToAddPropertiesForPretender?: boolean;
|
|
5
6
|
};
|
|
6
|
-
|
|
7
|
+
type Rule = {
|
|
7
8
|
enum: [string, ...string[]];
|
|
8
9
|
} | {
|
|
9
10
|
pattern: string;
|
|
@@ -9,7 +9,9 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
9
9
|
defaultOptions: {},
|
|
10
10
|
async verify({ document, report, t }) {
|
|
11
11
|
await document.walkOn('Attr', attr => {
|
|
12
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
12
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
13
|
+
// Default
|
|
14
|
+
const allowToAddPropertiesForPretender = (_a = attr.rule.options.allowToAddPropertiesForPretender) !== null && _a !== void 0 ? _a : true;
|
|
13
15
|
if (attr.isDirective) {
|
|
14
16
|
return;
|
|
15
17
|
}
|
|
@@ -31,16 +33,16 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
31
33
|
}
|
|
32
34
|
const valueNode = attr.valueNode;
|
|
33
35
|
const value = attr.value;
|
|
34
|
-
if (attr.rule.
|
|
35
|
-
const ignoreAttrNamePrefixes = Array.isArray(attr.rule.
|
|
36
|
-
? attr.rule.
|
|
37
|
-
: [attr.rule.
|
|
36
|
+
if (attr.rule.options.ignoreAttrNamePrefix) {
|
|
37
|
+
const ignoreAttrNamePrefixes = Array.isArray(attr.rule.options.ignoreAttrNamePrefix)
|
|
38
|
+
? attr.rule.options.ignoreAttrNamePrefix
|
|
39
|
+
: [attr.rule.options.ignoreAttrNamePrefix];
|
|
38
40
|
if (ignoreAttrNamePrefixes.some(prefix => name.indexOf(prefix) === 0)) {
|
|
39
41
|
return;
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
let invalid = false;
|
|
43
|
-
const customRule = attr.rule.
|
|
45
|
+
const customRule = attr.rule.options.attrs ? attr.rule.options.attrs[name] : null;
|
|
44
46
|
if (customRule) {
|
|
45
47
|
if ('enum' in customRule) {
|
|
46
48
|
invalid = (0, attr_check_1.attrCheck)(t, name.toLowerCase(), value, true, {
|
|
@@ -82,15 +84,18 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
82
84
|
report({
|
|
83
85
|
scope: attr,
|
|
84
86
|
message: invalid.message,
|
|
85
|
-
line: ((
|
|
86
|
-
col: ((
|
|
87
|
-
? ((
|
|
88
|
-
: ((
|
|
89
|
-
raw: (
|
|
87
|
+
line: ((_b = valueNode === null || valueNode === void 0 ? void 0 : valueNode.startLine) !== null && _b !== void 0 ? _b : 0) + ((_d = (_c = invalid.loc) === null || _c === void 0 ? void 0 : _c.line) !== null && _d !== void 0 ? _d : 0),
|
|
88
|
+
col: ((_e = invalid.loc) === null || _e === void 0 ? void 0 : _e.line)
|
|
89
|
+
? ((_f = invalid.loc) === null || _f === void 0 ? void 0 : _f.col) + 1
|
|
90
|
+
: ((_g = valueNode === null || valueNode === void 0 ? void 0 : valueNode.startCol) !== null && _g !== void 0 ? _g : 0) + ((_j = (_h = invalid.loc) === null || _h === void 0 ? void 0 : _h.col) !== null && _j !== void 0 ? _j : 0),
|
|
91
|
+
raw: (_l = (_k = invalid.loc) === null || _k === void 0 ? void 0 : _k.raw) !== null && _l !== void 0 ? _l : value,
|
|
90
92
|
});
|
|
91
93
|
break;
|
|
92
94
|
}
|
|
93
95
|
case 'non-existent': {
|
|
96
|
+
if (allowToAddPropertiesForPretender && ((_m = attr.ownerElement.pretenderContext) === null || _m === void 0 ? void 0 : _m.type) === 'origin') {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
94
99
|
const spec = (0, ml_core_1.getSpec)(attr.ownerElement, document.specs.specs);
|
|
95
100
|
if (spec === null || spec === void 0 ? void 0 : spec.possibleToAddProperties) {
|
|
96
101
|
return;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
+
const controlSelector = ["input:not([type='hidden' i])", 'select', 'textarea'].join(',');
|
|
5
|
+
exports.default = (0, ml_core_1.createRule)({
|
|
6
|
+
defaultSeverity: 'warning',
|
|
7
|
+
async verify({ document, report, t }) {
|
|
8
|
+
await document.walkOn('Element', el => {
|
|
9
|
+
if (el.localName !== 'label') {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (el.children.length === 0 && !el.hasAttribute('for')) {
|
|
13
|
+
report({
|
|
14
|
+
scope: el,
|
|
15
|
+
message: t('{0} should associate with {1}', t('The "{0*}" {1}', 'label', 'element'), t('a {0}', 'control')),
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
const controls = el.querySelectorAll(controlSelector);
|
|
19
|
+
const secondControl = controls[1];
|
|
20
|
+
if (secondControl) {
|
|
21
|
+
report({
|
|
22
|
+
scope: secondControl,
|
|
23
|
+
message: t('{0} associates only {1}', t('The "{0*}" {1}', 'label', 'element'), t('first {0}', 'control')),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
type Options = {
|
|
2
2
|
ignoreRoles: Roles[];
|
|
3
3
|
labelEachArea: boolean;
|
|
4
4
|
};
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
type TopLevelRoles = 'banner' | 'main' | 'complementary' | 'contentinfo';
|
|
6
|
+
type Roles = TopLevelRoles | 'form' | 'navigation' | 'region';
|
|
7
7
|
declare const _default: import("@markuplint/ml-core").RuleSeed<boolean, Options>;
|
|
8
8
|
export default _default;
|
|
@@ -72,7 +72,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
72
72
|
if (el.rule.disabled) {
|
|
73
73
|
continue;
|
|
74
74
|
}
|
|
75
|
-
if ((_a = el.rule.
|
|
75
|
+
if ((_a = el.rule.options.ignoreRoles) === null || _a === void 0 ? void 0 : _a.includes(role)) {
|
|
76
76
|
continue;
|
|
77
77
|
}
|
|
78
78
|
if (el.isDescendantByUUIDList(uuidList)) {
|
|
@@ -93,7 +93,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
93
93
|
if (el.rule.disabled) {
|
|
94
94
|
continue;
|
|
95
95
|
}
|
|
96
|
-
if (!el.rule.
|
|
96
|
+
if (!el.rule.options.labelEachArea) {
|
|
97
97
|
continue;
|
|
98
98
|
}
|
|
99
99
|
if (!hasLabel(el)) {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
+
const ml_spec_1 = require("@markuplint/ml-spec");
|
|
5
|
+
exports.default = (0, ml_core_1.createRule)({
|
|
6
|
+
defaultSeverity: 'warning',
|
|
7
|
+
defaultOptions: {
|
|
8
|
+
extendsExposableElements: true,
|
|
9
|
+
ignoreIfAriaBusy: true,
|
|
10
|
+
},
|
|
11
|
+
async verify({ document, report, t }) {
|
|
12
|
+
await document.walkOn('Element', el => {
|
|
13
|
+
if (!(0, ml_spec_1.isPalpableElement)(el, el.ownerMLDocument.specs, {
|
|
14
|
+
extendsSvg: false,
|
|
15
|
+
extendsExposableElements: el.rule.options.extendsExposableElements,
|
|
16
|
+
})) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if ((0, ml_spec_1.isNothingContentModel)(el)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (el.rule.options.ignoreIfAriaBusy && el.getAttribute('aria-busy') === 'true') {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const isEmpty = Array.from(el.childNodes).every(node => node.is(node.TEXT_NODE) && node.isWhitespace());
|
|
26
|
+
if (isEmpty) {
|
|
27
|
+
report({
|
|
28
|
+
scope: el,
|
|
29
|
+
message: t('{0} should not {1}', t('the {0}', 'element'), 'empty'),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
});
|
|
@@ -69,7 +69,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
const { props } = (0, ml_core_1.ariaSpecs)(document.specs, attr.rule.
|
|
72
|
+
const { props } = (0, ml_core_1.ariaSpecs)(document.specs, attr.rule.options.ariaVersion);
|
|
73
73
|
const aria = props.find(prop => prop.name === name);
|
|
74
74
|
if (aria) {
|
|
75
75
|
if (aria.value === 'ID reference' && !idList.has(value)) {
|
|
@@ -10,10 +10,10 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
10
10
|
if (attr.ownerElement.elementType !== 'html') {
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
|
-
const ignoreList = Array.isArray(attr.rule.
|
|
14
|
-
? attr.rule.
|
|
15
|
-
: attr.rule.
|
|
16
|
-
? [attr.rule.
|
|
13
|
+
const ignoreList = Array.isArray(attr.rule.options.ignore)
|
|
14
|
+
? attr.rule.options.ignore
|
|
15
|
+
: attr.rule.options.ignore
|
|
16
|
+
? [attr.rule.options.ignore]
|
|
17
17
|
: [];
|
|
18
18
|
const name = attr.name;
|
|
19
19
|
for (const ignore of ignoreList) {
|