@markuplint/rules 1.10.4 → 2.0.0-dev.20211115.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -20
- package/lib/attr-check.d.ts +16 -0
- package/lib/attr-check.js +498 -0
- package/lib/attr-duplication/index.d.ts +1 -1
- package/lib/attr-duplication/index.js +5 -8
- package/lib/attr-equal-space-after/index.d.ts +1 -1
- package/lib/attr-equal-space-after/index.js +8 -11
- package/lib/attr-equal-space-before/index.d.ts +1 -1
- package/lib/attr-equal-space-before/index.js +8 -11
- package/lib/attr-spacing/index.d.ts +3 -3
- package/lib/attr-spacing/index.js +19 -21
- package/lib/attr-value-quotes/index.d.ts +1 -1
- package/lib/attr-value-quotes/index.js +9 -12
- package/lib/case-sensitive-attr-name/index.d.ts +1 -1
- package/lib/case-sensitive-attr-name/index.js +11 -14
- package/lib/case-sensitive-tag-name/index.d.ts +1 -1
- package/lib/case-sensitive-tag-name/index.js +8 -11
- package/lib/character-reference/index.d.ts +1 -1
- package/lib/character-reference/index.js +15 -11
- package/lib/class-naming/index.d.ts +1 -1
- package/lib/class-naming/index.js +7 -10
- package/lib/deprecated-attr/index.d.ts +1 -1
- package/lib/deprecated-attr/index.js +6 -9
- package/lib/deprecated-element/index.d.ts +1 -1
- package/lib/deprecated-element/index.js +10 -15
- package/lib/doctype/index.d.ts +1 -1
- package/lib/doctype/index.js +16 -25
- package/lib/helpers.d.ts +12 -11
- package/lib/helpers.js +38 -25
- package/lib/id-duplication/index.d.ts +1 -1
- package/lib/id-duplication/index.js +5 -8
- package/lib/indentation/index.d.ts +3 -3
- package/lib/indentation/index.js +81 -116
- package/lib/index.d.ts +45 -24
- package/lib/index.js +42 -42
- package/lib/invalid-attr/index.d.ts +2 -2
- package/lib/invalid-attr/index.js +23 -25
- package/lib/landmark-roles/index.d.ts +3 -3
- package/lib/landmark-roles/index.js +12 -20
- package/lib/permitted-contents/index.d.ts +2 -2
- package/lib/permitted-contents/index.js +63 -45
- package/lib/permitted-contents/permitted-content.spec-to-regexp.d.ts +2 -2
- package/lib/permitted-contents/permitted-content.spec-to-regexp.js +49 -30
- package/lib/permitted-contents/unfold-content-models-to-tags.d.ts +1 -1
- package/lib/permitted-contents/unfold-content-models-to-tags.js +2 -3
- package/lib/{type-check.d.ts → primitive-check.d.ts} +24 -7
- package/lib/primitive-check.js +109 -0
- package/lib/required-attr/index.d.ts +1 -1
- package/lib/required-attr/index.js +12 -16
- package/lib/required-h1/index.d.ts +3 -3
- package/lib/required-h1/index.js +8 -13
- package/lib/wai-aria/index.d.ts +1 -1
- package/lib/wai-aria/index.js +57 -64
- package/package.json +6 -6
- package/tsconfig.test.json +1 -24
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/type-check.js +0 -321
package/lib/index.js
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
-
const attr_duplication_1 = tslib_1.__importDefault(require("./attr-duplication"));
|
|
5
|
-
const attr_equal_space_after_1 = tslib_1.__importDefault(require("./attr-equal-space-after"));
|
|
6
|
-
const attr_equal_space_before_1 = tslib_1.__importDefault(require("./attr-equal-space-before"));
|
|
7
|
-
const attr_spacing_1 = tslib_1.__importDefault(require("./attr-spacing"));
|
|
8
|
-
const attr_value_quotes_1 = tslib_1.__importDefault(require("./attr-value-quotes"));
|
|
9
|
-
const case_sensitive_attr_name_1 = tslib_1.__importDefault(require("./case-sensitive-attr-name"));
|
|
10
|
-
const case_sensitive_tag_name_1 = tslib_1.__importDefault(require("./case-sensitive-tag-name"));
|
|
11
|
-
const character_reference_1 = tslib_1.__importDefault(require("./character-reference"));
|
|
12
|
-
const class_naming_1 = tslib_1.__importDefault(require("./class-naming"));
|
|
13
|
-
const deprecated_attr_1 = tslib_1.__importDefault(require("./deprecated-attr"));
|
|
14
|
-
const deprecated_element_1 = tslib_1.__importDefault(require("./deprecated-element"));
|
|
15
|
-
const doctype_1 = tslib_1.__importDefault(require("./doctype"));
|
|
16
|
-
const id_duplication_1 = tslib_1.__importDefault(require("./id-duplication"));
|
|
17
|
-
const indentation_1 = tslib_1.__importDefault(require("./indentation"));
|
|
18
|
-
const invalid_attr_1 = tslib_1.__importDefault(require("./invalid-attr"));
|
|
19
|
-
const landmark_roles_1 = tslib_1.__importDefault(require("./landmark-roles"));
|
|
20
|
-
const permitted_contents_1 = tslib_1.__importDefault(require("./permitted-contents"));
|
|
21
|
-
const required_attr_1 = tslib_1.__importDefault(require("./required-attr"));
|
|
22
|
-
const required_h1_1 = tslib_1.__importDefault(require("./required-h1"));
|
|
23
|
-
const wai_aria_1 = tslib_1.__importDefault(require("./wai-aria"));
|
|
24
|
-
exports.default =
|
|
25
|
-
attr_duplication_1.default,
|
|
26
|
-
attr_equal_space_after_1.default,
|
|
27
|
-
attr_equal_space_before_1.default,
|
|
28
|
-
attr_spacing_1.default,
|
|
29
|
-
attr_value_quotes_1.default,
|
|
30
|
-
case_sensitive_attr_name_1.default,
|
|
31
|
-
case_sensitive_tag_name_1.default,
|
|
32
|
-
character_reference_1.default,
|
|
33
|
-
class_naming_1.default,
|
|
34
|
-
deprecated_attr_1.default,
|
|
35
|
-
deprecated_element_1.default,
|
|
36
|
-
doctype_1.default,
|
|
37
|
-
id_duplication_1.default,
|
|
38
|
-
indentation_1.default,
|
|
39
|
-
invalid_attr_1.default,
|
|
40
|
-
landmark_roles_1.default,
|
|
41
|
-
permitted_contents_1.default,
|
|
42
|
-
required_attr_1.default,
|
|
43
|
-
required_h1_1.default,
|
|
44
|
-
wai_aria_1.default,
|
|
45
|
-
|
|
4
|
+
const attr_duplication_1 = (0, tslib_1.__importDefault)(require("./attr-duplication"));
|
|
5
|
+
const attr_equal_space_after_1 = (0, tslib_1.__importDefault)(require("./attr-equal-space-after"));
|
|
6
|
+
const attr_equal_space_before_1 = (0, tslib_1.__importDefault)(require("./attr-equal-space-before"));
|
|
7
|
+
const attr_spacing_1 = (0, tslib_1.__importDefault)(require("./attr-spacing"));
|
|
8
|
+
const attr_value_quotes_1 = (0, tslib_1.__importDefault)(require("./attr-value-quotes"));
|
|
9
|
+
const case_sensitive_attr_name_1 = (0, tslib_1.__importDefault)(require("./case-sensitive-attr-name"));
|
|
10
|
+
const case_sensitive_tag_name_1 = (0, tslib_1.__importDefault)(require("./case-sensitive-tag-name"));
|
|
11
|
+
const character_reference_1 = (0, tslib_1.__importDefault)(require("./character-reference"));
|
|
12
|
+
const class_naming_1 = (0, tslib_1.__importDefault)(require("./class-naming"));
|
|
13
|
+
const deprecated_attr_1 = (0, tslib_1.__importDefault)(require("./deprecated-attr"));
|
|
14
|
+
const deprecated_element_1 = (0, tslib_1.__importDefault)(require("./deprecated-element"));
|
|
15
|
+
const doctype_1 = (0, tslib_1.__importDefault)(require("./doctype"));
|
|
16
|
+
const id_duplication_1 = (0, tslib_1.__importDefault)(require("./id-duplication"));
|
|
17
|
+
const indentation_1 = (0, tslib_1.__importDefault)(require("./indentation"));
|
|
18
|
+
const invalid_attr_1 = (0, tslib_1.__importDefault)(require("./invalid-attr"));
|
|
19
|
+
const landmark_roles_1 = (0, tslib_1.__importDefault)(require("./landmark-roles"));
|
|
20
|
+
const permitted_contents_1 = (0, tslib_1.__importDefault)(require("./permitted-contents"));
|
|
21
|
+
const required_attr_1 = (0, tslib_1.__importDefault)(require("./required-attr"));
|
|
22
|
+
const required_h1_1 = (0, tslib_1.__importDefault)(require("./required-h1"));
|
|
23
|
+
const wai_aria_1 = (0, tslib_1.__importDefault)(require("./wai-aria"));
|
|
24
|
+
exports.default = {
|
|
25
|
+
'attr-duplication': attr_duplication_1.default,
|
|
26
|
+
'attr-equal-space-after': attr_equal_space_after_1.default,
|
|
27
|
+
'attr-equal-space-before': attr_equal_space_before_1.default,
|
|
28
|
+
'attr-spacing': attr_spacing_1.default,
|
|
29
|
+
'attr-value-quotes': attr_value_quotes_1.default,
|
|
30
|
+
'case-sensitive-attr-name': case_sensitive_attr_name_1.default,
|
|
31
|
+
'case-sensitive-tag-name': case_sensitive_tag_name_1.default,
|
|
32
|
+
'character-reference': character_reference_1.default,
|
|
33
|
+
'class-naming': class_naming_1.default,
|
|
34
|
+
'deprecated-attr': deprecated_attr_1.default,
|
|
35
|
+
'deprecated-element': deprecated_element_1.default,
|
|
36
|
+
doctype: doctype_1.default,
|
|
37
|
+
'id-duplication': id_duplication_1.default,
|
|
38
|
+
indentation: indentation_1.default,
|
|
39
|
+
'invalid-attr': invalid_attr_1.default,
|
|
40
|
+
'landmark-roles': landmark_roles_1.default,
|
|
41
|
+
'permitted-contents': permitted_contents_1.default,
|
|
42
|
+
'required-attr': required_attr_1.default,
|
|
43
|
+
'required-h1': required_h1_1.default,
|
|
44
|
+
'wai-aria': wai_aria_1.default,
|
|
45
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AttributeType } from '@markuplint/ml-spec
|
|
1
|
+
import type { AttributeType } from '@markuplint/ml-spec';
|
|
2
2
|
declare type Option = {
|
|
3
3
|
attrs?: Record<string, Rule>;
|
|
4
4
|
ignoreAttrNamePrefix?: string | string[];
|
|
@@ -10,5 +10,5 @@ declare type Rule = {
|
|
|
10
10
|
} | {
|
|
11
11
|
type: AttributeType;
|
|
12
12
|
};
|
|
13
|
-
declare const _default: import("@markuplint/ml-core").
|
|
13
|
+
declare const _default: import("@markuplint/ml-core").RuleSeed<true, Option>;
|
|
14
14
|
export default _default;
|
|
@@ -1,34 +1,32 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const ml_core_1 = require("@markuplint/ml-core");
|
|
4
|
+
const attr_check_1 = require("../attr-check");
|
|
4
5
|
const helpers_1 = require("../helpers");
|
|
5
|
-
|
|
6
|
-
exports.default = ml_core_1.createRule({
|
|
7
|
-
name: 'invalid-attr',
|
|
8
|
-
defaultLevel: 'error',
|
|
6
|
+
exports.default = (0, ml_core_1.createRule)({
|
|
9
7
|
defaultValue: true,
|
|
10
8
|
defaultOptions: {},
|
|
11
|
-
async verify(document,
|
|
12
|
-
const reports = [];
|
|
9
|
+
async verify({ document, report, t }) {
|
|
13
10
|
await document.walkOn('Element', async (node) => {
|
|
14
|
-
const attrSpecs = helpers_1.getAttrSpecs(node.
|
|
11
|
+
const attrSpecs = (0, helpers_1.getAttrSpecs)(node.nameWithNS, document.specs);
|
|
15
12
|
for (const attr of node.attributes) {
|
|
16
13
|
if (attr.attrType === 'html-attr' && attr.isDirective) {
|
|
17
14
|
continue;
|
|
18
15
|
}
|
|
19
16
|
const attrName = attr.getName();
|
|
20
17
|
const name = attrName.potential;
|
|
21
|
-
if (!node.isCustomElement && attr.attrType === 'html-attr' && attr.
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
(
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
if (!node.isCustomElement && attr.attrType === 'html-attr' && attr.candidate) {
|
|
19
|
+
const message = t('{0} is {1:c}', t('the "{0}" {1}', attrName.raw, 'attribute'), 'disallowed') +
|
|
20
|
+
t('. ') +
|
|
21
|
+
t('Did you mean "{0}"?', attr.candidate);
|
|
22
|
+
report({
|
|
23
|
+
scope: node,
|
|
27
24
|
message: message,
|
|
28
25
|
line: attrName.line,
|
|
29
26
|
col: attrName.col,
|
|
30
27
|
raw: attrName.raw,
|
|
31
28
|
});
|
|
29
|
+
continue;
|
|
32
30
|
}
|
|
33
31
|
const attrValue = attr.getValue();
|
|
34
32
|
const value = attrValue.raw;
|
|
@@ -44,33 +42,34 @@ exports.default = ml_core_1.createRule({
|
|
|
44
42
|
const customRule = node.rule.option.attrs ? node.rule.option.attrs[name] : null;
|
|
45
43
|
if (customRule) {
|
|
46
44
|
if ('enum' in customRule) {
|
|
47
|
-
invalid =
|
|
45
|
+
invalid = (0, attr_check_1.attrCheck)(t, name.toLowerCase(), value, true, {
|
|
48
46
|
name,
|
|
49
|
-
type:
|
|
50
|
-
|
|
47
|
+
type: {
|
|
48
|
+
enum: customRule.enum,
|
|
49
|
+
},
|
|
51
50
|
description: '',
|
|
52
51
|
});
|
|
53
52
|
}
|
|
54
53
|
else if ('pattern' in customRule) {
|
|
55
|
-
if (!helpers_1.match(value, customRule.pattern)) {
|
|
54
|
+
if (!(0, helpers_1.match)(value, customRule.pattern)) {
|
|
56
55
|
invalid = {
|
|
57
56
|
invalidType: 'invalid-value',
|
|
58
|
-
message:
|
|
57
|
+
message: t('{0} is unmatched with the below patterns: {1}', t('the "{0}" {1}', name, 'attribute'), customRule.pattern),
|
|
59
58
|
};
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
61
|
else if ('type' in customRule) {
|
|
63
|
-
invalid =
|
|
62
|
+
invalid = (0, attr_check_1.attrCheck)(t, name, value, true, { name, type: customRule.type, description: '' });
|
|
64
63
|
}
|
|
65
64
|
}
|
|
66
65
|
else if (!node.isCustomElement && attrSpecs) {
|
|
67
|
-
invalid = helpers_1.isValidAttr(name, value, (attr.attrType === 'html-attr' && attr.isDynamicValue) || false, node, attrSpecs);
|
|
66
|
+
invalid = (0, helpers_1.isValidAttr)(t, name, value, (attr.attrType === 'html-attr' && attr.isDynamicValue) || false, node, attrSpecs);
|
|
68
67
|
}
|
|
69
68
|
if (invalid) {
|
|
70
69
|
switch (invalid.invalidType) {
|
|
71
70
|
case 'invalid-value': {
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
report({
|
|
72
|
+
scope: node,
|
|
74
73
|
message: invalid.message,
|
|
75
74
|
line: attrValue.line,
|
|
76
75
|
col: attrValue.col,
|
|
@@ -79,8 +78,8 @@ exports.default = ml_core_1.createRule({
|
|
|
79
78
|
break;
|
|
80
79
|
}
|
|
81
80
|
case 'non-existent': {
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
report({
|
|
82
|
+
scope: node,
|
|
84
83
|
message: invalid.message,
|
|
85
84
|
line: attrName.line,
|
|
86
85
|
col: attrName.col,
|
|
@@ -91,6 +90,5 @@ exports.default = ml_core_1.createRule({
|
|
|
91
90
|
}
|
|
92
91
|
}
|
|
93
92
|
});
|
|
94
|
-
return reports;
|
|
95
93
|
},
|
|
96
94
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
declare type Options = {
|
|
2
|
-
ignoreRoles
|
|
3
|
-
labelEachArea
|
|
2
|
+
ignoreRoles?: Roles[];
|
|
3
|
+
labelEachArea?: boolean;
|
|
4
4
|
};
|
|
5
5
|
declare type TopLevelRoles = 'banner' | 'main' | 'complementary' | 'contentinfo';
|
|
6
6
|
declare type Roles = TopLevelRoles | 'form' | 'navigation' | 'region';
|
|
7
|
-
declare const _default: import("@markuplint/ml-core").
|
|
7
|
+
declare const _default: import("@markuplint/ml-core").RuleSeed<boolean, Options>;
|
|
8
8
|
export default _default;
|
|
@@ -11,19 +11,18 @@ const selectors = {
|
|
|
11
11
|
region: ['[role="region"]', 'section[aria-labelledby]', 'section[aria-label]', 'section[title]'],
|
|
12
12
|
};
|
|
13
13
|
const topLevelRoles = ['banner', 'main', 'complementary', 'contentinfo'];
|
|
14
|
-
exports.default = ml_core_1.createRule({
|
|
15
|
-
|
|
16
|
-
defaultLevel: 'warning',
|
|
14
|
+
exports.default = (0, ml_core_1.createRule)({
|
|
15
|
+
defaultServerity: 'warning',
|
|
17
16
|
defaultValue: true,
|
|
18
17
|
defaultOptions: {
|
|
19
18
|
ignoreRoles: [],
|
|
20
19
|
labelEachArea: true,
|
|
21
20
|
},
|
|
22
|
-
async verify(document,
|
|
21
|
+
async verify({ document, report, t }) {
|
|
22
|
+
var _a;
|
|
23
23
|
if (document.isFragment) {
|
|
24
|
-
return
|
|
24
|
+
return;
|
|
25
25
|
}
|
|
26
|
-
const reports = [];
|
|
27
26
|
const roles = {
|
|
28
27
|
complementary: document.matchNodes(selectors.complementary.join(',')),
|
|
29
28
|
contentinfo: document.matchNodes(selectors.contentinfo.join(',')),
|
|
@@ -74,16 +73,13 @@ exports.default = ml_core_1.createRule({
|
|
|
74
73
|
if (el.rule.disabled) {
|
|
75
74
|
continue;
|
|
76
75
|
}
|
|
77
|
-
if (el.rule.option.ignoreRoles.includes(role)) {
|
|
76
|
+
if ((_a = el.rule.option.ignoreRoles) === null || _a === void 0 ? void 0 : _a.includes(role)) {
|
|
78
77
|
continue;
|
|
79
78
|
}
|
|
80
79
|
if (el.isDescendantByUUIDList(uuidList)) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
message:
|
|
84
|
-
line: el.startLine,
|
|
85
|
-
col: el.startCol,
|
|
86
|
-
raw: el.raw,
|
|
80
|
+
report({
|
|
81
|
+
scope: el,
|
|
82
|
+
message: t('{0} should be {1}', t('the "{0}" {1}', role, 'role'), 'top level'),
|
|
87
83
|
});
|
|
88
84
|
}
|
|
89
85
|
}
|
|
@@ -102,17 +98,13 @@ exports.default = ml_core_1.createRule({
|
|
|
102
98
|
continue;
|
|
103
99
|
}
|
|
104
100
|
if (!hasLabel(el)) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
message:
|
|
108
|
-
line: el.startLine,
|
|
109
|
-
col: el.startCol,
|
|
110
|
-
raw: el.raw,
|
|
101
|
+
report({
|
|
102
|
+
scope: el,
|
|
103
|
+
message: t('Require {0}', t('unique {0}', 'accessible name')),
|
|
111
104
|
});
|
|
112
105
|
}
|
|
113
106
|
}
|
|
114
107
|
}
|
|
115
|
-
return reports;
|
|
116
108
|
},
|
|
117
109
|
});
|
|
118
110
|
function landmarkRoleElementUUIDList(roleset) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { PermittedStructuresSchema } from '@markuplint/ml-spec';
|
|
1
|
+
import type { PermittedStructuresSchema } from '@markuplint/ml-spec';
|
|
2
2
|
declare type Options = {
|
|
3
3
|
ignoreHasMutableChildren: boolean;
|
|
4
4
|
};
|
|
5
|
-
declare const _default: import("@markuplint/ml-core").
|
|
5
|
+
declare const _default: import("@markuplint/ml-core").RuleSeed<PermittedStructuresSchema[], Options>;
|
|
6
6
|
export default _default;
|
|
@@ -2,18 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const ml_core_1 = require("@markuplint/ml-core");
|
|
5
|
-
const permitted_content_spec_to_regexp_1 = tslib_1.__importDefault(require("./permitted-content.spec-to-regexp"));
|
|
6
5
|
const helpers_1 = require("../helpers");
|
|
7
|
-
const
|
|
6
|
+
const permitted_content_spec_to_regexp_1 = (0, tslib_1.__importDefault)(require("./permitted-content.spec-to-regexp"));
|
|
7
|
+
const unfold_content_models_to_tags_1 = (0, tslib_1.__importDefault)(require("./unfold-content-models-to-tags"));
|
|
8
8
|
const expMapOnNodeId = new Map();
|
|
9
|
-
exports.default = ml_core_1.createRule({
|
|
10
|
-
name: 'permitted-contents',
|
|
9
|
+
exports.default = (0, ml_core_1.createRule)({
|
|
11
10
|
defaultValue: [],
|
|
12
11
|
defaultOptions: {
|
|
13
12
|
ignoreHasMutableChildren: true,
|
|
14
13
|
},
|
|
15
|
-
async verify(document,
|
|
16
|
-
const reports = [];
|
|
14
|
+
async verify({ document, report, t }) {
|
|
17
15
|
let idCounter = 0;
|
|
18
16
|
await document.walkOn('Element', async (node) => {
|
|
19
17
|
var _a;
|
|
@@ -23,17 +21,15 @@ exports.default = ml_core_1.createRule({
|
|
|
23
21
|
if (node.rule.option.ignoreHasMutableChildren && node.hasMutableChildren()) {
|
|
24
22
|
return;
|
|
25
23
|
}
|
|
24
|
+
const specType = node.ns === 'html' ? 'HTML' : node.ns === 'svg' ? 'SVG' : 'Any Language';
|
|
26
25
|
const childNodes = node.getChildElementsAndTextNodeWithoutWhitespaces();
|
|
27
|
-
const spec = !node.isCustomElement && ((_a = helpers_1.htmlSpec(node.
|
|
26
|
+
const spec = !node.isCustomElement && ((_a = (0, helpers_1.htmlSpec)(node.nameWithNS)) === null || _a === void 0 ? void 0 : _a.permittedStructures);
|
|
28
27
|
const expGen = new permitted_content_spec_to_regexp_1.default(idCounter++);
|
|
29
28
|
if (spec) {
|
|
30
29
|
if (spec.ancestor && !node.closest(spec.ancestor)) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
message:
|
|
34
|
-
line: node.startLine,
|
|
35
|
-
col: node.startCol,
|
|
36
|
-
raw: node.raw,
|
|
30
|
+
report({
|
|
31
|
+
scope: node,
|
|
32
|
+
message: t('{0} must be {1}', t('the "{0}" {1}', node.nodeName, 'element'), t('{0} of {1}', 'descendant', t('the "{0}" {1}', spec.ancestor, 'element'))),
|
|
37
33
|
});
|
|
38
34
|
return;
|
|
39
35
|
}
|
|
@@ -50,12 +46,15 @@ exports.default = ml_core_1.createRule({
|
|
|
50
46
|
if (matched) {
|
|
51
47
|
try {
|
|
52
48
|
const parentExp = getRegExpFromParentNode(node, expGen);
|
|
53
|
-
const exp = expGen.specToRegExp(conditional.contents, parentExp);
|
|
54
|
-
const conditionalResult = match(exp, childNodes, false);
|
|
49
|
+
const exp = expGen.specToRegExp(conditional.contents, parentExp, node.ns);
|
|
50
|
+
const conditionalResult = match(exp, childNodes, node.ns, false);
|
|
55
51
|
if (!conditionalResult) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
const message = t('{0} is {1:c}', t('{0} of {1}', t('the {0}', 'content'), t('the "{0}" {1}', node.nodeName, 'element')), 'invalid');
|
|
53
|
+
report({
|
|
54
|
+
scope: node,
|
|
55
|
+
message: specType !== 'Any Language'
|
|
56
|
+
? t('{0} according to {1}', message, `the ${specType} specification`)
|
|
57
|
+
: message,
|
|
59
58
|
line: node.startLine,
|
|
60
59
|
col: node.startCol,
|
|
61
60
|
raw: node.raw,
|
|
@@ -64,8 +63,13 @@ exports.default = ml_core_1.createRule({
|
|
|
64
63
|
}
|
|
65
64
|
}
|
|
66
65
|
catch (e) {
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
if (e instanceof Error) {
|
|
67
|
+
// eslint-disable-next-line no-console
|
|
68
|
+
console.warn(node.raw, 'conditional', conditional, e.message);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
throw e;
|
|
72
|
+
}
|
|
69
73
|
}
|
|
70
74
|
}
|
|
71
75
|
}
|
|
@@ -73,20 +77,25 @@ exports.default = ml_core_1.createRule({
|
|
|
73
77
|
if (!matched) {
|
|
74
78
|
try {
|
|
75
79
|
const exp = getRegExpFromNode(node, expGen);
|
|
76
|
-
const specResult = match(exp, childNodes, false);
|
|
80
|
+
const specResult = match(exp, childNodes, node.ns, false);
|
|
77
81
|
if (!specResult) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
const message = t('{0} is {1:c}', t('{0} of {1}', t('the {0}', 'content'), t('the "{0}" {1}', node.nodeName, 'element')), 'invalid');
|
|
83
|
+
report({
|
|
84
|
+
scope: node,
|
|
85
|
+
message: specType !== 'Any Language'
|
|
86
|
+
? t('{0} according to {1}', message, `the ${specType} specification`)
|
|
87
|
+
: message,
|
|
84
88
|
});
|
|
85
89
|
}
|
|
86
90
|
}
|
|
87
91
|
catch (e) {
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
if (e instanceof Error) {
|
|
93
|
+
// eslint-disable-next-line no-console
|
|
94
|
+
console.warn(node.raw, 'HTML Spec', e.message);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
throw e;
|
|
98
|
+
}
|
|
90
99
|
}
|
|
91
100
|
}
|
|
92
101
|
}
|
|
@@ -96,13 +105,13 @@ exports.default = ml_core_1.createRule({
|
|
|
96
105
|
}
|
|
97
106
|
const parentExp = getRegExpFromParentNode(node, expGen);
|
|
98
107
|
try {
|
|
99
|
-
const exp = expGen.specToRegExp(rule.contents, parentExp);
|
|
108
|
+
const exp = expGen.specToRegExp(rule.contents, parentExp, node.ns);
|
|
100
109
|
// Evaluate the custom element if the optional schema.
|
|
101
|
-
const r = match(exp, childNodes, node.isCustomElement);
|
|
110
|
+
const r = match(exp, childNodes, node.ns, node.isCustomElement);
|
|
102
111
|
if (!r) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
message:
|
|
112
|
+
report({
|
|
113
|
+
scope: node,
|
|
114
|
+
message: t('{0} is {1:c}', t('{0} of {1}', t('the {0}', 'content'), t('the "{0}" {1}', node.nodeName, 'element')), 'invalid'),
|
|
106
115
|
line: node.startLine,
|
|
107
116
|
col: node.startCol,
|
|
108
117
|
raw: node.raw,
|
|
@@ -111,22 +120,31 @@ exports.default = ml_core_1.createRule({
|
|
|
111
120
|
}
|
|
112
121
|
}
|
|
113
122
|
catch (e) {
|
|
114
|
-
|
|
115
|
-
|
|
123
|
+
if (e instanceof Error) {
|
|
124
|
+
// eslint-disable-next-line no-console
|
|
125
|
+
console.warn(node.raw, 'rule', rule, e.message);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
throw e;
|
|
129
|
+
}
|
|
116
130
|
}
|
|
117
131
|
}
|
|
118
132
|
});
|
|
119
133
|
expMapOnNodeId.clear();
|
|
120
|
-
return reports;
|
|
121
134
|
},
|
|
122
135
|
});
|
|
123
|
-
function normalization(nodes, evalCustomElement) {
|
|
136
|
+
function normalization(nodes, ownNS, evalCustomElement) {
|
|
124
137
|
return nodes
|
|
125
138
|
.map(node => {
|
|
126
139
|
if (!evalCustomElement && node.type === 'Element' && node.isCustomElement) {
|
|
127
140
|
return '';
|
|
128
141
|
}
|
|
129
|
-
|
|
142
|
+
if (node.type !== 'Element') {
|
|
143
|
+
return '<#text>';
|
|
144
|
+
}
|
|
145
|
+
ownNS = ownNS || 'html';
|
|
146
|
+
const name = node.nameWithNS.replace(new RegExp(`^${ownNS}:`), '');
|
|
147
|
+
return `<${name}>`;
|
|
130
148
|
})
|
|
131
149
|
.join('');
|
|
132
150
|
}
|
|
@@ -137,9 +155,9 @@ function getRegExpFromNode(node, expGen) {
|
|
|
137
155
|
return expMapOnNodeId.get(node.uuid);
|
|
138
156
|
}
|
|
139
157
|
const parentExp = node.parentNode ? getRegExpFromNode(node.parentNode, expGen) : null;
|
|
140
|
-
const spec = !node.isCustomElement && ((_a = helpers_1.htmlSpec(node.nodeName)) === null || _a === void 0 ? void 0 : _a.permittedStructures);
|
|
158
|
+
const spec = !node.isCustomElement && ((_a = (0, helpers_1.htmlSpec)(node.nameWithNS || node.nodeName.toLowerCase())) === null || _a === void 0 ? void 0 : _a.permittedStructures);
|
|
141
159
|
const contentRule = spec ? spec.contents : true;
|
|
142
|
-
const exp = expGen.specToRegExp(contentRule, parentExp);
|
|
160
|
+
const exp = expGen.specToRegExp(contentRule, parentExp, node.ns || null);
|
|
143
161
|
expMapOnNodeId.set(node.uuid, exp);
|
|
144
162
|
return exp;
|
|
145
163
|
}
|
|
@@ -148,8 +166,8 @@ function getRegExpFromParentNode(node, expGen) {
|
|
|
148
166
|
const parentExp = node.parentNode ? getRegExpFromNode(node.parentNode, expGen) : null;
|
|
149
167
|
return parentExp;
|
|
150
168
|
}
|
|
151
|
-
function match(exp, childNodes, evalCustomElement) {
|
|
152
|
-
const target = normalization(childNodes, evalCustomElement);
|
|
169
|
+
function match(exp, childNodes, ownNS, evalCustomElement) {
|
|
170
|
+
const target = normalization(childNodes, ownNS, evalCustomElement);
|
|
153
171
|
const result = exp.exec(target);
|
|
154
172
|
if (!result) {
|
|
155
173
|
return false;
|
|
@@ -170,7 +188,7 @@ function match(exp, childNodes, evalCustomElement) {
|
|
|
170
188
|
switch (type) {
|
|
171
189
|
case 'ACM': {
|
|
172
190
|
const [model, tag] = _selector;
|
|
173
|
-
const selectors = unfold_content_models_to_tags_1.default(`#${model}`).filter(selector => {
|
|
191
|
+
const selectors = (0, unfold_content_models_to_tags_1.default)(`#${model}`).filter(selector => {
|
|
174
192
|
const [, tagName] = /^([^[\]]+)(?:\[[^\]]+\])?$/.exec(selector) || [];
|
|
175
193
|
return tagName.toLowerCase() === tag.toLowerCase();
|
|
176
194
|
});
|
|
@@ -203,7 +221,7 @@ function match(exp, childNodes, evalCustomElement) {
|
|
|
203
221
|
: null;
|
|
204
222
|
_selector.forEach(content => {
|
|
205
223
|
if (content[0] === '_') {
|
|
206
|
-
unfold_content_models_to_tags_1.default(content.replace('_', '#')).forEach(tag => contents.add(tag));
|
|
224
|
+
(0, unfold_content_models_to_tags_1.default)(content.replace('_', '#')).forEach(tag => contents.add(tag));
|
|
207
225
|
return;
|
|
208
226
|
}
|
|
209
227
|
contents.add(content);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { PermittedContent } from '@markuplint/ml-spec';
|
|
1
|
+
import type { PermittedContent } from '@markuplint/ml-spec';
|
|
2
2
|
export default class ExpGenerator {
|
|
3
3
|
private _id;
|
|
4
4
|
private _idCounter;
|
|
5
5
|
constructor(_id: number);
|
|
6
|
-
specToRegExp(contentRule: PermittedContent[] | boolean, parentExp?: RegExp | null): RegExp;
|
|
6
|
+
specToRegExp(contentRule: PermittedContent[] | boolean, parentExp?: RegExp | null, ownNS?: string | null): RegExp;
|
|
7
7
|
private _toPattern;
|
|
8
8
|
private _interleavePattern;
|
|
9
9
|
private _targetTags;
|