@markuplint/rules 3.13.0 → 4.0.0-alpha.2
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/lib/attr-check.js +14 -19
- package/lib/attr-duplication/index.js +3 -6
- package/lib/attr-value-quotes/index.js +5 -9
- package/lib/case-sensitive-attr-name/index.js +9 -13
- package/lib/case-sensitive-tag-name/index.js +2 -4
- package/lib/character-reference/index.js +6 -8
- package/lib/class-naming/index.js +9 -11
- package/lib/create-message.js +9 -16
- package/lib/debug.js +2 -6
- package/lib/deprecated-attr/index.js +6 -9
- package/lib/deprecated-element/index.js +3 -5
- package/lib/disallowed-element/index.js +2 -4
- package/lib/doctype/index.js +2 -4
- package/lib/end-tag/index.js +5 -8
- package/lib/helpers.d.ts +1 -1
- package/lib/helpers.js +17 -28
- package/lib/id-duplication/index.js +2 -4
- package/lib/index.d.ts +15 -15
- package/lib/index.js +63 -66
- package/lib/ineffective-attr/index.js +5 -7
- package/lib/invalid-attr/index.js +30 -33
- package/lib/label-has-control/index.js +2 -4
- package/lib/landmark-roles/index.js +3 -6
- package/lib/no-boolean-attr-value/index.js +6 -9
- package/lib/no-default-value/index.js +9 -12
- package/lib/no-empty-palpable-content/index.js +5 -7
- package/lib/no-hard-code-id/index.js +2 -4
- package/lib/no-refer-to-non-existent-id/index.js +26 -30
- package/lib/no-use-event-handler-attr/index.js +4 -6
- package/lib/permitted-contents/choice.d.ts +1 -1
- package/lib/permitted-contents/choice.js +13 -18
- package/lib/permitted-contents/complex-branch.d.ts +1 -1
- package/lib/permitted-contents/complex-branch.js +10 -14
- package/lib/permitted-contents/content-model.d.ts +1 -1
- package/lib/permitted-contents/content-model.js +5 -9
- package/lib/permitted-contents/count-pattern.d.ts +1 -1
- package/lib/permitted-contents/count-pattern.js +19 -24
- package/lib/permitted-contents/debug.browser.js +9 -12
- package/lib/permitted-contents/debug.d.ts +8 -1
- package/lib/permitted-contents/debug.js +12 -13
- package/lib/permitted-contents/index.d.ts +1 -1
- package/lib/permitted-contents/index.js +10 -13
- package/lib/permitted-contents/matches-selector.d.ts +1 -1
- package/lib/permitted-contents/matches-selector.js +12 -17
- package/lib/permitted-contents/order.d.ts +1 -1
- package/lib/permitted-contents/order.js +17 -22
- package/lib/permitted-contents/recursive-branch.d.ts +2 -2
- package/lib/permitted-contents/recursive-branch.js +9 -13
- package/lib/permitted-contents/represent-transparent-nodes.d.ts +1 -1
- package/lib/permitted-contents/represent-transparent-nodes.js +15 -20
- package/lib/permitted-contents/start.d.ts +1 -1
- package/lib/permitted-contents/start.js +13 -21
- package/lib/permitted-contents/transparent.d.ts +1 -1
- package/lib/permitted-contents/transparent.js +4 -9
- package/lib/permitted-contents/types.js +1 -2
- package/lib/permitted-contents/utils.d.ts +1 -1
- package/lib/permitted-contents/utils.js +55 -74
- package/lib/placeholder-label-option/index.js +5 -9
- package/lib/require-accessible-name/index.js +10 -13
- package/lib/require-datetime/index.d.ts +1 -1
- package/lib/require-datetime/index.js +6 -8
- package/lib/require-datetime/types.js +1 -2
- package/lib/require-datetime/utils.d.ts +1 -1
- package/lib/require-datetime/utils.js +4 -11
- package/lib/required-attr/index.js +8 -11
- package/lib/required-element/index.js +3 -6
- package/lib/required-h1/index.js +3 -6
- package/lib/use-list/index.js +6 -10
- package/lib/wai-aria/checkings/abstract-role.d.ts +1 -1
- package/lib/wai-aria/checkings/abstract-role.js +5 -10
- package/lib/wai-aria/checkings/default-value.d.ts +1 -1
- package/lib/wai-aria/checkings/default-value.js +2 -6
- package/lib/wai-aria/checkings/deprecated-props.d.ts +1 -1
- package/lib/wai-aria/checkings/deprecated-props.js +3 -8
- package/lib/wai-aria/checkings/disallowed-prop.d.ts +1 -1
- package/lib/wai-aria/checkings/disallowed-prop.js +7 -12
- package/lib/wai-aria/checkings/implicit-props.d.ts +1 -1
- package/lib/wai-aria/checkings/implicit-props.js +6 -11
- package/lib/wai-aria/checkings/implicit-role.d.ts +1 -1
- package/lib/wai-aria/checkings/implicit-role.js +4 -9
- package/lib/wai-aria/checkings/interaction-in-hidden.d.ts +1 -1
- package/lib/wai-aria/checkings/interaction-in-hidden.js +4 -8
- package/lib/wai-aria/checkings/no-global-prop.d.ts +1 -1
- package/lib/wai-aria/checkings/no-global-prop.js +2 -7
- package/lib/wai-aria/checkings/non-existent-role.d.ts +1 -1
- package/lib/wai-aria/checkings/non-existent-role.js +4 -9
- package/lib/wai-aria/checkings/permitted-roles.d.ts +1 -1
- package/lib/wai-aria/checkings/permitted-roles.js +4 -9
- package/lib/wai-aria/checkings/presentational-children.d.ts +1 -1
- package/lib/wai-aria/checkings/presentational-children.js +4 -9
- package/lib/wai-aria/checkings/required-owned-elements.d.ts +1 -1
- package/lib/wai-aria/checkings/required-owned-elements.js +4 -8
- package/lib/wai-aria/checkings/required-prop.d.ts +1 -1
- package/lib/wai-aria/checkings/required-prop.js +2 -7
- package/lib/wai-aria/checkings/value.d.ts +1 -1
- package/lib/wai-aria/checkings/value.js +4 -10
- package/lib/wai-aria/index.d.ts +1 -1
- package/lib/wai-aria/index.js +38 -40
- package/lib/wai-aria/types.js +1 -2
- package/package.json +17 -12
- package/test/attr-check.spec.js +0 -77
- package/test/attr-duplication/index.spec.js +0 -159
- package/test/attr-value-quotes/index.spec.js +0 -133
- package/test/case-sensitive-attr-name/index.spec.js +0 -65
- package/test/case-sensitive-tag-name/index.spec.js +0 -80
- package/test/character-reference/index.spec.js +0 -72
- package/test/class-naming/index.spec.js +0 -470
- package/test/create-message.spec.js +0 -497
- package/test/deprecated-attr/index.spec.js +0 -48
- package/test/deprecated-element/index.spec.js +0 -35
- package/test/disallowed-element/index.spec.js +0 -90
- package/test/doctype/index.spec.js +0 -50
- package/test/end-tag/index.spec.js +0 -162
- package/test/id-duplication/index.spec.js +0 -47
- package/test/ineffective-attr/index.spec.js +0 -31
- package/test/invalid-attr/index.spec.js +0 -1631
- package/test/label-has-control/index.spec.js +0 -29
- package/test/landmark-roles/index.spec.js +0 -187
- package/test/no-boolean-attr-value/index.spec.js +0 -41
- package/test/no-default-value/index.spec.js +0 -74
- package/test/no-empty-palpable-content/index.spec.js +0 -115
- package/test/no-hard-code-id/index.spec.js +0 -100
- package/test/no-refer-to-non-existent-id/index.spec.js +0 -254
- package/test/no-use-event-handler-attr/index.spec.js +0 -57
- package/test/permitted-contents/choice.spec.js +0 -174
- package/test/permitted-contents/count-pattern.spec.js +0 -308
- package/test/permitted-contents/index.spec.js +0 -1395
- package/test/permitted-contents/matches-selector.spec.js +0 -59
- package/test/permitted-contents/order.spec.js +0 -351
- package/test/permitted-contents/recursive-branch.spec.js +0 -41
- package/test/permitted-contents/represent-transparent-nodes.spec.js +0 -24
- package/test/permitted-contents/start.spec.js +0 -67
- package/test/placeholder-label-option/index.spec.js +0 -113
- package/test/require-accessible-name/index.spec.js +0 -444
- package/test/require-datetime/index.spec.js +0 -54
- package/test/require-datetime/utils.spec.js +0 -52
- package/test/required-attr/index.spec.js +0 -414
- package/test/required-element/index.spec.js +0 -188
- package/test/required-h1/index.spec.js +0 -69
- package/test/use-list/index.spec.js +0 -109
- package/test/wai-aria/checkings/value.spec.js +0 -33
- package/test/wai-aria/index.spec.js +0 -1203
package/lib/attr-check.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const types_1 = require("@markuplint/types");
|
|
6
|
-
const create_message_1 = require("./create-message");
|
|
7
|
-
const debug_1 = require("./debug");
|
|
1
|
+
import { toNonNullableArrayFromItemOrArray } from '@markuplint/shared';
|
|
2
|
+
import { check } from '@markuplint/types';
|
|
3
|
+
import { createMessageValueExpected } from './create-message.js';
|
|
4
|
+
import { log } from './debug.js';
|
|
8
5
|
/**
|
|
9
6
|
* Use in rules `invalid-attr` and `wai-aria`
|
|
10
7
|
*
|
|
@@ -13,7 +10,7 @@ const debug_1 = require("./debug");
|
|
|
13
10
|
* @param isCustomRule
|
|
14
11
|
* @param spec
|
|
15
12
|
*/
|
|
16
|
-
function attrCheck(t, name, value, isCustomRule, spec) {
|
|
13
|
+
export function attrCheck(t, name, value, isCustomRule, spec) {
|
|
17
14
|
if (!isCustomRule) {
|
|
18
15
|
if (/^data-.+$/.test(name)) {
|
|
19
16
|
// Ignore checking because "data-*" attribute is any type
|
|
@@ -32,7 +29,7 @@ function attrCheck(t, name, value, isCustomRule, spec) {
|
|
|
32
29
|
}
|
|
33
30
|
// Existence
|
|
34
31
|
if (!spec) {
|
|
35
|
-
|
|
32
|
+
log('The "%s" attribute DOES\'NT EXIST in the spec', name);
|
|
36
33
|
return {
|
|
37
34
|
invalidType: 'non-existent',
|
|
38
35
|
message: t('{0} is {1:c}', t('the "{0*}" {1}', name, 'attribute'), 'disallowed'),
|
|
@@ -40,7 +37,7 @@ function attrCheck(t, name, value, isCustomRule, spec) {
|
|
|
40
37
|
}
|
|
41
38
|
const nameCaseSensitive = /[A-Z]/.test(spec.name);
|
|
42
39
|
if (nameCaseSensitive && name !== spec.name) {
|
|
43
|
-
|
|
40
|
+
log('The "%s" attribute name is unmatched in case-sensitive', name);
|
|
44
41
|
return {
|
|
45
42
|
invalidType: 'non-existent',
|
|
46
43
|
message: t('{0} is {1:c}', t('the "{0*}" {1}', name, 'attribute'), 'disallowed') +
|
|
@@ -54,7 +51,7 @@ function attrCheck(t, name, value, isCustomRule, spec) {
|
|
|
54
51
|
message: t('{0} is {1:c}', t('the "{0*}" {1}', name, 'attribute'), 'disallowed'),
|
|
55
52
|
};
|
|
56
53
|
}
|
|
57
|
-
const types =
|
|
54
|
+
const types = toNonNullableArrayFromItemOrArray(spec.type);
|
|
58
55
|
const invalidList = types.map(type => {
|
|
59
56
|
const invalid = valueCheck(t, name, value, type);
|
|
60
57
|
if (invalid === false) {
|
|
@@ -78,17 +75,16 @@ function attrCheck(t, name, value, isCustomRule, spec) {
|
|
|
78
75
|
return false;
|
|
79
76
|
}
|
|
80
77
|
const invalid = invalidList.find(i => i);
|
|
81
|
-
return invalid
|
|
78
|
+
return invalid ?? false;
|
|
82
79
|
}
|
|
83
|
-
|
|
84
|
-
function valueCheck(t, name, value, type) {
|
|
80
|
+
export function valueCheck(t, name, value, type) {
|
|
85
81
|
if (type === 'Boolean') {
|
|
86
82
|
// Valid because an attribute is exist
|
|
87
83
|
return false;
|
|
88
84
|
}
|
|
89
|
-
const matches =
|
|
90
|
-
if (
|
|
91
|
-
|
|
85
|
+
const matches = check(value, type);
|
|
86
|
+
if (log.enabled) {
|
|
87
|
+
log(`Result ([${name}="${value}"]): %O`, { ...matches, type });
|
|
92
88
|
}
|
|
93
89
|
if (!matches.matched) {
|
|
94
90
|
const location = {
|
|
@@ -97,9 +93,8 @@ function valueCheck(t, name, value, type) {
|
|
|
97
93
|
col: matches.column - 1,
|
|
98
94
|
};
|
|
99
95
|
const base = t('the "{0*}" {1}', name, 'attribute');
|
|
100
|
-
const message =
|
|
96
|
+
const message = createMessageValueExpected(t, base, type, matches);
|
|
101
97
|
return [message, location];
|
|
102
98
|
}
|
|
103
99
|
return false;
|
|
104
100
|
}
|
|
105
|
-
exports.valueCheck = valueCheck;
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
-
exports.default = (0, ml_core_1.createRule)({
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
5
3
|
async verify({ document, report, t }) {
|
|
6
4
|
const message = t('{0} is {1:c}', t('the {0}', 'attribute name'), 'duplicated');
|
|
7
5
|
await document.walkOn('Element', node => {
|
|
8
|
-
var _a;
|
|
9
6
|
const attrNameStack = [];
|
|
10
7
|
for (const attr of node.getAttributeTokens()) {
|
|
11
8
|
if (attr.isDuplicatable) {
|
|
@@ -14,7 +11,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
14
11
|
const attrName = attr.name;
|
|
15
12
|
const name = node.elementType === 'html' ? attrName.toLowerCase() : attrName;
|
|
16
13
|
if (attrNameStack.includes(name)) {
|
|
17
|
-
const scope =
|
|
14
|
+
const scope = attr.nameNode ?? attr;
|
|
18
15
|
report({
|
|
19
16
|
scope: {
|
|
20
17
|
rule: node.rule,
|
|
@@ -1,21 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const ml_core_1 = require("@markuplint/ml-core");
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
4
2
|
const quoteList = {
|
|
5
3
|
double: '"',
|
|
6
4
|
single: "'",
|
|
7
5
|
};
|
|
8
|
-
|
|
6
|
+
export default createRule({
|
|
9
7
|
defaultSeverity: 'warning',
|
|
10
8
|
defaultValue: 'double',
|
|
11
9
|
async verify({ document, report, t }) {
|
|
12
10
|
await document.walkOn('Attr', attr => {
|
|
13
|
-
var _a, _b;
|
|
14
11
|
const message = t('{0} is must {1} on {2}', 'Attribute value', 'quote', `${attr.rule.value} quotation mark`);
|
|
15
|
-
if (attr.isDynamicValue || attr.isDirective || !attr.equal ||
|
|
12
|
+
if (attr.isDynamicValue || attr.isDirective || !attr.equal || attr.equal?.raw === '') {
|
|
16
13
|
return;
|
|
17
14
|
}
|
|
18
|
-
const quote =
|
|
15
|
+
const quote = attr.startQuote?.raw;
|
|
19
16
|
if (quote !== quoteList[attr.rule.value]) {
|
|
20
17
|
report({
|
|
21
18
|
scope: attr,
|
|
@@ -26,12 +23,11 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
26
23
|
},
|
|
27
24
|
async fix({ document }) {
|
|
28
25
|
await document.walkOn('Attr', attr => {
|
|
29
|
-
var _a;
|
|
30
26
|
const quote = quoteList[attr.rule.value];
|
|
31
27
|
if (quote && attr.startQuote && attr.startQuote.raw !== quote) {
|
|
32
28
|
attr.startQuote.fix(quote);
|
|
33
29
|
// TODO: attr.endQuote = new MLToken(quote);
|
|
34
|
-
|
|
30
|
+
attr.endQuote?.fix(quote);
|
|
35
31
|
}
|
|
36
32
|
});
|
|
37
33
|
},
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
-
exports.default = (0, ml_core_1.createRule)({
|
|
1
|
+
import { createRule, getAttrSpecs } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
5
3
|
defaultSeverity: 'warning',
|
|
6
4
|
defaultValue: 'lower',
|
|
7
5
|
async verify({ document, report, t }) {
|
|
8
6
|
await document.walkOn('Attr', attr => {
|
|
9
|
-
var _a, _b, _c, _d;
|
|
10
7
|
const el = attr.ownerElement;
|
|
11
8
|
if (el.isForeignElement || el.elementType !== 'html') {
|
|
12
9
|
return;
|
|
@@ -16,12 +13,12 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
16
13
|
const deny = value === 'lower' ? /[A-Z]/ : /[a-z]/;
|
|
17
14
|
const cases = value === 'lower' ? 'lower' : 'upper';
|
|
18
15
|
const message = t(`{0} ${ms} be {1}`, t('{0} of {1}', 'attribute names', 'HTML elements'), `${cases}case`);
|
|
19
|
-
const attrSpecs =
|
|
16
|
+
const attrSpecs = getAttrSpecs(el, document.specs);
|
|
20
17
|
/**
|
|
21
18
|
* Ignore when it has the potential name,
|
|
22
19
|
* it Interprets `tabIndex` to `tabindex` in JSX for example.
|
|
23
20
|
*/
|
|
24
|
-
if (
|
|
21
|
+
if (attr.nameNode?.raw !== attr.name) {
|
|
25
22
|
return;
|
|
26
23
|
}
|
|
27
24
|
const name = attr.name;
|
|
@@ -34,9 +31,9 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
34
31
|
if (deny.test(name)) {
|
|
35
32
|
report({
|
|
36
33
|
scope: attr,
|
|
37
|
-
line:
|
|
38
|
-
col:
|
|
39
|
-
raw:
|
|
34
|
+
line: attr.nameNode?.startLine,
|
|
35
|
+
col: attr.nameNode?.startCol,
|
|
36
|
+
raw: attr.nameNode?.raw,
|
|
40
37
|
message,
|
|
41
38
|
});
|
|
42
39
|
}
|
|
@@ -44,18 +41,17 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
44
41
|
},
|
|
45
42
|
async fix({ document }) {
|
|
46
43
|
await document.walkOn('Attr', attr => {
|
|
47
|
-
var _a;
|
|
48
44
|
const el = attr.ownerElement;
|
|
49
45
|
if (el.isForeignElement || el.elementType !== 'html') {
|
|
50
46
|
return;
|
|
51
47
|
}
|
|
52
|
-
const attrSpecs =
|
|
48
|
+
const attrSpecs = getAttrSpecs(el, document.specs);
|
|
53
49
|
const value = attr.rule.value;
|
|
54
50
|
/**
|
|
55
51
|
* Ignore when it has the potential name,
|
|
56
52
|
* it Interprets `tabIndex` to `tabindex` in JSX for example.
|
|
57
53
|
*/
|
|
58
|
-
if (
|
|
54
|
+
if (attr.nameNode?.raw !== attr.name) {
|
|
59
55
|
return;
|
|
60
56
|
}
|
|
61
57
|
const name = attr.name;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
-
exports.default = (0, ml_core_1.createRule)({
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
5
3
|
defaultSeverity: 'warning',
|
|
6
4
|
defaultValue: 'lower',
|
|
7
5
|
async verify({ document, report, t }) {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const ml_core_1 = require("@markuplint/ml-core");
|
|
1
|
+
import { createRule, getLocationFromChars } from '@markuplint/ml-core';
|
|
4
2
|
const defaultChars = ['"', '&', '<', '>'];
|
|
5
3
|
const ignoreParentElement = ['script', 'style'];
|
|
6
|
-
|
|
4
|
+
export default createRule({
|
|
7
5
|
async verify({ document, report, t }) {
|
|
8
6
|
const targetNodes = [];
|
|
9
7
|
await document.walkOn('Text', node => {
|
|
@@ -32,9 +30,9 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
32
30
|
const valueNode = attr.valueNode;
|
|
33
31
|
targetNodes.push({
|
|
34
32
|
scope: node,
|
|
35
|
-
line: valueNode
|
|
36
|
-
col: valueNode
|
|
37
|
-
raw: valueNode
|
|
33
|
+
line: valueNode?.startLine,
|
|
34
|
+
col: valueNode?.startCol,
|
|
35
|
+
raw: valueNode?.raw,
|
|
38
36
|
message,
|
|
39
37
|
});
|
|
40
38
|
}
|
|
@@ -44,7 +42,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
44
42
|
continue;
|
|
45
43
|
}
|
|
46
44
|
const escapedText = targetNode.raw.replace(/&(?:[a-z]+|#[0-9]+|#x[0-9a-f]+);/gi, $0 => '*'.repeat($0.length));
|
|
47
|
-
|
|
45
|
+
getLocationFromChars(defaultChars, escapedText, targetNode.line, targetNode.col).forEach(location => {
|
|
48
46
|
report({
|
|
49
47
|
scope: targetNode.scope,
|
|
50
48
|
message: targetNode.message,
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const helpers_1 = require("../helpers");
|
|
6
|
-
exports.default = (0, ml_core_1.createRule)({
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
2
|
+
import { toNoEmptyStringArrayFromStringOrArray } from '@markuplint/shared';
|
|
3
|
+
import { match } from '../helpers.js';
|
|
4
|
+
export default createRule({
|
|
7
5
|
defaultSeverity: 'warning',
|
|
8
6
|
defaultValue: null,
|
|
9
7
|
async verify({ document, report, t }) {
|
|
10
8
|
await document.walkOn('Element', el => {
|
|
11
|
-
const classPatterns =
|
|
9
|
+
const classPatterns = toNoEmptyStringArrayFromStringOrArray(el.rule.value).filter(className => className && typeof className === 'string');
|
|
12
10
|
const attrs = el.getAttributeToken('class');
|
|
13
11
|
for (const attr of attrs) {
|
|
14
12
|
if (attr.isDynamicValue) {
|
|
@@ -20,13 +18,13 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
20
18
|
.map(c => c.trim())
|
|
21
19
|
.filter(c => c);
|
|
22
20
|
for (const className of classList) {
|
|
23
|
-
if (!classPatterns.some(pattern =>
|
|
21
|
+
if (!classPatterns.some(pattern => match(className, pattern))) {
|
|
24
22
|
report({
|
|
25
23
|
scope: attr,
|
|
26
24
|
message: t('{0} is unmatched with the below patterns: {1}', t('the "{0*}" {1}', className, 'class name'), `"${classPatterns.join('", "')}"`),
|
|
27
|
-
line: classAttr
|
|
28
|
-
col: classAttr
|
|
29
|
-
raw: classAttr
|
|
25
|
+
line: classAttr?.startLine,
|
|
26
|
+
col: classAttr?.startCol,
|
|
27
|
+
raw: classAttr?.raw,
|
|
30
28
|
});
|
|
31
29
|
}
|
|
32
30
|
}
|
package/lib/create-message.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.__createMessageValueExpected = exports.createMessageValueExpected = void 0;
|
|
4
|
-
const types_1 = require("@markuplint/types");
|
|
5
|
-
function createMessageValueExpected(t, baseTarget, type, matches) {
|
|
1
|
+
import { isList, isKeyword, isEnum } from '@markuplint/types';
|
|
2
|
+
export function createMessageValueExpected(t, baseTarget, type, matches) {
|
|
6
3
|
let target = baseTarget;
|
|
7
4
|
let listDescriptionPart;
|
|
8
5
|
let tokenType;
|
|
9
|
-
if (
|
|
6
|
+
if (isList(type)) {
|
|
10
7
|
listDescriptionPart = t('{0} expects {1:c}', target, type.separator === 'space' ? 'space-separated list' : 'comma-separated list');
|
|
11
8
|
tokenType = type.token;
|
|
12
9
|
target = 'the content of the list';
|
|
@@ -20,9 +17,7 @@ function createMessageValueExpected(t, baseTarget, type, matches) {
|
|
|
20
17
|
.join(t('. '));
|
|
21
18
|
return message;
|
|
22
19
|
}
|
|
23
|
-
|
|
24
|
-
function __createMessageValueExpected(t, baseTarget, expected, matches) {
|
|
25
|
-
var _a;
|
|
20
|
+
export function __createMessageValueExpected(t, baseTarget, expected, matches) {
|
|
26
21
|
let target = baseTarget;
|
|
27
22
|
let reasonPart;
|
|
28
23
|
let expectPart;
|
|
@@ -53,7 +48,7 @@ function __createMessageValueExpected(t, baseTarget, expected, matches) {
|
|
|
53
48
|
break;
|
|
54
49
|
}
|
|
55
50
|
case 'extra-token': {
|
|
56
|
-
const token =
|
|
51
|
+
const token = matches.partName ?? 'token';
|
|
57
52
|
reasonPart = t('Found {0}', t('extra {0}', token)) + ' ' + t([matches.raw]);
|
|
58
53
|
if (matches.extra) {
|
|
59
54
|
const extra = expectValueToWord(t, matches.extra, 'Any');
|
|
@@ -202,21 +197,19 @@ function __createMessageValueExpected(t, baseTarget, expected, matches) {
|
|
|
202
197
|
}
|
|
203
198
|
return message;
|
|
204
199
|
}
|
|
205
|
-
exports.__createMessageValueExpected = __createMessageValueExpected;
|
|
206
200
|
function createExpectedObject(type, matches, t) {
|
|
207
|
-
var _a;
|
|
208
201
|
const expectedObject = [];
|
|
209
202
|
if (matches.expects && matches.expects.length > 0) {
|
|
210
203
|
expectedObject.push(...matches.expects.map(expect => {
|
|
211
204
|
return expectValueToWord(t, expect, type);
|
|
212
205
|
}));
|
|
213
206
|
}
|
|
214
|
-
else if (
|
|
207
|
+
else if (isKeyword(type)) {
|
|
215
208
|
if (type[0] === '<') {
|
|
216
209
|
expectedObject.push(t('the CSS Syntax "{0}"', type));
|
|
217
210
|
}
|
|
218
211
|
}
|
|
219
|
-
else if (
|
|
212
|
+
else if (isEnum(type)) {
|
|
220
213
|
expectedObject.push(...type.enum);
|
|
221
214
|
}
|
|
222
215
|
else {
|
|
@@ -226,7 +219,7 @@ function createExpectedObject(type, matches, t) {
|
|
|
226
219
|
? null
|
|
227
220
|
: 1 < expectedObject.length
|
|
228
221
|
? t('either {0}', t(expectedObject))
|
|
229
|
-
:
|
|
222
|
+
: expectedObject[0] ?? null;
|
|
230
223
|
return expects;
|
|
231
224
|
}
|
|
232
225
|
function expectValueToWord(t, expect, type) {
|
|
@@ -240,7 +233,7 @@ function expectValueToWord(t, expect, type) {
|
|
|
240
233
|
case 'regexp':
|
|
241
234
|
return t('{0} ({1})', 'regular expression', expect.value);
|
|
242
235
|
case 'syntax':
|
|
243
|
-
if (
|
|
236
|
+
if (isKeyword(type) && type[0] === '<') {
|
|
244
237
|
return t('the CSS Syntax "{0}"', expect.value);
|
|
245
238
|
}
|
|
246
239
|
return t('{0} syntax', expect.value);
|
package/lib/debug.js
CHANGED
|
@@ -1,6 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.log = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
6
|
-
exports.log = (0, debug_1.default)('ml-rules');
|
|
1
|
+
import debug from 'debug';
|
|
2
|
+
export const log = debug('ml-rules');
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
-
exports.default = (0, ml_core_1.createRule)({
|
|
1
|
+
import { createRule, getAttrSpecs } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
5
3
|
async verify({ document, report, t }) {
|
|
6
4
|
await document.walkOn('Attr', attr => {
|
|
7
|
-
|
|
8
|
-
const attrSpecs = (0, ml_core_1.getAttrSpecs)(attr.ownerElement, document.specs);
|
|
5
|
+
const attrSpecs = getAttrSpecs(attr.ownerElement, document.specs);
|
|
9
6
|
if (!attrSpecs) {
|
|
10
7
|
return;
|
|
11
8
|
}
|
|
@@ -18,9 +15,9 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
18
15
|
const message = t('{0} is {1:c}', t('the "{0*}" {1}', name, 'attribute'), attrSpec.obsolete ? 'obsolete' : 'deprecated');
|
|
19
16
|
report({
|
|
20
17
|
scope: attr,
|
|
21
|
-
line:
|
|
22
|
-
col:
|
|
23
|
-
raw:
|
|
18
|
+
line: attr.nameNode?.startLine,
|
|
19
|
+
col: attr.nameNode?.startCol,
|
|
20
|
+
raw: attr.nameNode?.raw,
|
|
24
21
|
message,
|
|
25
22
|
});
|
|
26
23
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
-
exports.default = (0, ml_core_1.createRule)({
|
|
1
|
+
import { createRule, getSpec } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
5
3
|
async verify({ document, report, t }) {
|
|
6
4
|
await document.walkOn('Element', el => {
|
|
7
5
|
if (!(el.namespaceURI === 'http://www.w3.org/1999/xhtml' ||
|
|
@@ -9,7 +7,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
9
7
|
el.elementType !== 'html') {
|
|
10
8
|
return;
|
|
11
9
|
}
|
|
12
|
-
const spec =
|
|
10
|
+
const spec = getSpec(el, document.specs.specs);
|
|
13
11
|
if (spec && (spec.obsolete != null || spec.deprecated || spec.nonStandard)) {
|
|
14
12
|
const message = t('{0} is {1:c}', t('the "{0*}" {1}', el.localName, 'element'), spec.deprecated ? 'deprecated' : spec.obsolete != null ? 'obsolete' : 'non-standard');
|
|
15
13
|
report({
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
-
exports.default = (0, ml_core_1.createRule)({
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
5
3
|
defaultValue: [],
|
|
6
4
|
async verify({ document, report, t }) {
|
|
7
5
|
for (const query of document.rule.value) {
|
package/lib/doctype/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
-
exports.default = (0, ml_core_1.createRule)({
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
5
3
|
defaultValue: 'always',
|
|
6
4
|
defaultOptions: {
|
|
7
5
|
denyObsoleteType: true,
|
package/lib/end-tag/index.js
CHANGED
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const ml_spec_1 = require("@markuplint/ml-spec");
|
|
5
|
-
exports.default = (0, ml_core_1.createRule)({
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
2
|
+
import { isVoidElement } from '@markuplint/ml-spec';
|
|
3
|
+
export default createRule({
|
|
6
4
|
defaultSeverity: 'warning',
|
|
7
5
|
async verify({ document, report, t }) {
|
|
8
6
|
if (document.endTag === 'never') {
|
|
9
7
|
return;
|
|
10
8
|
}
|
|
11
9
|
await document.walkOn('Element', el => {
|
|
12
|
-
var _a;
|
|
13
10
|
if (el.isOmitted) {
|
|
14
11
|
return;
|
|
15
12
|
}
|
|
16
|
-
if (
|
|
13
|
+
if (isVoidElement(el)) {
|
|
17
14
|
return;
|
|
18
15
|
}
|
|
19
16
|
if (el.closeTag != null) {
|
|
20
17
|
return;
|
|
21
18
|
}
|
|
22
|
-
if ((document.endTag === 'xml' || el.isForeignElement) &&
|
|
19
|
+
if ((document.endTag === 'xml' || el.isForeignElement) && el.selfClosingSolidus?.raw) {
|
|
23
20
|
return;
|
|
24
21
|
}
|
|
25
22
|
report({
|
package/lib/helpers.d.ts
CHANGED
package/lib/helpers.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var _Collection_items;
|
|
3
|
-
|
|
4
|
-
exports.deepCopy = exports.Collection = exports.getOwnedLabel = exports.accnameMayBeMutable = exports.toNormalizedValue = exports.isValidAttr = exports.rePCENChar = exports.match = exports.attrMatches = void 0;
|
|
5
|
-
const tslib_1 = require("tslib");
|
|
2
|
+
import { __classPrivateFieldGet } from "tslib";
|
|
6
3
|
// @ts-ignore
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
function attrMatches(
|
|
4
|
+
import structuredClone from '@ungap/structured-clone';
|
|
5
|
+
import { attrCheck } from './attr-check.js';
|
|
6
|
+
export function attrMatches(
|
|
10
7
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
11
8
|
node, condition) {
|
|
12
9
|
if (condition == null) {
|
|
@@ -15,8 +12,7 @@ node, condition) {
|
|
|
15
12
|
const condSelector = typeof condition === 'string' ? condition : condition.join(',');
|
|
16
13
|
return node.matches(condSelector);
|
|
17
14
|
}
|
|
18
|
-
|
|
19
|
-
function match(needle, pattern) {
|
|
15
|
+
export function match(needle, pattern) {
|
|
20
16
|
const matches = pattern.match(/^\/(.*)\/(i|g|m)*$/);
|
|
21
17
|
if (matches && matches[1]) {
|
|
22
18
|
const re = matches[1];
|
|
@@ -25,7 +21,6 @@ function match(needle, pattern) {
|
|
|
25
21
|
}
|
|
26
22
|
return needle === pattern;
|
|
27
23
|
}
|
|
28
|
-
exports.match = match;
|
|
29
24
|
/**
|
|
30
25
|
* PotentialCustomElementName
|
|
31
26
|
*
|
|
@@ -41,7 +36,7 @@ exports.match = match;
|
|
|
41
36
|
* ASCII-case-insensitively.
|
|
42
37
|
* Originally, it is not possible to define a name including ASCII upper alphas in the custom element, but it is not treated as illegal by the HTML parser.
|
|
43
38
|
*/
|
|
44
|
-
|
|
39
|
+
export const rePCENChar = [
|
|
45
40
|
'\\-',
|
|
46
41
|
'\\.',
|
|
47
42
|
'[0-9]',
|
|
@@ -61,7 +56,7 @@ exports.rePCENChar = [
|
|
|
61
56
|
'[\uFDF0-\uFFFD]',
|
|
62
57
|
'[\uD800-\uDBFF][\uDC00-\uDFFF]',
|
|
63
58
|
].join('|');
|
|
64
|
-
function isValidAttr(t, name, value, isDynamicValue,
|
|
59
|
+
export function isValidAttr(t, name, value, isDynamicValue,
|
|
65
60
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
66
61
|
node, attrSpecs,
|
|
67
62
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
@@ -69,7 +64,7 @@ log) {
|
|
|
69
64
|
let invalid = false;
|
|
70
65
|
const spec = attrSpecs.find(s => s.name.toLowerCase() === name.toLowerCase());
|
|
71
66
|
log && log('Spec of the %s attr: %o', name, spec);
|
|
72
|
-
invalid =
|
|
67
|
+
invalid = attrCheck(t, name, value, false, spec);
|
|
73
68
|
if (invalid === false &&
|
|
74
69
|
spec &&
|
|
75
70
|
spec.condition != null &&
|
|
@@ -85,8 +80,7 @@ log) {
|
|
|
85
80
|
}
|
|
86
81
|
return invalid;
|
|
87
82
|
}
|
|
88
|
-
|
|
89
|
-
function toNormalizedValue(value, spec) {
|
|
83
|
+
export function toNormalizedValue(value, spec) {
|
|
90
84
|
let normalized = value;
|
|
91
85
|
if (!spec.caseSensitive) {
|
|
92
86
|
normalized = normalized.toLowerCase();
|
|
@@ -114,8 +108,7 @@ function toNormalizedValue(value, spec) {
|
|
|
114
108
|
}
|
|
115
109
|
return normalized;
|
|
116
110
|
}
|
|
117
|
-
|
|
118
|
-
function accnameMayBeMutable(
|
|
111
|
+
export function accnameMayBeMutable(
|
|
119
112
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
120
113
|
el,
|
|
121
114
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
@@ -129,9 +122,8 @@ document) {
|
|
|
129
122
|
}
|
|
130
123
|
return false;
|
|
131
124
|
}
|
|
132
|
-
exports.accnameMayBeMutable = accnameMayBeMutable;
|
|
133
125
|
const labelable = ['button', 'input:not([type=hidden])', 'meter', 'output', 'progress', 'select', 'textarea'];
|
|
134
|
-
function getOwnedLabel(
|
|
126
|
+
export function getOwnedLabel(
|
|
135
127
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
136
128
|
el,
|
|
137
129
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
@@ -148,29 +140,26 @@ document) {
|
|
|
148
140
|
}
|
|
149
141
|
return ownedLabel;
|
|
150
142
|
}
|
|
151
|
-
|
|
152
|
-
class Collection {
|
|
143
|
+
export class Collection {
|
|
153
144
|
constructor(...items) {
|
|
154
145
|
_Collection_items.set(this, new Set());
|
|
155
146
|
this.add(...items);
|
|
156
147
|
}
|
|
157
148
|
[(_Collection_items = new WeakMap(), Symbol.iterator)]() {
|
|
158
|
-
return
|
|
149
|
+
return __classPrivateFieldGet(this, _Collection_items, "f").values();
|
|
159
150
|
}
|
|
160
151
|
add(...items) {
|
|
161
152
|
for (const item of items) {
|
|
162
153
|
if (item == null) {
|
|
163
154
|
continue;
|
|
164
155
|
}
|
|
165
|
-
|
|
156
|
+
__classPrivateFieldGet(this, _Collection_items, "f").add(item);
|
|
166
157
|
}
|
|
167
158
|
}
|
|
168
159
|
toArray() {
|
|
169
|
-
return Object.freeze(Array.from(
|
|
160
|
+
return Object.freeze(Array.from(__classPrivateFieldGet(this, _Collection_items, "f")));
|
|
170
161
|
}
|
|
171
162
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
return (0, structured_clone_1.default)(value);
|
|
163
|
+
export function deepCopy(value) {
|
|
164
|
+
return structuredClone(value);
|
|
175
165
|
}
|
|
176
|
-
exports.deepCopy = deepCopy;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
-
exports.default = (0, ml_core_1.createRule)({
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
5
3
|
async verify({ document, report, t }) {
|
|
6
4
|
const message = t('{0} is {1:c}', t('{0} of {1}', t('the {0}', 'value'), t('the "{0*}" {1}', 'id', 'attribute')), 'duplicated');
|
|
7
5
|
const idStack = [];
|