@markuplint/rules 3.15.0 → 4.0.0-alpha.10
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/.eslintrc +5 -0
- package/LICENSE +1 -1
- package/lib/attr-check.d.ts +8 -19
- package/lib/attr-check.js +16 -21
- package/lib/attr-duplication/index.d.ts +1 -3
- package/lib/attr-duplication/index.js +6 -6
- package/lib/attr-value-quotes/index.d.ts +2 -2
- package/lib/attr-value-quotes/index.js +8 -10
- package/lib/case-sensitive-attr-name/index.d.ts +1 -1
- package/lib/case-sensitive-attr-name/index.js +12 -13
- package/lib/case-sensitive-tag-name/index.d.ts +1 -1
- package/lib/case-sensitive-tag-name/index.js +5 -4
- package/lib/character-reference/index.d.ts +1 -1
- package/lib/character-reference/index.js +13 -12
- package/lib/class-naming/index.d.ts +1 -1
- package/lib/class-naming/index.js +14 -13
- package/lib/create-message.d.ts +2 -12
- package/lib/create-message.js +26 -26
- package/lib/debug.js +2 -6
- package/lib/deprecated-attr/index.d.ts +1 -3
- package/lib/deprecated-attr/index.js +9 -9
- package/lib/deprecated-element/index.d.ts +1 -3
- package/lib/deprecated-element/index.js +7 -6
- package/lib/disallowed-element/index.d.ts +1 -1
- package/lib/disallowed-element/index.js +9 -8
- package/lib/doctype/index.d.ts +2 -2
- package/lib/doctype/index.js +5 -4
- package/lib/end-tag/index.d.ts +1 -1
- package/lib/end-tag/index.js +8 -8
- package/lib/helpers.d.ts +17 -35
- package/lib/helpers.js +25 -32
- package/lib/id-duplication/index.d.ts +1 -3
- package/lib/id-duplication/index.js +5 -4
- package/lib/index.d.ts +21 -17
- package/lib/index.js +63 -66
- package/lib/ineffective-attr/index.d.ts +1 -3
- package/lib/ineffective-attr/index.js +8 -7
- package/lib/invalid-attr/index.d.ts +31 -38
- package/lib/invalid-attr/index.js +33 -33
- package/lib/label-has-control/index.d.ts +1 -3
- package/lib/label-has-control/index.js +5 -4
- package/lib/landmark-roles/index.d.ts +3 -3
- package/lib/landmark-roles/index.js +16 -18
- package/lib/no-boolean-attr-value/index.d.ts +1 -3
- package/lib/no-boolean-attr-value/index.js +9 -9
- package/lib/no-default-value/index.d.ts +1 -3
- package/lib/no-default-value/index.js +12 -12
- package/lib/no-empty-palpable-content/index.d.ts +3 -3
- package/lib/no-empty-palpable-content/index.js +9 -8
- package/lib/no-hard-code-id/index.d.ts +1 -3
- package/lib/no-hard-code-id/index.js +5 -4
- package/lib/no-refer-to-non-existent-id/index.d.ts +1 -1
- package/lib/no-refer-to-non-existent-id/index.js +37 -38
- package/lib/no-use-event-handler-attr/index.d.ts +2 -2
- package/lib/no-use-event-handler-attr/index.js +7 -6
- package/lib/permitted-contents/choice.d.ts +2 -8
- package/lib/permitted-contents/choice.js +14 -19
- package/lib/permitted-contents/complex-branch.d.ts +2 -8
- 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 +10 -11
- package/lib/permitted-contents/count-pattern.d.ts +3 -18
- package/lib/permitted-contents/count-pattern.js +19 -24
- package/lib/permitted-contents/debug.browser.d.ts +16 -16
- package/lib/permitted-contents/debug.browser.js +9 -12
- package/lib/permitted-contents/debug.d.ts +10 -3
- package/lib/permitted-contents/debug.js +12 -13
- package/lib/permitted-contents/index.d.ts +2 -2
- package/lib/permitted-contents/index.js +13 -13
- package/lib/permitted-contents/matches-selector.d.ts +2 -7
- package/lib/permitted-contents/matches-selector.js +13 -18
- package/lib/permitted-contents/order.d.ts +2 -8
- package/lib/permitted-contents/order.js +19 -24
- package/lib/permitted-contents/recursive-branch.d.ts +3 -9
- package/lib/permitted-contents/recursive-branch.js +9 -13
- package/lib/permitted-contents/represent-transparent-nodes.d.ts +4 -8
- package/lib/permitted-contents/represent-transparent-nodes.js +15 -20
- package/lib/permitted-contents/start.d.ts +2 -7
- package/lib/permitted-contents/start.js +13 -21
- package/lib/permitted-contents/transparent.d.ts +1 -1
- package/lib/permitted-contents/transparent.js +6 -11
- package/lib/permitted-contents/types.d.ts +29 -29
- package/lib/permitted-contents/types.js +1 -2
- package/lib/permitted-contents/utils.d.ts +42 -79
- package/lib/permitted-contents/utils.js +72 -82
- package/lib/placeholder-label-option/index.d.ts +1 -1
- package/lib/placeholder-label-option/index.js +12 -13
- package/lib/require-accessible-name/index.d.ts +2 -2
- package/lib/require-accessible-name/index.js +12 -15
- package/lib/require-datetime/index.d.ts +3 -3
- package/lib/require-datetime/index.js +14 -13
- package/lib/require-datetime/types.d.ts +2 -2
- package/lib/require-datetime/types.js +1 -2
- package/lib/require-datetime/utils.d.ts +1 -1
- package/lib/require-datetime/utils.js +5 -12
- package/lib/required-attr/index.d.ts +3 -3
- package/lib/required-attr/index.js +11 -11
- package/lib/required-element/index.d.ts +2 -2
- package/lib/required-element/index.js +7 -7
- package/lib/required-h1/index.d.ts +3 -3
- package/lib/required-h1/index.js +6 -6
- package/lib/use-list/index.d.ts +6 -2
- package/lib/use-list/index.js +27 -11
- 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 +4 -8
- package/lib/wai-aria/checkings/default-value.js +2 -6
- package/lib/wai-aria/checkings/deprecated-props.d.ts +5 -9
- package/lib/wai-aria/checkings/deprecated-props.js +3 -8
- package/lib/wai-aria/checkings/disallowed-prop.d.ts +5 -9
- package/lib/wai-aria/checkings/disallowed-prop.js +7 -12
- package/lib/wai-aria/checkings/implicit-props.d.ts +5 -9
- package/lib/wai-aria/checkings/implicit-props.js +12 -17
- 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 +4 -8
- 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 +5 -10
- package/lib/wai-aria/checkings/required-owned-elements.d.ts +4 -8
- package/lib/wai-aria/checkings/required-owned-elements.js +7 -11
- package/lib/wai-aria/checkings/required-prop.d.ts +7 -13
- package/lib/wai-aria/checkings/required-prop.js +2 -7
- package/lib/wai-aria/checkings/value.d.ts +7 -16
- package/lib/wai-aria/checkings/value.js +7 -13
- package/lib/wai-aria/index.d.ts +2 -2
- package/lib/wai-aria/index.js +41 -40
- package/lib/wai-aria/types.d.ts +10 -10
- package/lib/wai-aria/types.js +1 -2
- package/package.json +17 -13
- 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/.eslintrc
ADDED
package/LICENSE
CHANGED
package/lib/attr-check.d.ts
CHANGED
|
@@ -2,14 +2,14 @@ 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
4
|
type Invalid = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
invalidType: 'non-existent' | 'invalid-value' | 'disallowed-attr';
|
|
6
|
+
message: string;
|
|
7
|
+
loc?: Loc;
|
|
8
8
|
};
|
|
9
9
|
type Loc = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
raw: string;
|
|
11
|
+
line: number;
|
|
12
|
+
col: number;
|
|
13
13
|
};
|
|
14
14
|
/**
|
|
15
15
|
* Use in rules `invalid-attr` and `wai-aria`
|
|
@@ -19,17 +19,6 @@ type Loc = {
|
|
|
19
19
|
* @param isCustomRule
|
|
20
20
|
* @param spec
|
|
21
21
|
*/
|
|
22
|
-
export declare function attrCheck(
|
|
23
|
-
|
|
24
|
-
name: string,
|
|
25
|
-
value: string,
|
|
26
|
-
isCustomRule: boolean,
|
|
27
|
-
spec?: AttrSpec,
|
|
28
|
-
): Invalid | false;
|
|
29
|
-
export declare function valueCheck(
|
|
30
|
-
t: Translator,
|
|
31
|
-
name: string,
|
|
32
|
-
value: string,
|
|
33
|
-
type: ReadonlyDeep<AttributeType>,
|
|
34
|
-
): [string, Loc] | false;
|
|
22
|
+
export declare function attrCheck(t: Translator, name: string, value: string, isCustomRule: boolean, spec?: AttrSpec): Invalid | false;
|
|
23
|
+
export declare function valueCheck(t: Translator, name: string, value: string, type: ReadonlyDeep<AttributeType>): [string, Loc] | false;
|
|
35
24
|
export {};
|
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) {
|
|
@@ -74,21 +71,20 @@ function attrCheck(t, name, value, isCustomRule, spec) {
|
|
|
74
71
|
};
|
|
75
72
|
}
|
|
76
73
|
});
|
|
77
|
-
if (invalidList.
|
|
74
|
+
if (invalidList.includes(false)) {
|
|
78
75
|
return false;
|
|
79
76
|
}
|
|
80
|
-
const invalid = invalidList.find(
|
|
81
|
-
return invalid
|
|
77
|
+
const invalid = invalidList.find(Boolean);
|
|
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,4 +1,2 @@
|
|
|
1
|
-
declare const _default: Readonly<
|
|
2
|
-
import('@markuplint/ml-core').RuleSeed<import('@markuplint/ml-core').RuleConfigValue, undefined>
|
|
3
|
-
>;
|
|
1
|
+
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
|
|
4
2
|
export default _default;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
3
|
+
meta: {
|
|
4
|
+
category: 'validation',
|
|
5
|
+
},
|
|
5
6
|
async verify({ document, report, t }) {
|
|
6
7
|
const message = t('{0} is {1:c}', t('the {0}', 'attribute name'), 'duplicated');
|
|
7
8
|
await document.walkOn('Element', node => {
|
|
8
|
-
var _a;
|
|
9
9
|
const attrNameStack = [];
|
|
10
10
|
for (const attr of node.getAttributeTokens()) {
|
|
11
11
|
if (attr.isDuplicatable) {
|
|
@@ -14,7 +14,7 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
14
14
|
const attrName = attr.name;
|
|
15
15
|
const name = node.elementType === 'html' ? attrName.toLowerCase() : attrName;
|
|
16
16
|
if (attrNameStack.includes(name)) {
|
|
17
|
-
const scope =
|
|
17
|
+
const scope = attr.nameNode ?? attr;
|
|
18
18
|
report({
|
|
19
19
|
scope: {
|
|
20
20
|
rule: node.rule,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type Type = 'double' | 'single';
|
|
2
2
|
export type Quote = '"' | "'";
|
|
3
3
|
export type QuoteMap = {
|
|
4
|
-
|
|
4
|
+
[P in Type]: Quote;
|
|
5
5
|
};
|
|
6
|
-
declare const _default: Readonly<import(
|
|
6
|
+
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<Type, undefined>>;
|
|
7
7
|
export default _default;
|
|
@@ -1,21 +1,21 @@
|
|
|
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({
|
|
7
|
+
meta: {
|
|
8
|
+
category: 'style',
|
|
9
|
+
},
|
|
9
10
|
defaultSeverity: 'warning',
|
|
10
11
|
defaultValue: 'double',
|
|
11
12
|
async verify({ document, report, t }) {
|
|
12
13
|
await document.walkOn('Attr', attr => {
|
|
13
|
-
var _a, _b;
|
|
14
14
|
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 ||
|
|
15
|
+
if (attr.isDynamicValue || attr.isDirective || !attr.equal || attr.equal?.raw === '') {
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
|
-
const quote =
|
|
18
|
+
const quote = attr.startQuote?.raw;
|
|
19
19
|
if (quote !== quoteList[attr.rule.value]) {
|
|
20
20
|
report({
|
|
21
21
|
scope: attr,
|
|
@@ -26,12 +26,10 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
26
26
|
},
|
|
27
27
|
async fix({ document }) {
|
|
28
28
|
await document.walkOn('Attr', attr => {
|
|
29
|
-
var _a;
|
|
30
29
|
const quote = quoteList[attr.rule.value];
|
|
31
30
|
if (quote && attr.startQuote && attr.startQuote.raw !== quote) {
|
|
32
31
|
attr.startQuote.fix(quote);
|
|
33
|
-
|
|
34
|
-
(_a = attr.endQuote) === null || _a === void 0 ? void 0 : _a.fix(quote);
|
|
32
|
+
attr.endQuote?.fix(quote);
|
|
35
33
|
}
|
|
36
34
|
});
|
|
37
35
|
},
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { createRule, getAttrSpecs } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
3
|
+
meta: {
|
|
4
|
+
category: 'style',
|
|
5
|
+
},
|
|
5
6
|
defaultSeverity: 'warning',
|
|
6
7
|
defaultValue: 'lower',
|
|
7
8
|
async verify({ document, report, t }) {
|
|
8
9
|
await document.walkOn('Attr', attr => {
|
|
9
|
-
var _a, _b, _c, _d;
|
|
10
10
|
const el = attr.ownerElement;
|
|
11
11
|
if (el.isForeignElement || el.elementType !== 'html') {
|
|
12
12
|
return;
|
|
@@ -16,12 +16,12 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
16
16
|
const deny = value === 'lower' ? /[A-Z]/ : /[a-z]/;
|
|
17
17
|
const cases = value === 'lower' ? 'lower' : 'upper';
|
|
18
18
|
const message = t(`{0} ${ms} be {1}`, t('{0} of {1}', 'attribute names', 'HTML elements'), `${cases}case`);
|
|
19
|
-
const attrSpecs =
|
|
19
|
+
const attrSpecs = getAttrSpecs(el, document.specs);
|
|
20
20
|
/**
|
|
21
21
|
* Ignore when it has the potential name,
|
|
22
22
|
* it Interprets `tabIndex` to `tabindex` in JSX for example.
|
|
23
23
|
*/
|
|
24
|
-
if (
|
|
24
|
+
if (attr.nameNode?.raw !== attr.name) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
const name = attr.name;
|
|
@@ -34,9 +34,9 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
34
34
|
if (deny.test(name)) {
|
|
35
35
|
report({
|
|
36
36
|
scope: attr,
|
|
37
|
-
line:
|
|
38
|
-
col:
|
|
39
|
-
raw:
|
|
37
|
+
line: attr.nameNode?.startLine,
|
|
38
|
+
col: attr.nameNode?.startCol,
|
|
39
|
+
raw: attr.nameNode?.raw,
|
|
40
40
|
message,
|
|
41
41
|
});
|
|
42
42
|
}
|
|
@@ -44,18 +44,17 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
44
44
|
},
|
|
45
45
|
async fix({ document }) {
|
|
46
46
|
await document.walkOn('Attr', attr => {
|
|
47
|
-
var _a;
|
|
48
47
|
const el = attr.ownerElement;
|
|
49
48
|
if (el.isForeignElement || el.elementType !== 'html') {
|
|
50
49
|
return;
|
|
51
50
|
}
|
|
52
|
-
const attrSpecs =
|
|
51
|
+
const attrSpecs = getAttrSpecs(el, document.specs);
|
|
53
52
|
const value = attr.rule.value;
|
|
54
53
|
/**
|
|
55
54
|
* Ignore when it has the potential name,
|
|
56
55
|
* it Interprets `tabIndex` to `tabindex` in JSX for example.
|
|
57
56
|
*/
|
|
58
|
-
if (
|
|
57
|
+
if (attr.nameNode?.raw !== attr.name) {
|
|
59
58
|
return;
|
|
60
59
|
}
|
|
61
60
|
const name = attr.name;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
3
|
+
meta: {
|
|
4
|
+
category: 'style',
|
|
5
|
+
},
|
|
5
6
|
defaultSeverity: 'warning',
|
|
6
7
|
defaultValue: 'lower',
|
|
7
8
|
async verify({ document, report, t }) {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { RuleConfigValue } from '@markuplint/ml-config';
|
|
2
|
-
declare const _default: Readonly<import(
|
|
2
|
+
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<RuleConfigValue, undefined>>;
|
|
3
3
|
export default _default;
|
|
@@ -1,13 +1,14 @@
|
|
|
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
|
-
const ignoreParentElement = ['script', 'style'];
|
|
6
|
-
|
|
3
|
+
const ignoreParentElement = new Set(['script', 'style']);
|
|
4
|
+
export default createRule({
|
|
5
|
+
meta: {
|
|
6
|
+
category: 'style',
|
|
7
|
+
},
|
|
7
8
|
async verify({ document, report, t }) {
|
|
8
9
|
const targetNodes = [];
|
|
9
10
|
await document.walkOn('Text', node => {
|
|
10
|
-
if (node.parentNode && ignoreParentElement.
|
|
11
|
+
if (node.parentNode && ignoreParentElement.has(node.parentNode.nodeName.toLowerCase())) {
|
|
11
12
|
return;
|
|
12
13
|
}
|
|
13
14
|
const severity = node.rule.severity;
|
|
@@ -32,9 +33,9 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
32
33
|
const valueNode = attr.valueNode;
|
|
33
34
|
targetNodes.push({
|
|
34
35
|
scope: node,
|
|
35
|
-
line: valueNode
|
|
36
|
-
col: valueNode
|
|
37
|
-
raw: valueNode
|
|
36
|
+
line: valueNode?.startLine,
|
|
37
|
+
col: valueNode?.startCol,
|
|
38
|
+
raw: valueNode?.raw,
|
|
38
39
|
message,
|
|
39
40
|
});
|
|
40
41
|
}
|
|
@@ -43,14 +44,14 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
43
44
|
if (!('scope' in targetNode && 'line' in targetNode && targetNode.line != null)) {
|
|
44
45
|
continue;
|
|
45
46
|
}
|
|
46
|
-
const escapedText = targetNode.raw.
|
|
47
|
-
(
|
|
47
|
+
const escapedText = targetNode.raw.replaceAll(/&(?:[a-z]+|#\d+|#x[\da-f]+);/gi, $0 => '*'.repeat($0.length));
|
|
48
|
+
for (const location of getLocationFromChars(defaultChars, escapedText, targetNode.line, targetNode.col)) {
|
|
48
49
|
report({
|
|
49
50
|
scope: targetNode.scope,
|
|
50
51
|
message: targetNode.message,
|
|
51
52
|
...location,
|
|
52
53
|
});
|
|
53
|
-
}
|
|
54
|
+
}
|
|
54
55
|
}
|
|
55
56
|
},
|
|
56
57
|
});
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { createRule } from '@markuplint/ml-core';
|
|
2
|
+
import { toNoEmptyStringArrayFromStringOrArray } from '@markuplint/shared';
|
|
3
|
+
import { match } from '../helpers.js';
|
|
4
|
+
export default createRule({
|
|
5
|
+
meta: {
|
|
6
|
+
category: 'naming-convention',
|
|
7
|
+
},
|
|
7
8
|
defaultSeverity: 'warning',
|
|
8
9
|
defaultValue: null,
|
|
9
10
|
async verify({ document, report, t }) {
|
|
10
11
|
await document.walkOn('Element', el => {
|
|
11
|
-
const classPatterns =
|
|
12
|
+
const classPatterns = toNoEmptyStringArrayFromStringOrArray(el.rule.value).filter(className => className && typeof className === 'string');
|
|
12
13
|
const attrs = el.getAttributeToken('class');
|
|
13
14
|
for (const attr of attrs) {
|
|
14
15
|
if (attr.isDynamicValue) {
|
|
@@ -16,17 +17,17 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
16
17
|
}
|
|
17
18
|
const classAttr = attr.valueNode;
|
|
18
19
|
const classList = attr.value
|
|
19
|
-
.split(/\s+/
|
|
20
|
+
.split(/\s+/)
|
|
20
21
|
.map(c => c.trim())
|
|
21
|
-
.filter(
|
|
22
|
+
.filter(Boolean);
|
|
22
23
|
for (const className of classList) {
|
|
23
|
-
if (!classPatterns.some(pattern =>
|
|
24
|
+
if (!classPatterns.some(pattern => match(className, pattern))) {
|
|
24
25
|
report({
|
|
25
26
|
scope: attr,
|
|
26
27
|
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
|
|
28
|
+
line: classAttr?.startLine,
|
|
29
|
+
col: classAttr?.startCol,
|
|
30
|
+
raw: classAttr?.raw,
|
|
30
31
|
});
|
|
31
32
|
}
|
|
32
33
|
}
|
package/lib/create-message.d.ts
CHANGED
|
@@ -2,15 +2,5 @@ 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
|
-
export declare function createMessageValueExpected(
|
|
6
|
-
|
|
7
|
-
baseTarget: string,
|
|
8
|
-
type: ReadonlyDeep<AttributeType>,
|
|
9
|
-
matches: UnmatchedResult,
|
|
10
|
-
): string;
|
|
11
|
-
export declare function __createMessageValueExpected(
|
|
12
|
-
t: Translator,
|
|
13
|
-
baseTarget: string,
|
|
14
|
-
expected: string | null,
|
|
15
|
-
matches: Pick<UnmatchedResult, 'partName' | 'reason' | 'raw' | 'candidate' | 'ref' | 'extra' | 'fallbackTo'>,
|
|
16
|
-
): string;
|
|
5
|
+
export declare function createMessageValueExpected(t: Translator, baseTarget: string, type: ReadonlyDeep<AttributeType>, matches: UnmatchedResult): string;
|
|
6
|
+
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,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';
|
|
@@ -16,13 +13,11 @@ function createMessageValueExpected(t, baseTarget, type, matches) {
|
|
|
16
13
|
}
|
|
17
14
|
const expected = createExpectedObject(tokenType, matches, t);
|
|
18
15
|
const message = [listDescriptionPart, __createMessageValueExpected(t, target, expected, matches)]
|
|
19
|
-
.filter(
|
|
16
|
+
.filter(Boolean)
|
|
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');
|
|
@@ -141,11 +136,11 @@ function __createMessageValueExpected(t, baseTarget, expected, matches) {
|
|
|
141
136
|
if (lte != null && gte === lte) {
|
|
142
137
|
expectedDigits = t('{0} digits', gte);
|
|
143
138
|
}
|
|
144
|
-
else if (lte
|
|
145
|
-
expectedDigits = t('{0}
|
|
139
|
+
else if (lte == null) {
|
|
140
|
+
expectedDigits = t('{0} or more digits', gte);
|
|
146
141
|
}
|
|
147
142
|
else {
|
|
148
|
-
expectedDigits = t('{0}
|
|
143
|
+
expectedDigits = t('{0} to {1} digits', gte, lte);
|
|
149
144
|
}
|
|
150
145
|
if (!expected) {
|
|
151
146
|
expected = expectedDigits;
|
|
@@ -196,27 +191,27 @@ function __createMessageValueExpected(t, baseTarget, expected, matches) {
|
|
|
196
191
|
if (matches.fallbackTo) {
|
|
197
192
|
fallbackToPart = t('The user agent will automatically use "{0*}" instead', matches.fallbackTo);
|
|
198
193
|
}
|
|
199
|
-
let message = [reasonPart, unnecessaryPart, expectPart, candidatePart, fallbackToPart]
|
|
194
|
+
let message = [reasonPart, unnecessaryPart, expectPart, candidatePart, fallbackToPart]
|
|
195
|
+
.filter(Boolean)
|
|
196
|
+
.join(t('. '));
|
|
200
197
|
if (matches.ref) {
|
|
201
198
|
message += ` (${matches.ref})`;
|
|
202
199
|
}
|
|
203
200
|
return message;
|
|
204
201
|
}
|
|
205
|
-
exports.__createMessageValueExpected = __createMessageValueExpected;
|
|
206
202
|
function createExpectedObject(type, matches, t) {
|
|
207
|
-
var _a;
|
|
208
203
|
const expectedObject = [];
|
|
209
204
|
if (matches.expects && matches.expects.length > 0) {
|
|
210
205
|
expectedObject.push(...matches.expects.map(expect => {
|
|
211
206
|
return expectValueToWord(t, expect, type);
|
|
212
207
|
}));
|
|
213
208
|
}
|
|
214
|
-
else if (
|
|
209
|
+
else if (isKeyword(type)) {
|
|
215
210
|
if (type[0] === '<') {
|
|
216
211
|
expectedObject.push(t('the CSS Syntax "{0}"', type));
|
|
217
212
|
}
|
|
218
213
|
}
|
|
219
|
-
else if (
|
|
214
|
+
else if (isEnum(type)) {
|
|
220
215
|
expectedObject.push(...type.enum);
|
|
221
216
|
}
|
|
222
217
|
else {
|
|
@@ -226,24 +221,29 @@ function createExpectedObject(type, matches, t) {
|
|
|
226
221
|
? null
|
|
227
222
|
: 1 < expectedObject.length
|
|
228
223
|
? t('either {0}', t(expectedObject))
|
|
229
|
-
:
|
|
224
|
+
: expectedObject[0] ?? null;
|
|
230
225
|
return expects;
|
|
231
226
|
}
|
|
232
227
|
function expectValueToWord(t, expect, type) {
|
|
233
228
|
switch (expect.type) {
|
|
234
|
-
case 'common':
|
|
229
|
+
case 'common': {
|
|
235
230
|
return expect.value;
|
|
236
|
-
|
|
231
|
+
}
|
|
232
|
+
case 'const': {
|
|
237
233
|
return expect.value ? `%${expect.value}%` : '';
|
|
238
|
-
|
|
234
|
+
}
|
|
235
|
+
case 'format': {
|
|
239
236
|
return t('the {0} format', expect.value);
|
|
240
|
-
|
|
237
|
+
}
|
|
238
|
+
case 'regexp': {
|
|
241
239
|
return t('{0} ({1})', 'regular expression', expect.value);
|
|
242
|
-
|
|
243
|
-
|
|
240
|
+
}
|
|
241
|
+
case 'syntax': {
|
|
242
|
+
if (isKeyword(type) && type[0] === '<') {
|
|
244
243
|
return t('the CSS Syntax "{0}"', expect.value);
|
|
245
244
|
}
|
|
246
245
|
return t('{0} syntax', expect.value);
|
|
246
|
+
}
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
249
|
function createExpectedNumber(t, type) {
|
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,4 +1,2 @@
|
|
|
1
|
-
declare const _default: Readonly<
|
|
2
|
-
import('@markuplint/ml-core').RuleSeed<import('@markuplint/ml-core').RuleConfigValue, undefined>
|
|
3
|
-
>;
|
|
1
|
+
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
|
|
4
2
|
export default _default;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { createRule, getAttrSpecs } from '@markuplint/ml-core';
|
|
2
|
+
export default createRule({
|
|
3
|
+
meta: {
|
|
4
|
+
category: 'validation',
|
|
5
|
+
},
|
|
5
6
|
async verify({ document, report, t }) {
|
|
6
7
|
await document.walkOn('Attr', attr => {
|
|
7
|
-
|
|
8
|
-
const attrSpecs = (0, ml_core_1.getAttrSpecs)(attr.ownerElement, document.specs);
|
|
8
|
+
const attrSpecs = getAttrSpecs(attr.ownerElement, document.specs);
|
|
9
9
|
if (!attrSpecs) {
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
@@ -18,9 +18,9 @@ exports.default = (0, ml_core_1.createRule)({
|
|
|
18
18
|
const message = t('{0} is {1:c}', t('the "{0*}" {1}', name, 'attribute'), attrSpec.obsolete ? 'obsolete' : 'deprecated');
|
|
19
19
|
report({
|
|
20
20
|
scope: attr,
|
|
21
|
-
line:
|
|
22
|
-
col:
|
|
23
|
-
raw:
|
|
21
|
+
line: attr.nameNode?.startLine,
|
|
22
|
+
col: attr.nameNode?.startCol,
|
|
23
|
+
raw: attr.nameNode?.raw,
|
|
24
24
|
message,
|
|
25
25
|
});
|
|
26
26
|
}
|
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
declare const _default: Readonly<
|
|
2
|
-
import('@markuplint/ml-core').RuleSeed<import('@markuplint/ml-core').RuleConfigValue, undefined>
|
|
3
|
-
>;
|
|
1
|
+
declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
|
|
4
2
|
export default _default;
|