@markuplint/rules 4.12.0 → 5.0.0-alpha.0

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 (83) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/lib/attr-check.d.ts +5 -2
  3. package/lib/attr-check.js +13 -3
  4. package/lib/character-reference/index.d.ts +2 -1
  5. package/lib/character-reference/index.js +5 -1
  6. package/lib/correct-aspect-ratio/index.d.ts +5 -0
  7. package/lib/correct-aspect-ratio/index.js +80 -0
  8. package/lib/correct-aspect-ratio/meta.d.ts +4 -0
  9. package/lib/correct-aspect-ratio/meta.js +3 -0
  10. package/lib/correct-aspect-ratio/resolve-image-size.d.ts +24 -0
  11. package/lib/correct-aspect-ratio/resolve-image-size.js +165 -0
  12. package/lib/create-message.d.ts +2 -2
  13. package/lib/create-message.js +4 -1
  14. package/lib/deprecated-element/index.d.ts +2 -4
  15. package/lib/deprecated-element/index.js +4 -6
  16. package/lib/end-tag/index.js +1 -1
  17. package/lib/heading-levels/index.js +0 -1
  18. package/lib/helpers.d.ts +1 -0
  19. package/lib/helpers.js +8 -15
  20. package/lib/index.d.ts +30 -41
  21. package/lib/index.js +12 -0
  22. package/lib/invalid-attr/index.d.ts +12 -28
  23. package/lib/invalid-attr/index.js +50 -116
  24. package/lib/link-types/index.d.ts +10 -0
  25. package/lib/link-types/index.js +180 -0
  26. package/lib/link-types/meta.d.ts +5 -0
  27. package/lib/link-types/meta.js +4 -0
  28. package/lib/neighbor-popovers/index.js +3 -5
  29. package/lib/no-orphaned-end-tag/index.d.ts +2 -2
  30. package/lib/no-orphaned-end-tag/index.js +3 -4
  31. package/lib/no-refer-to-non-existent-id/index.d.ts +1 -1
  32. package/lib/no-refer-to-non-existent-id/index.js +2 -2
  33. package/lib/no-unsupported-features/compat-data.d.ts +71 -0
  34. package/lib/no-unsupported-features/compat-data.js +204 -0
  35. package/lib/no-unsupported-features/index.d.ts +24 -0
  36. package/lib/no-unsupported-features/index.js +139 -0
  37. package/lib/no-unsupported-features/meta.d.ts +5 -0
  38. package/lib/no-unsupported-features/meta.js +4 -0
  39. package/lib/no-unsupported-features/resolve-browsers.d.ts +30 -0
  40. package/lib/no-unsupported-features/resolve-browsers.js +125 -0
  41. package/lib/permitted-contents/choice.js +1 -1
  42. package/lib/permitted-contents/count-pattern.js +1 -1
  43. package/lib/permitted-contents/order.js +1 -1
  44. package/lib/permitted-contents/represent-transparent-nodes.d.ts +26 -1
  45. package/lib/permitted-contents/represent-transparent-nodes.js +96 -13
  46. package/lib/permitted-contents/utils.d.ts +1 -1
  47. package/lib/permitted-contents/utils.js +22 -35
  48. package/lib/redundant-accessible-name/index.d.ts +10 -0
  49. package/lib/redundant-accessible-name/index.js +123 -0
  50. package/lib/redundant-accessible-name/meta.d.ts +5 -0
  51. package/lib/redundant-accessible-name/meta.js +4 -0
  52. package/lib/require-accessible-name/index.d.ts +3 -8
  53. package/lib/require-accessible-name/index.js +6 -5
  54. package/lib/require-dialog-autofocus/index.d.ts +22 -0
  55. package/lib/require-dialog-autofocus/index.js +62 -0
  56. package/lib/require-dialog-autofocus/meta.d.ts +5 -0
  57. package/lib/require-dialog-autofocus/meta.js +4 -0
  58. package/lib/required-attr/index.d.ts +8 -1
  59. package/lib/required-attr/index.js +27 -4
  60. package/lib/required-element/index.js +1 -1
  61. package/lib/srcset-sizes-constraint/index.d.ts +6 -0
  62. package/lib/srcset-sizes-constraint/index.js +108 -0
  63. package/lib/srcset-sizes-constraint/meta.d.ts +5 -0
  64. package/lib/srcset-sizes-constraint/meta.js +4 -0
  65. package/lib/srcset-sizes-constraint/parse-srcset.d.ts +40 -0
  66. package/lib/srcset-sizes-constraint/parse-srcset.js +56 -0
  67. package/lib/table-row-column-alignment/grid.js +22 -29
  68. package/lib/wai-aria/checkings/abstract-role.js +5 -2
  69. package/lib/wai-aria/checkings/disallowed-prop.js +5 -2
  70. package/lib/wai-aria/checkings/implicit-role.js +5 -2
  71. package/lib/wai-aria/checkings/non-existent-role.d.ts +1 -0
  72. package/lib/wai-aria/checkings/non-existent-role.js +9 -2
  73. package/lib/wai-aria/checkings/permitted-roles.js +5 -2
  74. package/lib/wai-aria/checkings/presentational-children.js +3 -2
  75. package/lib/wai-aria/checkings/required-accessibility-parent-role.d.ts +25 -0
  76. package/lib/wai-aria/checkings/required-accessibility-parent-role.js +56 -0
  77. package/lib/wai-aria/checkings/required-owned-elements.d.ts +5 -4
  78. package/lib/wai-aria/checkings/required-owned-elements.js +57 -28
  79. package/lib/wai-aria/checkings/required-prop.js +5 -2
  80. package/lib/wai-aria/index.js +12 -4
  81. package/lib/wai-aria/types.d.ts +9 -2
  82. package/package.json +15 -10
  83. package/schema.json +18 -0
package/lib/index.d.ts CHANGED
@@ -17,6 +17,9 @@ declare const rules: {
17
17
  readonly 'case-sensitive-tag-name': Readonly<import("@markuplint/ml-core").RuleSeed<import("./case-sensitive-tag-name/index.js").Value, undefined>>;
18
18
  readonly 'character-reference': Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
19
19
  readonly 'class-naming': Readonly<import("@markuplint/ml-core").RuleSeed<import("./class-naming/index.js").Value, undefined>>;
20
+ readonly 'correct-aspect-ratio': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, {
21
+ readonly documentRoot?: string;
22
+ }>>;
20
23
  readonly 'deprecated-attr': Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
21
24
  readonly 'deprecated-element': Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
22
25
  readonly 'disallowed-element': Readonly<import("@markuplint/ml-core").RuleSeed<string[], undefined>>;
@@ -30,53 +33,23 @@ declare const rules: {
30
33
  readonly 'invalid-attr': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, {
31
34
  allowAttrs?: (string | {
32
35
  name: string;
33
- value: import("packages/@markuplint/ml-spec/lib/index.js").AttributeType | ({
34
- enum: [string, ...string[]];
35
- } | {
36
- pattern: string;
37
- } | {
38
- type: import("packages/@markuplint/ml-spec/lib/index.js").AttributeType;
39
- });
40
- })[] | Record<string, {
41
- enum: [string, ...string[]];
42
- } | {
43
- pattern: string;
44
- } | {
45
- type: import("packages/@markuplint/ml-spec/lib/index.js").AttributeType;
46
- }>;
36
+ value: import("packages/@markuplint/ml-spec/lib/index.js").AttributeType | import("packages/@markuplint/types/lib/types.schema.js").Pattern;
37
+ })[] | Record<string, import("packages/@markuplint/ml-spec/lib/index.js").AttributeType | import("packages/@markuplint/types/lib/types.schema.js").Pattern>;
47
38
  disallowAttrs?: (string | {
48
39
  name: string;
49
- value: import("packages/@markuplint/ml-spec/lib/index.js").AttributeType | ({
50
- enum: [string, ...string[]];
51
- } | {
52
- pattern: string;
53
- } | {
54
- type: import("packages/@markuplint/ml-spec/lib/index.js").AttributeType;
55
- });
56
- })[] | Record<string, {
57
- enum: [string, ...string[]];
58
- } | {
59
- pattern: string;
60
- } | {
61
- type: import("packages/@markuplint/ml-spec/lib/index.js").AttributeType;
62
- }>;
40
+ value: import("packages/@markuplint/ml-spec/lib/index.js").AttributeType | import("packages/@markuplint/types/lib/types.schema.js").Pattern;
41
+ })[] | Record<string, import("packages/@markuplint/ml-spec/lib/index.js").AttributeType | import("packages/@markuplint/types/lib/types.schema.js").Pattern>;
63
42
  ignoreAttrNamePrefix?: string | string[];
64
43
  allowToAddPropertiesForPretender?: boolean;
65
- attrs?: Record<string, ({
66
- enum: [string, ...string[]];
67
- } | {
68
- pattern: string;
69
- } | {
70
- type: import("packages/@markuplint/ml-spec/lib/index.js").AttributeType;
71
- }) | {
72
- disallowed: true;
73
- }>;
74
44
  }>>;
75
45
  readonly 'label-has-control': Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
76
46
  readonly 'landmark-roles': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, {
77
47
  ignoreRoles: (("banner" | "main" | "complementary" | "contentinfo") | "form" | "navigation" | "region")[];
78
48
  labelEachArea: boolean;
79
49
  }>>;
50
+ readonly 'link-types': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, {
51
+ readonly allowMicroformats?: boolean | readonly string[];
52
+ }>>;
80
53
  readonly 'neighbor-popovers': Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
81
54
  readonly 'no-ambiguous-navigable-target-names': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, undefined>>;
82
55
  readonly 'no-boolean-attr-value': Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
@@ -90,29 +63,45 @@ declare const rules: {
90
63
  readonly 'no-hard-code-id': Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
91
64
  readonly 'no-orphaned-end-tag': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, null>>;
92
65
  readonly 'no-refer-to-non-existent-id': Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, {
93
- ariaVersion: import("packages/@markuplint/ml-spec/lib/index.js").ARIAVersion;
66
+ ariaVersion: import("packages/@markuplint/ml-spec/lib/index.js").ARIAVersion | undefined;
94
67
  fragmentRefersNameAttr: boolean;
95
68
  }>>;
69
+ readonly 'no-unsupported-features': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, {
70
+ readonly browserslist?: string | readonly string[];
71
+ readonly browserslistConfig?: string;
72
+ readonly browserslistEnv?: string;
73
+ readonly ignoreFeatures?: readonly string[];
74
+ readonly checkExperimental?: boolean;
75
+ readonly checkNonStandard?: boolean;
76
+ }>>;
96
77
  readonly 'no-use-event-handler-attr': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, {
97
78
  ignore?: string | string[];
98
79
  }>>;
99
80
  readonly 'permitted-contents': Readonly<import("@markuplint/ml-core").RuleSeed<import("./permitted-contents/types.js").TagRule[], import("./permitted-contents/types.js").Options>>;
100
81
  readonly 'placeholder-label-option': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, undefined>>;
101
- readonly 'require-accessible-name': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, {
102
- ariaVersion: import("packages/@markuplint/ml-spec/lib/index.js").ARIAVersion;
82
+ readonly 'redundant-accessible-name': Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, {
83
+ checkTitleFallback: boolean;
84
+ checkPlaceholderFallback: boolean;
85
+ }>>;
86
+ readonly 'require-accessible-name': Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, {
87
+ ariaVersion: import("packages/@markuplint/ml-spec/lib/index.js").ARIAVersion | undefined;
103
88
  }>>;
104
89
  readonly 'require-datetime': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, {
105
90
  langs?: import("./require-datetime/types.js").Lang[];
106
91
  }>>;
92
+ readonly 'require-dialog-autofocus': Readonly<import("@markuplint/ml-core").RuleSeed<import("@markuplint/ml-core").RuleConfigValue, undefined>>;
107
93
  readonly 'required-attr': Readonly<import("@markuplint/ml-core").RuleSeed<string | (string | {
108
94
  name: string;
109
95
  value?: string | string[];
110
- })[], undefined>>;
96
+ })[], {
97
+ readonly ignoreAttrs?: readonly string[];
98
+ }>>;
111
99
  readonly 'required-element': Readonly<import("@markuplint/ml-core").RuleSeed<string[], {
112
100
  ignoreHasMutableContents: boolean;
113
101
  ignoreOmittedElements: boolean;
114
102
  }>>;
115
103
  readonly 'required-h1': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, import("./required-h1/index.js").Options>>;
104
+ readonly 'srcset-sizes-constraint': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, undefined>>;
116
105
  readonly 'table-row-column-alignment': Readonly<import("@markuplint/ml-core").RuleSeed<boolean, undefined>>;
117
106
  readonly 'use-list': Readonly<import("@markuplint/ml-core").RuleSeed<readonly string[], {
118
107
  spaceNeededBullets?: string[];
package/lib/index.js CHANGED
@@ -11,6 +11,7 @@ import AttrValueQuotes from './attr-value-quotes/index.js';
11
11
  import CaseSensitiveAttrName from './case-sensitive-attr-name/index.js';
12
12
  import CaseSensitiveTagName from './case-sensitive-tag-name/index.js';
13
13
  import CharacterReference from './character-reference/index.js';
14
+ import CorrectAspectRatio from './correct-aspect-ratio/index.js';
14
15
  import ClassNaming from './class-naming/index.js';
15
16
  import DeprecatedAttr from './deprecated-attr/index.js';
16
17
  import DeprecatedElement from './deprecated-element/index.js';
@@ -23,6 +24,7 @@ import IneffectiveAttr from './ineffective-attr/index.js';
23
24
  import InvalidAttr from './invalid-attr/index.js';
24
25
  import LabelHasControl from './label-has-control/index.js';
25
26
  import LandmarkRoles from './landmark-roles/index.js';
27
+ import LinkTypes from './link-types/index.js';
26
28
  import NeighborPopovers from './neighbor-popovers/index.js';
27
29
  import NoAmbiguousNavigableTargetNames from './no-ambiguous-navigable-target-names/index.js';
28
30
  import NoBooleanAttrValue from './no-boolean-attr-value/index.js';
@@ -33,11 +35,15 @@ import NoEmptyPalpableContent from './no-empty-palpable-content/index.js';
33
35
  import NoHardCodeId from './no-hard-code-id/index.js';
34
36
  import NoOrphanedEndTag from './no-orphaned-end-tag/index.js';
35
37
  import NoReferToNonExistentId from './no-refer-to-non-existent-id/index.js';
38
+ import NoUnsupportedFeatures from './no-unsupported-features/index.js';
36
39
  import NoUseEventHandlerAttr from './no-use-event-handler-attr/index.js';
37
40
  import PermittedContents from './permitted-contents/index.js';
38
41
  import PlaceholderLabelOption from './placeholder-label-option/index.js';
42
+ import RedundantAccessibleName from './redundant-accessible-name/index.js';
39
43
  import RequireAccessibleName from './require-accessible-name/index.js';
40
44
  import RequireDatetime from './require-datetime/index.js';
45
+ import RequireDialogAutofocus from './require-dialog-autofocus/index.js';
46
+ import SrcsetSizesConstraint from './srcset-sizes-constraint/index.js';
41
47
  import RequiredAttr from './required-attr/index.js';
42
48
  import RequiredElement from './required-element/index.js';
43
49
  import RequiredH1 from './required-h1/index.js';
@@ -55,6 +61,7 @@ const rules = {
55
61
  'case-sensitive-tag-name': CaseSensitiveTagName,
56
62
  'character-reference': CharacterReference,
57
63
  'class-naming': ClassNaming,
64
+ 'correct-aspect-ratio': CorrectAspectRatio,
58
65
  'deprecated-attr': DeprecatedAttr,
59
66
  'deprecated-element': DeprecatedElement,
60
67
  'disallowed-element': DisallowedElement,
@@ -66,6 +73,7 @@ const rules = {
66
73
  'invalid-attr': InvalidAttr,
67
74
  'label-has-control': LabelHasControl,
68
75
  'landmark-roles': LandmarkRoles,
76
+ 'link-types': LinkTypes,
69
77
  'neighbor-popovers': NeighborPopovers,
70
78
  'no-ambiguous-navigable-target-names': NoAmbiguousNavigableTargetNames,
71
79
  'no-boolean-attr-value': NoBooleanAttrValue,
@@ -76,14 +84,18 @@ const rules = {
76
84
  'no-hard-code-id': NoHardCodeId,
77
85
  'no-orphaned-end-tag': NoOrphanedEndTag,
78
86
  'no-refer-to-non-existent-id': NoReferToNonExistentId,
87
+ 'no-unsupported-features': NoUnsupportedFeatures,
79
88
  'no-use-event-handler-attr': NoUseEventHandlerAttr,
80
89
  'permitted-contents': PermittedContents,
81
90
  'placeholder-label-option': PlaceholderLabelOption,
91
+ 'redundant-accessible-name': RedundantAccessibleName,
82
92
  'require-accessible-name': RequireAccessibleName,
83
93
  'require-datetime': RequireDatetime,
94
+ 'require-dialog-autofocus': RequireDialogAutofocus,
84
95
  'required-attr': RequiredAttr,
85
96
  'required-element': RequiredElement,
86
97
  'required-h1': RequiredH1,
98
+ 'srcset-sizes-constraint': SrcsetSizesConstraint,
87
99
  'table-row-column-alignment': TableRowColumnAlignment,
88
100
  'use-list': UseList,
89
101
  'wai-aria': WaiAria,
@@ -1,31 +1,26 @@
1
1
  import type { AttributeType } from '@markuplint/ml-spec';
2
+ import type { Pattern } from '@markuplint/types';
2
3
  /**
3
4
  * Configuration options for the `invalid-attr` rule.
4
5
  */
5
6
  type Option = {
6
7
  /**
8
+ * Attributes to allow beyond what the spec permits.
9
+ * Can override spec-level restrictions such as `noUse`.
10
+ *
7
11
  * @since 3.7.0
8
12
  */
9
- allowAttrs?: (string | Attr)[] | Record<string, ValueRule>;
13
+ allowAttrs?: (string | Attr)[] | Record<string, AttributeType | Pattern>;
10
14
  /**
15
+ * Attributes to disallow in addition to spec restrictions.
16
+ *
11
17
  * @since 3.7.0
12
18
  */
13
- disallowAttrs?: (string | Attr)[] | Record<string, ValueRule>;
19
+ disallowAttrs?: (string | Attr)[] | Record<string, AttributeType | Pattern>;
14
20
  /** Attribute name prefix(es) to ignore during validation. */
15
21
  ignoreAttrNamePrefix?: string | string[];
16
22
  /** Whether to allow additional properties for pretender elements (defaults to `true`). */
17
23
  allowToAddPropertiesForPretender?: boolean;
18
- /**
19
- * @deprecated Since version 3.7.0. Use `allowAttrs` or `disallowAttrs` instead.
20
- * This option (`attr`) is now considered ambiguous and may lead to confusion.
21
- * Please use the more explicit `allowAttrs` or `disallowAttrs` option
22
- * to specify allowed attributes for the `invalid-attr` rule.
23
- * @see {@link Option.allowAttrs}
24
- * @see {@link Option.disallowAttrs}
25
- */
26
- attrs?: Record<string, ValueRule | {
27
- disallowed: true;
28
- }>;
29
24
  };
30
25
  /**
31
26
  * Describes a single attribute with its name and expected value constraint.
@@ -34,18 +29,7 @@ type Attr = {
34
29
  /** The attribute name. */
35
30
  name: string;
36
31
  /** The expected attribute value type or validation rule. */
37
- value: AttributeType | ValueRule;
38
- };
39
- /**
40
- * A validation constraint for an attribute value, defined as either an
41
- * enumerated list, a regex pattern, or a spec-based type.
42
- */
43
- type ValueRule = {
44
- enum: [string, ...string[]];
45
- } | {
46
- pattern: string;
47
- } | {
48
- type: AttributeType;
32
+ value: AttributeType | Pattern;
49
33
  };
50
34
  /**
51
35
  * Rule that validates attributes against the HTML spec, allowed lists,
@@ -53,9 +37,9 @@ type ValueRule = {
53
37
  *
54
38
  * Checks each attribute for: existence in the spec, correct value type,
55
39
  * allowed/disallowed overrides from configuration, and typo suggestions
56
- * via candidate matching. Supports `allowAttrs`, `disallowAttrs`, and
57
- * the deprecated `attrs` option. Non-existent attributes on elements that
58
- * allow additional properties (pretenders) can be optionally permitted.
40
+ * via candidate matching. Supports `allowAttrs` and `disallowAttrs`.
41
+ * Non-existent attributes on elements that allow additional properties
42
+ * (pretenders) can be optionally permitted.
59
43
  */
60
44
  declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<boolean, Option>>;
61
45
  export default _default;
@@ -1,7 +1,8 @@
1
1
  import { createRule, getAttrSpecs, getSpec } from '@markuplint/ml-core';
2
+ import { check, isEnum, isPattern } from '@markuplint/types';
2
3
  import { attrCheck } from '../attr-check.js';
3
4
  import { log as ruleLog } from '../debug.js';
4
- import { isValidAttr, match } from '../helpers.js';
5
+ import { isValidAttr } from '../helpers.js';
5
6
  import meta from './meta.js';
6
7
  const log = ruleLog.extend('invalid-attr');
7
8
  /**
@@ -10,9 +11,9 @@ const log = ruleLog.extend('invalid-attr');
10
11
  *
11
12
  * Checks each attribute for: existence in the spec, correct value type,
12
13
  * allowed/disallowed overrides from configuration, and typo suggestions
13
- * via candidate matching. Supports `allowAttrs`, `disallowAttrs`, and
14
- * the deprecated `attrs` option. Non-existent attributes on elements that
15
- * allow additional properties (pretenders) can be optionally permitted.
14
+ * via candidate matching. Supports `allowAttrs` and `disallowAttrs`.
15
+ * Non-existent attributes on elements that allow additional properties
16
+ * (pretenders) can be optionally permitted.
16
17
  */
17
18
  export default createRule({
18
19
  meta: meta,
@@ -57,19 +58,15 @@ export default createRule({
57
58
  if (Array.isArray(attr.rule.options.allowAttrs)) {
58
59
  for (const allowAttr of attr.rule.options.allowAttrs) {
59
60
  if (typeof allowAttr === 'string') {
60
- allowAttrs[allowAttr] = { type: 'Any' };
61
+ allowAttrs[allowAttr] = 'Any';
61
62
  continue;
62
63
  }
63
- if (isValueRule(allowAttr.value)) {
64
- allowAttrs[allowAttr.name] = allowAttr.value;
65
- continue;
66
- }
67
- allowAttrs[allowAttr.name] = { type: allowAttr.value };
64
+ allowAttrs[allowAttr.name] = allowAttr.value;
68
65
  }
69
66
  }
70
67
  else {
71
- for (const [attrName, valueRule] of Object.entries(attr.rule.options.allowAttrs)) {
72
- allowAttrs[attrName] = valueRule;
68
+ for (const [attrName, attrType] of Object.entries(attr.rule.options.allowAttrs)) {
69
+ allowAttrs[attrName] = attrType;
73
70
  }
74
71
  }
75
72
  }
@@ -77,99 +74,50 @@ export default createRule({
77
74
  if (Array.isArray(attr.rule.options.disallowAttrs)) {
78
75
  for (const disallowAttr of attr.rule.options.disallowAttrs) {
79
76
  if (typeof disallowAttr === 'string') {
80
- disallowAttrs[disallowAttr] = { type: 'Any' };
77
+ disallowAttrs[disallowAttr] = 'Any';
81
78
  continue;
82
79
  }
83
- if (isValueRule(disallowAttr.value)) {
84
- disallowAttrs[disallowAttr.name] = disallowAttr.value;
85
- continue;
86
- }
87
- disallowAttrs[disallowAttr.name] = { type: disallowAttr.value };
80
+ disallowAttrs[disallowAttr.name] = disallowAttr.value;
88
81
  }
89
82
  }
90
83
  else {
91
- for (const [attrName, valueRule] of Object.entries(attr.rule.options.disallowAttrs)) {
92
- disallowAttrs[attrName] = valueRule;
93
- }
94
- }
95
- }
96
- if (attr.rule.options.attrs) {
97
- for (const [attrName, valueRule] of Object.entries(attr.rule.options.attrs)) {
98
- if ('disallowed' in valueRule) {
99
- disallowAttrs[attrName] = { type: 'Any' };
100
- }
101
- else {
102
- allowAttrs[attrName] = valueRule;
84
+ for (const [attrName, attrType] of Object.entries(attr.rule.options.disallowAttrs)) {
85
+ disallowAttrs[attrName] = attrType;
103
86
  }
104
87
  }
105
88
  }
106
89
  const allowValue = allowAttrs[name] ?? null;
107
90
  const disallowValue = disallowAttrs[name] ?? null;
108
- if (allowValue) {
109
- if ('enum' in allowValue) {
110
- invalid = attrCheck(t, name.toLowerCase(), value, true, {
111
- name,
112
- type: {
113
- enum: allowValue.enum,
114
- },
115
- description: '',
116
- });
117
- }
118
- else if ('pattern' in allowValue) {
119
- if (!match(value, allowValue.pattern)) {
120
- invalid = {
121
- invalidType: 'invalid-value',
122
- message: t('{0} is unmatched with the below patterns: {1}', t('the "{0*}" {1}', name, 'attribute'), allowValue.pattern),
123
- };
124
- }
125
- }
126
- else if ('type' in allowValue) {
127
- invalid = attrCheck(t, name, value, true, { name, type: allowValue.type, description: '' });
128
- }
91
+ if (allowValue !== null) {
92
+ invalid = attrCheck(t, name, value, true, {
93
+ name,
94
+ type: allowValue,
95
+ description: '',
96
+ });
129
97
  }
130
- else if (disallowValue) {
131
- if ('enum' in disallowValue) {
132
- const checkResult = attrCheck(t, name.toLowerCase(), value, true, {
133
- name,
134
- type: {
135
- enum: disallowValue.enum,
136
- },
137
- description: '',
138
- });
139
- if (checkResult === false) {
140
- invalid = {
141
- invalidType: 'invalid-value',
142
- message: t('{0} is disallowed to accept the following values: {1}', t('the "{0*}" {1}', name, 'attribute'), t(disallowValue.enum)),
143
- };
144
- }
98
+ else if (disallowValue !== null) {
99
+ if (disallowValue === 'Any') {
100
+ invalid = {
101
+ invalidType: 'non-existent',
102
+ message: t('{0} is disallowed', t('the "{0*}" {1}', name, 'attribute')),
103
+ };
145
104
  }
146
- else if ('pattern' in disallowValue) {
147
- if (match(value, disallowValue.pattern)) {
148
- invalid = {
149
- invalidType: 'invalid-value',
150
- message: t('{0} is matched with the below disallowed patterns: {1}', t('the "{0*}" {1}', name, 'attribute'), disallowValue.pattern),
151
- };
152
- }
153
- }
154
- else if ('type' in disallowValue) {
155
- if (disallowValue.type === 'Any') {
156
- invalid = {
157
- invalidType: 'non-existent',
158
- message: t('{0} is disallowed', t('the "{0*}" {1}', name, 'attribute')),
159
- };
160
- }
161
- else {
162
- const checkResult = attrCheck(t, name, value, true, {
105
+ else {
106
+ const checkResult = isPattern(disallowValue)
107
+ ? check(value, disallowValue)
108
+ : attrCheck(t, name, value, true, {
163
109
  name,
164
- type: disallowValue.type,
110
+ type: disallowValue,
165
111
  description: '',
166
112
  });
167
- if (checkResult === false) {
168
- invalid = {
169
- invalidType: 'invalid-value',
170
- message: t('{0} is disallowed', t('{0} of {1}', t('the {0}', 'type'), t('the "{0*}" {1}', name, 'attribute'))),
171
- };
172
- }
113
+ const isMatched = isPattern(disallowValue)
114
+ ? checkResult.matched
115
+ : checkResult === false;
116
+ if (isMatched) {
117
+ invalid = {
118
+ invalidType: 'invalid-value',
119
+ message: createDisallowMessage(t, name, disallowValue),
120
+ };
173
121
  }
174
122
  }
175
123
  }
@@ -227,35 +175,21 @@ export default createRule({
227
175
  },
228
176
  });
229
177
  /**
230
- * Determines whether the given value is a {@link ValueRule} (enum, pattern,
231
- * or simple type constraint) as opposed to a raw {@link AttributeType}.
178
+ * Creates an appropriate disallow message based on the type structure.
232
179
  *
233
- * @param value - The value to inspect.
234
- * @returns `true` if the value is a {@link ValueRule}, `false` otherwise.
180
+ * @param t - The i18n translator
181
+ * @param name - The attribute name
182
+ * @param type - The attribute type or pattern
183
+ * @returns A localized message string
235
184
  */
236
- function isValueRule(
185
+ function createDisallowMessage(t, name,
237
186
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
238
- value) {
239
- if (typeof value === 'string') {
240
- return false;
241
- }
242
- if ('enum' in value) {
243
- if (Object.keys(value).length > 1) {
244
- return false;
245
- }
246
- return true;
247
- }
248
- if ('token' in value) {
249
- return false;
250
- }
251
- if ('pattern' in value) {
252
- return true;
253
- }
254
- if (value.type === 'integer' || value.type === 'float') {
255
- return false;
187
+ type) {
188
+ if (isPattern(type)) {
189
+ return t('{0} is matched with the below disallowed patterns: {1}', t('the "{0*}" {1}', name, 'attribute'), type.pattern);
256
190
  }
257
- if (Object.keys(value).length > 1) {
258
- return false;
191
+ if (typeof type !== 'string' && isEnum(type)) {
192
+ return t('{0} is disallowed to accept the following values: {1}', t('the "{0*}" {1}', name, 'attribute'), t(type.enum));
259
193
  }
260
- return true;
194
+ return t('{0} is disallowed', t('{0} of {1}', t('the {0}', 'type'), t('the "{0*}" {1}', name, 'attribute')));
261
195
  }
@@ -0,0 +1,10 @@
1
+ type Options = {
2
+ readonly allowMicroformats?: boolean | readonly string[];
3
+ };
4
+ /**
5
+ * Rule that validates link type keywords in the `rel` attribute on
6
+ * `<link>`, `<a>`, `<area>`, and `<form>` elements against the WHATWG
7
+ * standard and optionally the Microformats registry.
8
+ */
9
+ declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<boolean, Options>>;
10
+ export default _default;