@markuplint/rules 2.0.0-dev.23 → 2.0.0-rc.5

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.
Files changed (63) hide show
  1. package/lib/attr-check.d.ts +8 -1
  2. package/lib/attr-check.js +53 -455
  3. package/lib/attr-duplication/index.d.ts +1 -1
  4. package/lib/attr-duplication/index.js +0 -2
  5. package/lib/attr-equal-space-after/index.js +0 -1
  6. package/lib/attr-equal-space-before/index.js +0 -1
  7. package/lib/attr-spacing/index.js +0 -1
  8. package/lib/attr-value-quotes/index.js +0 -1
  9. package/lib/case-sensitive-attr-name/index.d.ts +6 -2
  10. package/lib/case-sensitive-attr-name/index.js +30 -8
  11. package/lib/case-sensitive-tag-name/index.js +0 -1
  12. package/lib/character-reference/index.d.ts +1 -2
  13. package/lib/character-reference/index.js +0 -2
  14. package/lib/class-naming/index.js +23 -23
  15. package/lib/create-message.d.ts +5 -0
  16. package/lib/create-message.js +270 -0
  17. package/lib/debug.d.ts +3 -0
  18. package/lib/debug.js +6 -0
  19. package/lib/deprecated-attr/index.d.ts +1 -1
  20. package/lib/deprecated-attr/index.js +2 -5
  21. package/lib/deprecated-element/index.d.ts +1 -1
  22. package/lib/deprecated-element/index.js +1 -3
  23. package/lib/disallowed-element/index.d.ts +2 -0
  24. package/lib/disallowed-element/index.js +34 -0
  25. package/lib/helpers.d.ts +15 -9
  26. package/lib/helpers.js +63 -68
  27. package/lib/id-duplication/index.d.ts +1 -1
  28. package/lib/id-duplication/index.js +1 -3
  29. package/lib/index.d.ts +28 -11
  30. package/lib/index.js +16 -0
  31. package/lib/ineffective-attr/index.d.ts +2 -0
  32. package/lib/ineffective-attr/index.js +40 -0
  33. package/lib/invalid-attr/index.d.ts +4 -2
  34. package/lib/invalid-attr/index.js +25 -9
  35. package/lib/landmark-roles/index.js +1 -2
  36. package/lib/no-boolean-attr-value/index.d.ts +2 -0
  37. package/lib/no-boolean-attr-value/index.js +47 -0
  38. package/lib/no-default-value/index.d.ts +2 -0
  39. package/lib/no-default-value/index.js +38 -0
  40. package/lib/no-hard-code-id/index.d.ts +2 -0
  41. package/lib/no-hard-code-id/index.js +27 -0
  42. package/lib/no-refer-to-non-existent-id/index.d.ts +2 -0
  43. package/lib/no-refer-to-non-existent-id/index.js +110 -0
  44. package/lib/no-use-event-handler-attr/index.d.ts +5 -0
  45. package/lib/no-use-event-handler-attr/index.js +37 -0
  46. package/lib/permitted-contents/index.js +24 -13
  47. package/lib/permitted-contents/types.d.ts +8 -0
  48. package/lib/permitted-contents/types.js +2 -0
  49. package/lib/require-element/index.d.ts +2 -0
  50. package/lib/require-element/index.js +38 -0
  51. package/lib/required-attr/index.d.ts +5 -1
  52. package/lib/required-attr/index.js +60 -19
  53. package/lib/required-element/index.d.ts +5 -0
  54. package/lib/required-element/index.js +44 -0
  55. package/lib/required-h1/index.d.ts +2 -3
  56. package/lib/required-h1/index.js +2 -3
  57. package/lib/wai-aria/index.d.ts +1 -1
  58. package/lib/wai-aria/index.js +23 -24
  59. package/package.json +10 -5
  60. package/schema.json +24 -0
  61. package/tsconfig.tsbuildinfo +1 -1
  62. package/lib/primitive-check.d.ts +0 -48
  63. package/lib/primitive-check.js +0 -109
package/lib/helpers.js CHANGED
@@ -1,45 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.checkAria = exports.checkAriaValue = exports.getComputedRole = exports.getImplicitRole = exports.getPermittedRoles = exports.getRoleSpec = exports.ariaSpec = exports.isValidAttr = exports.htmlSpec = exports.rePCENChar = exports.match = exports.attrMatches = exports.getAttrSpecs = void 0;
4
- const html_spec_1 = require("@markuplint/html-spec");
3
+ exports.checkAria = exports.checkAriaValue = exports.getComputedRole = exports.getImplicitRole = exports.getPermittedRoles = exports.getRoleSpec = exports.ariaSpec = exports.toNormalizedValue = exports.isValidAttr = exports.htmlSpec = exports.rePCENChar = exports.match = exports.attrMatches = void 0;
5
4
  const attr_check_1 = require("./attr-check");
6
- function getAttrSpecs(nameWithNS, { specs, def }) {
7
- const spec = specs.find(spec => spec.name === nameWithNS);
8
- if (!spec) {
9
- return null;
10
- }
11
- const globalAttrs = def['#globalAttrs'];
12
- const attrs = [];
13
- if (!/[a-z]:[a-z]/i.test(nameWithNS)) {
14
- // It's HTML tag
15
- const hasGlobalAttr = spec.attributes.some(attr => attr === '#globalAttrs');
16
- if (hasGlobalAttr) {
17
- attrs.push(...(globalAttrs['#HTMLGlobalAttrs'] || []));
18
- }
19
- }
20
- for (const attr of spec.attributes) {
21
- if (typeof attr === 'string') {
22
- const globalAttr = globalAttrs[attr];
23
- if (!globalAttr) {
24
- continue;
25
- }
26
- attrs.push(...globalAttr);
27
- continue;
28
- }
29
- const definedIndex = attrs.findIndex(a => a.name === attr.name);
30
- if (definedIndex !== -1) {
31
- attrs[definedIndex] = {
32
- ...attrs[definedIndex],
33
- ...attr,
34
- };
35
- continue;
36
- }
37
- attrs.push(attr);
38
- }
39
- attrs.push(...(globalAttrs['#extends'] || []));
40
- return attrs;
41
- }
42
- exports.getAttrSpecs = getAttrSpecs;
43
5
  function attrMatches(node, condition) {
44
6
  if (!condition) {
45
7
  return true;
@@ -53,7 +15,10 @@ function attrMatches(node, condition) {
53
15
  let _node = node.parentNode;
54
16
  while (_node) {
55
17
  if (_node.type === 'Element') {
56
- if (_node.matches(condition.ancestor)) {
18
+ const condSelector = Array.isArray(condition.ancestor)
19
+ ? condition.ancestor.join(',')
20
+ : condition.ancestor;
21
+ if (_node.matches(condSelector)) {
57
22
  matched = true;
58
23
  break;
59
24
  }
@@ -109,19 +74,20 @@ exports.rePCENChar = [
109
74
  '[\uFDF0-\uFFFD]',
110
75
  '[\uD800-\uDBFF][\uDC00-\uDFFF]',
111
76
  ].join('|');
112
- function htmlSpec(nameWithNS) {
113
- const spec = html_spec_1.specs.find(spec => spec.name === nameWithNS);
77
+ function htmlSpec(specs, nameWithNS) {
78
+ const spec = specs.specs.find(spec => spec.name === nameWithNS);
114
79
  return spec || null;
115
80
  }
116
81
  exports.htmlSpec = htmlSpec;
117
- function isValidAttr(t, name, value, isDynamicValue, node, attrSpecs) {
82
+ function isValidAttr(t, name, value, isDynamicValue, node, attrSpecs, log) {
118
83
  let invalid = false;
119
- const spec = attrSpecs.find(s => s.name === name);
84
+ const spec = attrSpecs.find(s => s.name.toLowerCase() === name.toLowerCase());
85
+ log && log('Spec of the %s attr: %o', name, spec);
120
86
  invalid = (0, attr_check_1.attrCheck)(t, name, value, false, spec);
121
87
  if (!invalid && spec && spec.condition && !node.hasSpreadAttr && !attrMatches(node, spec.condition)) {
122
88
  invalid = {
123
89
  invalidType: 'non-existent',
124
- message: t('{0} is {1}', t('the "{0}" {1}', name, 'attribute'), 'disallowed'),
90
+ message: t('{0} is {1}', t('the "{0*}" {1}', name, 'attribute'), 'disallowed'),
125
91
  };
126
92
  }
127
93
  if (invalid && invalid.invalidType === 'invalid-value' && isDynamicValue) {
@@ -130,21 +96,50 @@ function isValidAttr(t, name, value, isDynamicValue, node, attrSpecs) {
130
96
  return invalid;
131
97
  }
132
98
  exports.isValidAttr = isValidAttr;
133
- function ariaSpec() {
134
- const roles = html_spec_1.def['#roles'];
135
- const ariaAttrs = html_spec_1.def['#ariaAttrs'];
99
+ function toNormalizedValue(value, spec) {
100
+ let normalized = value;
101
+ if (!spec.caseSensitive) {
102
+ normalized = normalized.toLowerCase();
103
+ }
104
+ if (typeof spec.type === 'string') {
105
+ if (spec.type[0] === '<') {
106
+ normalized = normalized.toLowerCase().trim().replace(/\s+/g, ' ');
107
+ }
108
+ }
109
+ else {
110
+ if ('token' in spec.type) {
111
+ if (spec.type.caseInsensitive) {
112
+ normalized = normalized.toLowerCase();
113
+ }
114
+ if (!spec.type.disallowToSurroundBySpaces) {
115
+ normalized = normalized.trim();
116
+ }
117
+ if (spec.type.separator === 'space') {
118
+ normalized = normalized.replace(/\s+/g, ' ');
119
+ }
120
+ if (spec.type.separator === 'comma') {
121
+ normalized = normalized.replace(/\s*,\s*/g, ',');
122
+ }
123
+ }
124
+ }
125
+ return normalized;
126
+ }
127
+ exports.toNormalizedValue = toNormalizedValue;
128
+ function ariaSpec(specs) {
129
+ const roles = specs.def['#roles'];
130
+ const ariaAttrs = specs.def['#ariaAttrs'];
136
131
  return {
137
132
  roles,
138
133
  ariaAttrs,
139
134
  };
140
135
  }
141
136
  exports.ariaSpec = ariaSpec;
142
- function getRoleSpec(roleName) {
143
- const role = getRoleByName(roleName);
137
+ function getRoleSpec(specs, roleName) {
138
+ const role = getRoleByName(specs, roleName);
144
139
  if (!role) {
145
140
  return null;
146
141
  }
147
- const superClassRoles = recursiveTraverseSuperClassRoles(roleName);
142
+ const superClassRoles = recursiveTraverseSuperClassRoles(specs, roleName);
148
143
  return {
149
144
  name: role.name,
150
145
  isAbstract: !!role.isAbstract,
@@ -153,22 +148,22 @@ function getRoleSpec(roleName) {
153
148
  };
154
149
  }
155
150
  exports.getRoleSpec = getRoleSpec;
156
- function getRoleByName(roleName) {
157
- const roles = html_spec_1.def['#roles'];
151
+ function getRoleByName(specs, roleName) {
152
+ const roles = specs.def['#roles'];
158
153
  const role = roles.find(r => r.name === roleName);
159
154
  return role;
160
155
  }
161
- function getSuperClassRoles(roleName) {
162
- const role = getRoleByName(roleName);
163
- return ((role === null || role === void 0 ? void 0 : role.generalization.map(roleName => getRoleByName(roleName)).filter((role) => !!role)) || null);
156
+ function getSuperClassRoles(specs, roleName) {
157
+ const role = getRoleByName(specs, roleName);
158
+ return ((role === null || role === void 0 ? void 0 : role.generalization.map(roleName => getRoleByName(specs, roleName)).filter((role) => !!role)) || null);
164
159
  }
165
- function recursiveTraverseSuperClassRoles(roleName) {
160
+ function recursiveTraverseSuperClassRoles(specs, roleName) {
166
161
  const roles = [];
167
- const superClassRoles = getSuperClassRoles(roleName);
162
+ const superClassRoles = getSuperClassRoles(specs, roleName);
168
163
  if (superClassRoles) {
169
164
  roles.push(...superClassRoles);
170
165
  for (const superClassRole of superClassRoles) {
171
- const ancestorRoles = recursiveTraverseSuperClassRoles(superClassRole.name);
166
+ const ancestorRoles = recursiveTraverseSuperClassRoles(specs, superClassRole.name);
172
167
  roles.push(...ancestorRoles);
173
168
  }
174
169
  }
@@ -181,10 +176,10 @@ function recursiveTraverseSuperClassRoles(roleName) {
181
176
  * - If `true`, this mean is "Any".
182
177
  * - If `false`, this mean is "No".
183
178
  */
184
- function getPermittedRoles(el) {
179
+ function getPermittedRoles(specs, el) {
185
180
  var _a;
186
- const implicitRole = getImplicitRole(el);
187
- const spec = (_a = htmlSpec(el.nodeName)) === null || _a === void 0 ? void 0 : _a.permittedRoles;
181
+ const implicitRole = getImplicitRole(specs, el);
182
+ const spec = (_a = htmlSpec(specs, el.nodeName)) === null || _a === void 0 ? void 0 : _a.permittedRoles;
188
183
  if (!spec) {
189
184
  return true;
190
185
  }
@@ -213,9 +208,9 @@ function mergeRoleList(implicitRole, permittedRoles) {
213
208
  }
214
209
  return permittedRoles;
215
210
  }
216
- function getImplicitRole(el) {
211
+ function getImplicitRole(specs, el) {
217
212
  var _a;
218
- const implicitRole = (_a = htmlSpec(el.nodeName)) === null || _a === void 0 ? void 0 : _a.implicitRole;
213
+ const implicitRole = (_a = htmlSpec(specs, el.nodeName)) === null || _a === void 0 ? void 0 : _a.implicitRole;
219
214
  if (!implicitRole) {
220
215
  return false;
221
216
  }
@@ -229,7 +224,7 @@ function getImplicitRole(el) {
229
224
  return implicitRole.role;
230
225
  }
231
226
  exports.getImplicitRole = getImplicitRole;
232
- function getComputedRole(el) {
227
+ function getComputedRole(specs, el) {
233
228
  const roleAttrTokens = el.getAttributeToken('role');
234
229
  const roleAttr = roleAttrTokens[0];
235
230
  if (roleAttr) {
@@ -239,7 +234,7 @@ function getComputedRole(el) {
239
234
  isImplicit: false,
240
235
  };
241
236
  }
242
- const implicitRole = getImplicitRole(el);
237
+ const implicitRole = getImplicitRole(specs, el);
243
238
  if (implicitRole) {
244
239
  return {
245
240
  name: implicitRole,
@@ -291,8 +286,8 @@ function checkAriaValue(type, value, tokenEnum) {
291
286
  return true;
292
287
  }
293
288
  exports.checkAriaValue = checkAriaValue;
294
- function checkAria(attrName, currentValue, role) {
295
- const ariaAttrs = html_spec_1.def['#ariaAttrs'];
289
+ function checkAria(specs, attrName, currentValue, role) {
290
+ const ariaAttrs = specs.def['#ariaAttrs'];
296
291
  const aria = ariaAttrs.find(a => a.name === attrName);
297
292
  if (!aria) {
298
293
  return {
@@ -1,2 +1,2 @@
1
- declare const _default: import("@markuplint/ml-core").RuleSeed<null, null>;
1
+ declare const _default: import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, null>;
2
2
  export default _default;
@@ -2,10 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const ml_core_1 = require("@markuplint/ml-core");
4
4
  exports.default = (0, ml_core_1.createRule)({
5
- defaultValue: null,
6
- defaultOptions: null,
7
5
  async verify({ document, report, t }) {
8
- const message = t('{0} is {1:c}', t('{0} of {1}', t('the {0}', 'value'), t('the "{0}" {1}', 'id', 'attribute')), 'duplicated');
6
+ const message = t('{0} is {1:c}', t('{0} of {1}', t('the {0}', 'value'), t('the "{0*}" {1}', 'id', 'attribute')), 'duplicated');
9
7
  const idStack = [];
10
8
  await document.walkOn('Element', async (node) => {
11
9
  const idAttrs = node.getAttributeToken('id');
package/lib/index.d.ts CHANGED
@@ -1,27 +1,31 @@
1
1
  declare const _default: {
2
- 'attr-duplication': import("packages/@markuplint/ml-core/lib").RuleSeed<null, null>;
2
+ 'attr-duplication': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
3
3
  'attr-equal-space-after': import("packages/@markuplint/ml-core/lib").RuleSeed<"always" | "never" | "always-single-line" | "never-single-line", null>;
4
4
  'attr-equal-space-before': import("packages/@markuplint/ml-core/lib").RuleSeed<"always" | "never" | "always-single-line" | "never-single-line", null>;
5
5
  'attr-spacing': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, import("./attr-spacing").AttrSpasingOptions>;
6
6
  'attr-value-quotes': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./attr-value-quotes").Type, null>;
7
- 'case-sensitive-attr-name': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./case-sensitive-attr-name").Value, null>;
7
+ 'case-sensitive-attr-name': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./case-sensitive-attr-name").Value | import("./case-sensitive-attr-name").Value_v1, null>;
8
8
  'case-sensitive-tag-name': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./case-sensitive-tag-name").Value, null>;
9
- 'character-reference': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, null>;
9
+ 'character-reference': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
10
10
  'class-naming': import("packages/@markuplint/ml-core/lib").RuleSeed<import("./class-naming").Value, null>;
11
- 'deprecated-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<null, null>;
12
- 'deprecated-element': import("packages/@markuplint/ml-core/lib").RuleSeed<null, null>;
11
+ 'deprecated-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
12
+ 'deprecated-element': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
13
+ 'disallowed-element': import("packages/@markuplint/ml-core/lib").RuleSeed<string[], null>;
13
14
  doctype: import("packages/@markuplint/ml-core/lib").RuleSeed<"always", {
14
15
  denyObsolateType: boolean;
15
16
  }>;
16
- 'id-duplication': import("packages/@markuplint/ml-core/lib").RuleSeed<null, null>;
17
+ 'id-duplication': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
17
18
  indentation: import("packages/@markuplint/ml-core/lib").RuleSeed<import("./indentation").Value, import("./indentation").IndentationOptions>;
18
- 'invalid-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<true, {
19
+ 'ineffective-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
20
+ 'invalid-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, {
19
21
  attrs?: Record<string, {
20
- enum: string[];
22
+ enum: [string, ...string[]];
21
23
  } | {
22
24
  pattern: string;
23
25
  } | {
24
26
  type: import("packages/@markuplint/ml-spec/lib").AttributeType;
27
+ } | {
28
+ disallowed: true;
25
29
  }> | undefined;
26
30
  ignoreAttrNamePrefix?: string | string[] | undefined;
27
31
  }>;
@@ -29,12 +33,25 @@ declare const _default: {
29
33
  ignoreRoles?: (("banner" | "main" | "complementary" | "contentinfo") | "form" | "navigation" | "region")[] | undefined;
30
34
  labelEachArea?: boolean | undefined;
31
35
  }>;
36
+ 'no-boolean-attr-value': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
37
+ 'no-default-value': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
38
+ 'no-hard-code-id': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
39
+ 'no-refer-to-non-existent-id': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-config/src").RuleConfigValue, null>;
40
+ 'no-use-event-handler-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, {
41
+ ignore?: string | string[] | undefined;
42
+ }>;
32
43
  'permitted-contents': import("packages/@markuplint/ml-core/lib").RuleSeed<import("packages/@markuplint/ml-spec/lib").PermittedStructuresSchema[], {
33
44
  ignoreHasMutableChildren: boolean;
34
45
  }>;
35
- 'required-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<string | string[], null>;
36
- 'required-h1': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, import("./required-h1").RequiredH1Options>;
37
- 'wai-aria': import("packages/@markuplint/ml-core/lib").RuleSeed<true, {
46
+ 'required-attr': import("packages/@markuplint/ml-core/lib").RuleSeed<string | (string | {
47
+ name: string;
48
+ value: string | string[];
49
+ })[], null>;
50
+ 'required-element': import("packages/@markuplint/ml-core/lib").RuleSeed<string[], {
51
+ ignoreHasMutableContents?: boolean | undefined;
52
+ }>;
53
+ 'required-h1': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, import("./required-h1").Options>;
54
+ 'wai-aria': import("packages/@markuplint/ml-core/lib").RuleSeed<boolean, {
38
55
  checkingValue?: boolean | undefined;
39
56
  checkingDeprecatedProps?: boolean | undefined;
40
57
  permittedAriaRoles?: boolean | undefined;
package/lib/index.js CHANGED
@@ -12,13 +12,21 @@ const character_reference_1 = (0, tslib_1.__importDefault)(require("./character-
12
12
  const class_naming_1 = (0, tslib_1.__importDefault)(require("./class-naming"));
13
13
  const deprecated_attr_1 = (0, tslib_1.__importDefault)(require("./deprecated-attr"));
14
14
  const deprecated_element_1 = (0, tslib_1.__importDefault)(require("./deprecated-element"));
15
+ const disallowed_element_1 = (0, tslib_1.__importDefault)(require("./disallowed-element"));
15
16
  const doctype_1 = (0, tslib_1.__importDefault)(require("./doctype"));
16
17
  const id_duplication_1 = (0, tslib_1.__importDefault)(require("./id-duplication"));
17
18
  const indentation_1 = (0, tslib_1.__importDefault)(require("./indentation"));
19
+ const ineffective_attr_1 = (0, tslib_1.__importDefault)(require("./ineffective-attr"));
18
20
  const invalid_attr_1 = (0, tslib_1.__importDefault)(require("./invalid-attr"));
19
21
  const landmark_roles_1 = (0, tslib_1.__importDefault)(require("./landmark-roles"));
22
+ const no_boolean_attr_value_1 = (0, tslib_1.__importDefault)(require("./no-boolean-attr-value"));
23
+ const no_default_value_1 = (0, tslib_1.__importDefault)(require("./no-default-value"));
24
+ const no_hard_code_id_1 = (0, tslib_1.__importDefault)(require("./no-hard-code-id"));
25
+ const no_refer_to_non_existent_id_1 = (0, tslib_1.__importDefault)(require("./no-refer-to-non-existent-id"));
26
+ const no_use_event_handler_attr_1 = (0, tslib_1.__importDefault)(require("./no-use-event-handler-attr"));
20
27
  const permitted_contents_1 = (0, tslib_1.__importDefault)(require("./permitted-contents"));
21
28
  const required_attr_1 = (0, tslib_1.__importDefault)(require("./required-attr"));
29
+ const required_element_1 = (0, tslib_1.__importDefault)(require("./required-element"));
22
30
  const required_h1_1 = (0, tslib_1.__importDefault)(require("./required-h1"));
23
31
  const wai_aria_1 = (0, tslib_1.__importDefault)(require("./wai-aria"));
24
32
  exports.default = {
@@ -33,13 +41,21 @@ exports.default = {
33
41
  'class-naming': class_naming_1.default,
34
42
  'deprecated-attr': deprecated_attr_1.default,
35
43
  'deprecated-element': deprecated_element_1.default,
44
+ 'disallowed-element': disallowed_element_1.default,
36
45
  doctype: doctype_1.default,
37
46
  'id-duplication': id_duplication_1.default,
38
47
  indentation: indentation_1.default,
48
+ 'ineffective-attr': ineffective_attr_1.default,
39
49
  'invalid-attr': invalid_attr_1.default,
40
50
  'landmark-roles': landmark_roles_1.default,
51
+ 'no-boolean-attr-value': no_boolean_attr_value_1.default,
52
+ 'no-default-value': no_default_value_1.default,
53
+ 'no-hard-code-id': no_hard_code_id_1.default,
54
+ 'no-refer-to-non-existent-id': no_refer_to_non_existent_id_1.default,
55
+ 'no-use-event-handler-attr': no_use_event_handler_attr_1.default,
41
56
  'permitted-contents': permitted_contents_1.default,
42
57
  'required-attr': required_attr_1.default,
58
+ 'required-element': required_element_1.default,
43
59
  'required-h1': required_h1_1.default,
44
60
  'wai-aria': wai_aria_1.default,
45
61
  };
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, null>;
2
+ export default _default;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ml_core_1 = require("@markuplint/ml-core");
4
+ exports.default = (0, ml_core_1.createRule)({
5
+ defaultServerity: 'warning',
6
+ async verify({ document, report, t }) {
7
+ document.walkOn('Element', el => {
8
+ const attrSpec = (0, ml_core_1.getAttrSpecs)(el.nameWithNS, document.specs);
9
+ if (!attrSpec) {
10
+ return;
11
+ }
12
+ for (const attr of el.attributes) {
13
+ if (attr.attrType === 'ps-attr') {
14
+ continue;
15
+ }
16
+ const name = attr.getName().potential;
17
+ const spec = attrSpec.find(s => s.name === name);
18
+ if (!spec) {
19
+ continue;
20
+ }
21
+ const ineffectiveConditions = spec.ineffective
22
+ ? Array.isArray(spec.ineffective)
23
+ ? spec.ineffective
24
+ : [spec.ineffective]
25
+ : [];
26
+ if (ineffectiveConditions.some(selector => el.matches(selector))) {
27
+ report({
28
+ scope: el,
29
+ raw: attr.raw,
30
+ line: attr.startLine,
31
+ col: attr.startCol,
32
+ message: t('{0} is {1:c}', t('the "{0*}" {1}', name, 'attribute'), 'ineffective') +
33
+ t('. ') +
34
+ t("It doesn't need {0}", t('the {0}', 'attribute')),
35
+ });
36
+ }
37
+ }
38
+ });
39
+ },
40
+ });
@@ -4,11 +4,13 @@ declare type Option = {
4
4
  ignoreAttrNamePrefix?: string | string[];
5
5
  };
6
6
  declare type Rule = {
7
- enum: string[];
7
+ enum: [string, ...string[]];
8
8
  } | {
9
9
  pattern: string;
10
10
  } | {
11
11
  type: AttributeType;
12
+ } | {
13
+ disallowed: true;
12
14
  };
13
- declare const _default: import("@markuplint/ml-core").RuleSeed<true, Option>;
15
+ declare const _default: import("@markuplint/ml-core").RuleSeed<boolean, Option>;
14
16
  export default _default;
@@ -2,13 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const ml_core_1 = require("@markuplint/ml-core");
4
4
  const attr_check_1 = require("../attr-check");
5
+ const debug_1 = require("../debug");
5
6
  const helpers_1 = require("../helpers");
7
+ const log = debug_1.log.extend('invalid-attr');
6
8
  exports.default = (0, ml_core_1.createRule)({
7
- defaultValue: true,
8
9
  defaultOptions: {},
9
10
  async verify({ document, report, t }) {
10
11
  await document.walkOn('Element', async (node) => {
11
- const attrSpecs = (0, helpers_1.getAttrSpecs)(node.nameWithNS, document.specs);
12
+ var _a, _b, _c, _d, _e, _f, _g, _h;
13
+ const attrSpecs = (0, ml_core_1.getAttrSpecs)(node.nameWithNS, document.specs);
12
14
  for (const attr of node.attributes) {
13
15
  if (attr.attrType === 'html-attr' && attr.isDirective) {
14
16
  continue;
@@ -16,7 +18,7 @@ exports.default = (0, ml_core_1.createRule)({
16
18
  const attrName = attr.getName();
17
19
  const name = attrName.potential;
18
20
  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') +
21
+ const message = t('{0} is {1:c}', t('the "{0*}" {1}', attrName.raw, 'attribute'), 'disallowed') +
20
22
  t('. ') +
21
23
  t('Did you mean "{0}"?', attr.candidate);
22
24
  report({
@@ -29,7 +31,7 @@ exports.default = (0, ml_core_1.createRule)({
29
31
  continue;
30
32
  }
31
33
  const attrValue = attr.getValue();
32
- const value = attrValue.raw;
34
+ const value = attrValue.potential;
33
35
  if (node.rule.option.ignoreAttrNamePrefix) {
34
36
  const ignoreAttrNamePrefixes = Array.isArray(node.rule.option.ignoreAttrNamePrefix)
35
37
  ? node.rule.option.ignoreAttrNamePrefix
@@ -41,6 +43,9 @@ exports.default = (0, ml_core_1.createRule)({
41
43
  let invalid = false;
42
44
  const customRule = node.rule.option.attrs ? node.rule.option.attrs[name] : null;
43
45
  if (customRule) {
46
+ if (attr.attrType === 'html-attr' && attr.isDynamicValue) {
47
+ continue;
48
+ }
44
49
  if ('enum' in customRule) {
45
50
  invalid = (0, attr_check_1.attrCheck)(t, name.toLowerCase(), value, true, {
46
51
  name,
@@ -54,16 +59,23 @@ exports.default = (0, ml_core_1.createRule)({
54
59
  if (!(0, helpers_1.match)(value, customRule.pattern)) {
55
60
  invalid = {
56
61
  invalidType: 'invalid-value',
57
- message: t('{0} is unmatched with the below patterns: {1}', t('the "{0}" {1}', name, 'attribute'), customRule.pattern),
62
+ message: t('{0} is unmatched with the below patterns: {1}', t('the "{0*}" {1}', name, 'attribute'), customRule.pattern),
58
63
  };
59
64
  }
60
65
  }
61
66
  else if ('type' in customRule) {
62
67
  invalid = (0, attr_check_1.attrCheck)(t, name, value, true, { name, type: customRule.type, description: '' });
63
68
  }
69
+ else if ('disallowed' in customRule && customRule.disallowed) {
70
+ invalid = {
71
+ invalidType: 'non-existent',
72
+ message: t('{0} is disallowed', t('the "{0*}" {1}', name, 'attribute')),
73
+ };
74
+ }
64
75
  }
65
76
  else if (!node.isCustomElement && attrSpecs) {
66
- invalid = (0, helpers_1.isValidAttr)(t, name, value, (attr.attrType === 'html-attr' && attr.isDynamicValue) || false, node, attrSpecs);
77
+ log('Checking %s[%s="%s"]', node.nodeName, name, value);
78
+ invalid = (0, helpers_1.isValidAttr)(t, name, value, (attr.attrType === 'html-attr' && attr.isDynamicValue) || false, node, attrSpecs, log);
67
79
  }
68
80
  if (invalid) {
69
81
  switch (invalid.invalidType) {
@@ -71,13 +83,17 @@ exports.default = (0, ml_core_1.createRule)({
71
83
  report({
72
84
  scope: node,
73
85
  message: invalid.message,
74
- line: attrValue.line,
75
- col: attrValue.col,
76
- raw: value,
86
+ line: attrValue.line + ((_b = (_a = invalid.loc) === null || _a === void 0 ? void 0 : _a.line) !== null && _b !== void 0 ? _b : 0),
87
+ col: ((_c = invalid.loc) === null || _c === void 0 ? void 0 : _c.line) ? ((_d = invalid.loc) === null || _d === void 0 ? void 0 : _d.col) + 1 : attrValue.col + ((_f = (_e = invalid.loc) === null || _e === void 0 ? void 0 : _e.col) !== null && _f !== void 0 ? _f : 0),
88
+ raw: (_h = (_g = invalid.loc) === null || _g === void 0 ? void 0 : _g.raw) !== null && _h !== void 0 ? _h : value,
77
89
  });
78
90
  break;
79
91
  }
80
92
  case 'non-existent': {
93
+ const spec = (0, helpers_1.htmlSpec)(document.specs, node.nameWithNS);
94
+ if (spec === null || spec === void 0 ? void 0 : spec.possibleToAddProperties) {
95
+ continue;
96
+ }
81
97
  report({
82
98
  scope: node,
83
99
  message: invalid.message,
@@ -13,7 +13,6 @@ const selectors = {
13
13
  const topLevelRoles = ['banner', 'main', 'complementary', 'contentinfo'];
14
14
  exports.default = (0, ml_core_1.createRule)({
15
15
  defaultServerity: 'warning',
16
- defaultValue: true,
17
16
  defaultOptions: {
18
17
  ignoreRoles: [],
19
18
  labelEachArea: true,
@@ -79,7 +78,7 @@ exports.default = (0, ml_core_1.createRule)({
79
78
  if (el.isDescendantByUUIDList(uuidList)) {
80
79
  report({
81
80
  scope: el,
82
- message: t('{0} should be {1}', t('the "{0}" {1}', role, 'role'), 'top level'),
81
+ message: t('{0} should be {1}', t('the "{0*}" {1}', role, 'role'), 'top level'),
83
82
  });
84
83
  }
85
84
  }
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, null>;
2
+ export default _default;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ml_core_1 = require("@markuplint/ml-core");
4
+ exports.default = (0, ml_core_1.createRule)({
5
+ defaultServerity: 'warning',
6
+ async verify({ document, report, t }) {
7
+ await document.walkOn('Element', el => {
8
+ const attrSpec = (0, ml_core_1.getAttrSpecs)(el.nameWithNS, document.specs);
9
+ if (!attrSpec) {
10
+ return;
11
+ }
12
+ for (const attr of el.attributes) {
13
+ if (attr.attrType === 'ps-attr' || attr.isDynamicValue) {
14
+ continue;
15
+ }
16
+ const name = attr.getName().potential;
17
+ const spec = attrSpec.find(s => s.name === name);
18
+ if (!spec) {
19
+ continue;
20
+ }
21
+ if (spec.type !== 'Boolean') {
22
+ continue;
23
+ }
24
+ const extraTokens = [
25
+ attr.spacesBeforeEqual,
26
+ attr.equal,
27
+ attr.spacesAfterEqual,
28
+ attr.startQuote,
29
+ attr.value,
30
+ attr.endQuote,
31
+ ];
32
+ const extraRaw = extraTokens.reduce((raw, t) => raw + t.raw, '');
33
+ if (extraRaw) {
34
+ report({
35
+ scope: el,
36
+ raw: extraRaw,
37
+ line: attr.spacesBeforeEqual.startLine,
38
+ col: attr.spacesBeforeEqual.startCol,
39
+ message: t('{0} is {1}', t('the "{0*}" {1}', name, 'attribute'), t('a {0}', 'boolean attribute')) +
40
+ t('. ') +
41
+ t("It doesn't need {0}", t('the {0}', 'value')),
42
+ });
43
+ }
44
+ }
45
+ });
46
+ },
47
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, null>;
2
+ export default _default;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ml_core_1 = require("@markuplint/ml-core");
4
+ const helpers_1 = require("../helpers");
5
+ exports.default = (0, ml_core_1.createRule)({
6
+ defaultServerity: 'warning',
7
+ async verify({ document, report, t }) {
8
+ await document.walkOn('Element', el => {
9
+ const attrSpec = (0, ml_core_1.getAttrSpecs)(el.nameWithNS, document.specs);
10
+ if (!attrSpec) {
11
+ return;
12
+ }
13
+ for (const attr of el.attributes) {
14
+ if (attr.attrType !== 'html-attr') {
15
+ continue;
16
+ }
17
+ const spec = attrSpec.find(s => s.name === attr.getName().potential);
18
+ if (!spec) {
19
+ continue;
20
+ }
21
+ if (!spec.defaultValue) {
22
+ continue;
23
+ }
24
+ const normalizedValue = (0, helpers_1.toNormalizedValue)(attr.getValue().potential, spec);
25
+ const defaultValue = (0, helpers_1.toNormalizedValue)(spec.defaultValue, spec);
26
+ if (defaultValue === normalizedValue) {
27
+ report({
28
+ scope: el,
29
+ line: attr.value.startLine,
30
+ col: attr.value.startCol,
31
+ raw: attr.value.raw,
32
+ message: t('It is {0}', t('the {0}', 'default value')),
33
+ });
34
+ }
35
+ }
36
+ });
37
+ },
38
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, null>;
2
+ export default _default;