testaro-issues 0.4.0 → 0.5.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.
package/dist/index.cjs CHANGED
@@ -1,5 +1,20 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/index.ts
3
+ const outcomes = ["failed", "cantTell"];
4
+ const uncertainties = [
5
+ "not-computable",
6
+ "judgement-required",
7
+ "runtime-dependent",
8
+ "spec-only",
9
+ "equivalence-unknown",
10
+ "out-of-scope"
11
+ ];
12
+ const whyIgnore = [
13
+ "invalid",
14
+ "irrelevant",
15
+ "duplicative",
16
+ "unreliable"
17
+ ];
3
18
  const issuesData = {
4
19
  "ignorable": {
5
20
  "summary": "ignorable",
@@ -2245,7 +2260,8 @@ const rulesData = {
2245
2260
  "cantTellTextContrast": {
2246
2261
  "issueID": "ignorable",
2247
2262
  "quality": 1,
2248
- "what": "Test of text contrast could not give a conclusive result [invalid]"
2263
+ "what": "Test of text contrast could not give a conclusive result [invalid]",
2264
+ "supersededBy": null
2249
2265
  },
2250
2266
  "r73": {
2251
2267
  "issueID": "ignorable",
@@ -2560,7 +2576,8 @@ const rulesData = {
2560
2576
  "cantTell": {
2561
2577
  "issueID": "notValidatable",
2562
2578
  "quality": 1,
2563
- "what": "Test could not give a conclusive result"
2579
+ "what": "Test could not give a conclusive result",
2580
+ "supersededBy": "r66"
2564
2581
  }
2565
2582
  },
2566
2583
  "variable": {}
@@ -3880,7 +3897,8 @@ const rulesData = {
3880
3897
  "E-AAA.4_1_1.F77": {
3881
3898
  "issueID": "duplicateID",
3882
3899
  "quality": 1,
3883
- "what": "Duplicate id attribute value"
3900
+ "what": "Duplicate id attribute value",
3901
+ "supersededBy": "E-WCAG2AAA.Principle4.Guideline4_1.4_1_1.F77"
3884
3902
  },
3885
3903
  "E-WCAG2AAA.Principle4.Guideline4_1.4_1_1.F77": {
3886
3904
  "issueID": "duplicateID",
@@ -3930,7 +3948,8 @@ const rulesData = {
3930
3948
  "E-H36": {
3931
3949
  "issueID": "imageButtonNoText",
3932
3950
  "quality": 1,
3933
- "what": "Image submit button has no alt attribute"
3951
+ "what": "Image submit button has no alt attribute",
3952
+ "supersededBy": "E-AAA.1_1_1.H36"
3934
3953
  },
3935
3954
  "E-AAA.1_1_1.H36": {
3936
3955
  "issueID": "imageButtonNoText",
@@ -3945,7 +3964,8 @@ const rulesData = {
3945
3964
  "E-AAA.1_1_1.H37": {
3946
3965
  "issueID": "imageNoText",
3947
3966
  "quality": 1,
3948
- "what": "img element has no alt attribute"
3967
+ "what": "img element has no alt attribute",
3968
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_1.1_1_1.H37"
3949
3969
  },
3950
3970
  "E-WCAG2AAA.Principle1.Guideline1_1.1_1_1.H37": {
3951
3971
  "issueID": "imageNoText",
@@ -3970,7 +3990,8 @@ const rulesData = {
3970
3990
  "E-AAA.3_1_1.H57.2": {
3971
3991
  "issueID": "pageLanguage",
3972
3992
  "quality": 1,
3973
- "what": "html element has no lang or xml:lang attribute"
3993
+ "what": "html element has no lang or xml:lang attribute",
3994
+ "supersededBy": "E-WCAG2AAA.Principle3.Guideline3_1.3_1_1.H57.2"
3974
3995
  },
3975
3996
  "E-WCAG2AAA.Principle3.Guideline3_1.3_1_1.H57.2": {
3976
3997
  "issueID": "pageLanguage",
@@ -4015,7 +4036,8 @@ const rulesData = {
4015
4036
  "W-AAA.2_1_1.G90": {
4016
4037
  "issueID": "eventKeyboardRisk",
4017
4038
  "quality": 1,
4018
- "what": "Event handler functionality is not available by keyboard?"
4039
+ "what": "Event handler functionality is not available by keyboard?",
4040
+ "supersededBy": "W-WCAG2AAA.Principle2.Guideline2_1.2_1_1.G90"
4019
4041
  },
4020
4042
  "W-WCAG2AAA.Principle2.Guideline2_1.2_1_1.G90": {
4021
4043
  "issueID": "eventKeyboardRisk",
@@ -4025,7 +4047,8 @@ const rulesData = {
4025
4047
  "W-AAA.2_1_1.SCR20.MouseOut": {
4026
4048
  "issueID": "eventKeyboardRisk",
4027
4049
  "quality": 1,
4028
- "what": "Mousing-out functionality is not available by keyboard?"
4050
+ "what": "Mousing-out functionality is not available by keyboard?",
4051
+ "supersededBy": "W-WCAG2AAA.Principle2.Guideline2_1.2_1_1.SCR20.MouseOut"
4029
4052
  },
4030
4053
  "W-WCAG2AAA.Principle2.Guideline2_1.2_1_1.SCR20.MouseOut": {
4031
4054
  "issueID": "eventKeyboardRisk",
@@ -4035,7 +4058,8 @@ const rulesData = {
4035
4058
  "W-AAA.2_1_1.SCR20.MouseOver": {
4036
4059
  "issueID": "eventKeyboardRisk",
4037
4060
  "quality": 1,
4038
- "what": "Mousing-over functionality is not available by keyboard?"
4061
+ "what": "Mousing-over functionality is not available by keyboard?",
4062
+ "supersededBy": "W-WCAG2AAA.Principle2.Guideline2_1.2_1_1.SCR20.MouseOver"
4039
4063
  },
4040
4064
  "W-WCAG2AAA.Principle2.Guideline2_1.2_1_1.SCR20.MouseOver": {
4041
4065
  "issueID": "eventKeyboardRisk",
@@ -4055,7 +4079,8 @@ const rulesData = {
4055
4079
  "E-AAA.2_4_1.G1,G123,G124.NoSuchID": {
4056
4080
  "issueID": "internalLinkBroken",
4057
4081
  "quality": 1,
4058
- "what": "Internal link references a nonexistent destination"
4082
+ "what": "Internal link references a nonexistent destination",
4083
+ "supersededBy": "E-WCAG2AAA.Principle2.Guideline2_4.2_4_1.G1,G123,G124.NoSuchID"
4059
4084
  },
4060
4085
  "E-WCAG2AAA.Principle2.Guideline2_4.2_4_1.G1,G123,G124.NoSuchID": {
4061
4086
  "issueID": "internalLinkBroken",
@@ -4080,7 +4105,8 @@ const rulesData = {
4080
4105
  "E-AAA.1_3_1.ARIA16,ARIA9": {
4081
4106
  "issueID": "labelBadID",
4082
4107
  "quality": 1,
4083
- "what": "aria-labelledby attribute references a nonexistent element"
4108
+ "what": "aria-labelledby attribute references a nonexistent element",
4109
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.ARIA16,ARIA9"
4084
4110
  },
4085
4111
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.ARIA16,ARIA9": {
4086
4112
  "issueID": "labelBadID",
@@ -4095,7 +4121,8 @@ const rulesData = {
4095
4121
  "E-AAA.4_1_2.H91.A.Empty": {
4096
4122
  "issueID": "linkNoText",
4097
4123
  "quality": 1,
4098
- "what": "a element has an id attribute but no href attribute or text"
4124
+ "what": "a element has an id attribute but no href attribute or text",
4125
+ "supersededBy": "W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.A.Empty"
4099
4126
  },
4100
4127
  "W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.A.Empty": {
4101
4128
  "issueID": "linkNoText",
@@ -4105,7 +4132,8 @@ const rulesData = {
4105
4132
  "E-AAA.4_1_2.H91.A.EmptyNoId": {
4106
4133
  "issueID": "linkNoText",
4107
4134
  "quality": 1,
4108
- "what": "Link has no name or id attribute or value"
4135
+ "what": "Link has no name or id attribute or value",
4136
+ "supersededBy": "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.A.EmptyNoId"
4109
4137
  },
4110
4138
  "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.A.EmptyNoId": {
4111
4139
  "issueID": "linkNoText",
@@ -4130,7 +4158,8 @@ const rulesData = {
4130
4158
  "E-AAA.1_1_1.H30.2": {
4131
4159
  "issueID": "imageLinkNoText",
4132
4160
  "quality": 1,
4133
- "what": "img element is the only link content but has no text alternative"
4161
+ "what": "img element is the only link content but has no text alternative",
4162
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_1.1_1_1.H30.2"
4134
4163
  },
4135
4164
  "E-WCAG2AAA.Principle1.Guideline1_1.1_1_1.H30.2": {
4136
4165
  "issueID": "imageLinkNoText",
@@ -4140,7 +4169,8 @@ const rulesData = {
4140
4169
  "E-AAA.4_1_2.H91.A.Placeholder": {
4141
4170
  "issueID": "linkBrokenRisk",
4142
4171
  "quality": 1,
4143
- "what": "Link has text but no href, id, or name attribute"
4172
+ "what": "Link has text but no href, id, or name attribute",
4173
+ "supersededBy": "W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.A.Placeholder"
4144
4174
  },
4145
4175
  "W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.A.Placeholder": {
4146
4176
  "issueID": "linkBrokenRisk",
@@ -4150,7 +4180,8 @@ const rulesData = {
4150
4180
  "E-AAA.2_4_8.H59.2b": {
4151
4181
  "issueID": "linkElNoHref",
4152
4182
  "quality": 1,
4153
- "what": "link element is missing a non-empty href for the linked resource"
4183
+ "what": "link element is missing a non-empty href for the linked resource",
4184
+ "supersededBy": "E-WCAG2AAA.Principle2.Guideline2_4.2_4_8.H59.2b"
4154
4185
  },
4155
4186
  "E-WCAG2AAA.Principle2.Guideline2_4.2_4_8.H59.2b": {
4156
4187
  "issueID": "linkElNoHref",
@@ -4170,7 +4201,8 @@ const rulesData = {
4170
4201
  "E-AAA.4_1_2.H91.Textarea.Name": {
4171
4202
  "issueID": "textAreaNoText",
4172
4203
  "quality": 1,
4173
- "what": "textarea element has no accessible name"
4204
+ "what": "textarea element has no accessible name",
4205
+ "supersededBy": "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Textarea.Name"
4174
4206
  },
4175
4207
  "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Textarea.Name": {
4176
4208
  "issueID": "textAreaNoText",
@@ -4180,7 +4212,8 @@ const rulesData = {
4180
4212
  "E-AAA.1_1_1.H2.EG3": {
4181
4213
  "issueID": "linkAltSame",
4182
4214
  "quality": 1,
4183
- "what": "alt value of the link img element duplicates the text of a link beside it"
4215
+ "what": "alt value of the link img element duplicates the text of a link beside it",
4216
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_1.1_1_1.H2.EG3"
4184
4217
  },
4185
4218
  "E-WCAG2AAA.Principle1.Guideline1_1.1_1_1.H2.EG3": {
4186
4219
  "issueID": "linkAltSame",
@@ -4210,7 +4243,8 @@ const rulesData = {
4210
4243
  "E-AAA.4_1_2.H91.Div.Name": {
4211
4244
  "issueID": "buttonNoText",
4212
4245
  "quality": 1,
4213
- "what": "div element with button role has no accessible name"
4246
+ "what": "div element with button role has no accessible name",
4247
+ "supersededBy": "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Div.Name"
4214
4248
  },
4215
4249
  "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Div.Name": {
4216
4250
  "issueID": "buttonNoText",
@@ -4245,7 +4279,8 @@ const rulesData = {
4245
4279
  "E-AAA.1_3_1.F92,ARIA4": {
4246
4280
  "issueID": "presentationChild",
4247
4281
  "quality": 1,
4248
- "what": "Element has presentation role but semantic child"
4282
+ "what": "Element has presentation role but semantic child",
4283
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.F92,ARIA4"
4249
4284
  },
4250
4285
  "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.F92,ARIA4": {
4251
4286
  "issueID": "presentationChild",
@@ -4265,7 +4300,8 @@ const rulesData = {
4265
4300
  "E-AAA.2_4_8.H59.2a": {
4266
4301
  "issueID": "linkElementBad",
4267
4302
  "quality": 1,
4268
- "what": "Element has no nonempty rel attribute for the type"
4303
+ "what": "Element has no nonempty rel attribute for the type",
4304
+ "supersededBy": "E-WCAG2AAA.Principle2.Guideline2_4.2_4_8.H59.2a"
4269
4305
  },
4270
4306
  "E-WCAG2AAA.Principle2.Guideline2_4.2_4_8.H59.2a": {
4271
4307
  "issueID": "linkElementBad",
@@ -4290,7 +4326,8 @@ const rulesData = {
4290
4326
  "E-AAA.1_3_5.H98": {
4291
4327
  "issueID": "autocompleteBad",
4292
4328
  "quality": 1,
4293
- "what": "autocomplete attribute and the input type are mismatched"
4329
+ "what": "autocomplete attribute and the input type are mismatched",
4330
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_3.1_3_5.H98"
4294
4331
  },
4295
4332
  "E-WCAG2AAA.Principle1.Guideline1_3.1_3_5.H98": {
4296
4333
  "issueID": "autocompleteBad",
@@ -4315,7 +4352,8 @@ const rulesData = {
4315
4352
  "E-AAA.1_4_6.G18.Fail": {
4316
4353
  "issueID": "contrastAA",
4317
4354
  "quality": 1,
4318
- "what": "Contrast between the text and its background is less than 4.5:1"
4355
+ "what": "Contrast between the text and its background is less than 4.5:1",
4356
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_4.1_4_6.G18.Fail"
4319
4357
  },
4320
4358
  "E-WCAG2AAA.Principle1.Guideline1_4.1_4_6.G18.Fail": {
4321
4359
  "issueID": "contrastAA",
@@ -4430,7 +4468,8 @@ const rulesData = {
4430
4468
  "E-AAA.1_3_1.H42.2": {
4431
4469
  "issueID": "headingEmpty",
4432
4470
  "quality": 1,
4433
- "what": "Heading is empty"
4471
+ "what": "Heading is empty",
4472
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H42.2"
4434
4473
  },
4435
4474
  "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H42.2": {
4436
4475
  "issueID": "headingEmpty",
@@ -4450,7 +4489,8 @@ const rulesData = {
4450
4489
  "W-AAA.1_3_1.H65": {
4451
4490
  "issueID": "titleEmpty",
4452
4491
  "quality": .5,
4453
- "what": "title attribute of the form control is empty or only whitespace"
4492
+ "what": "title attribute of the form control is empty or only whitespace",
4493
+ "supersededBy": "W-AAA.4_1_2.H65"
4454
4494
  },
4455
4495
  "W-AAA.4_1_2.H65": {
4456
4496
  "issueID": "titleEmpty",
@@ -4485,7 +4525,8 @@ const rulesData = {
4485
4525
  "E-AAA.1_3_1.H49.I": {
4486
4526
  "issueID": "nonSemanticText",
4487
4527
  "quality": 1,
4488
- "what": "Special text is italicized nonsemantically"
4528
+ "what": "Special text is italicized nonsemantically",
4529
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.I"
4489
4530
  },
4490
4531
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.I": {
4491
4532
  "issueID": "nonSemanticText",
@@ -4500,7 +4541,8 @@ const rulesData = {
4500
4541
  "E-AAA.1_3_1.H49.Small": {
4501
4542
  "issueID": "nonSemanticText",
4502
4543
  "quality": 1,
4503
- "what": "Special text is made small nonsemantically"
4544
+ "what": "Special text is made small nonsemantically",
4545
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.Small"
4504
4546
  },
4505
4547
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.Small": {
4506
4548
  "issueID": "nonSemanticText",
@@ -4515,7 +4557,8 @@ const rulesData = {
4515
4557
  "W-AAA.1_3_1.H42": {
4516
4558
  "issueID": "pseudoHeadingRisk",
4517
4559
  "quality": 1,
4518
- "what": "Heading coding is not used but the element is intended as a heading?"
4560
+ "what": "Heading coding is not used but the element is intended as a heading?",
4561
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H42"
4519
4562
  },
4520
4563
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H42": {
4521
4564
  "issueID": "pseudoHeadingRisk",
@@ -4525,7 +4568,8 @@ const rulesData = {
4525
4568
  "W-AAA.1_3_1.H48.1": {
4526
4569
  "issueID": "pseudoListRisk",
4527
4570
  "quality": 1,
4528
- "what": "Content simulates an unordered list without a ul?"
4571
+ "what": "Content simulates an unordered list without a ul?",
4572
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H48.1"
4529
4573
  },
4530
4574
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H48.1": {
4531
4575
  "issueID": "pseudoListRisk",
@@ -4535,7 +4579,8 @@ const rulesData = {
4535
4579
  "W-AAA.1_3_1.H48.2": {
4536
4580
  "issueID": "pseudoOrderedListRisk",
4537
4581
  "quality": 1,
4538
- "what": "Ordered list fails to be coded as such?"
4582
+ "what": "Ordered list fails to be coded as such?",
4583
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H48.2"
4539
4584
  },
4540
4585
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H48.2": {
4541
4586
  "issueID": "pseudoOrderedListRisk",
@@ -4560,7 +4605,8 @@ const rulesData = {
4560
4605
  "E-AAA.4_1_2.H91.Select.Value": {
4561
4606
  "issueID": "selectNoText",
4562
4607
  "quality": 1,
4563
- "what": "Element is select but its value has no accessible name"
4608
+ "what": "Element is select but its value has no accessible name",
4609
+ "supersededBy": "W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Select.Value"
4564
4610
  },
4565
4611
  "W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Select.Value": {
4566
4612
  "issueID": "selectNoText",
@@ -4570,7 +4616,8 @@ const rulesData = {
4570
4616
  "W-AAA.1_3_1.H85.2": {
4571
4617
  "issueID": "selectFlatRisk",
4572
4618
  "quality": 1,
4573
- "what": "Selection list contains groups of related options not grouped with optgroup?"
4619
+ "what": "Selection list contains groups of related options not grouped with optgroup?",
4620
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H85.2"
4574
4621
  },
4575
4622
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H85.2": {
4576
4623
  "issueID": "selectFlatRisk",
@@ -4590,7 +4637,8 @@ const rulesData = {
4590
4637
  "E-AAA.1_3_1.H71.NoLegend": {
4591
4638
  "issueID": "legendMissing",
4592
4639
  "quality": 1,
4593
- "what": "Element has no legend element"
4640
+ "what": "Element has no legend element",
4641
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H71.NoLegend"
4594
4642
  },
4595
4643
  "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H71.NoLegend": {
4596
4644
  "issueID": "legendMissing",
@@ -4600,7 +4648,8 @@ const rulesData = {
4600
4648
  "E-AAA.4_1_2.H91.Fieldset.Name": {
4601
4649
  "issueID": "groupName",
4602
4650
  "quality": 1,
4603
- "what": "fieldset element has no accessible name"
4651
+ "what": "fieldset element has no accessible name",
4652
+ "supersededBy": "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Fieldset.Name"
4604
4653
  },
4605
4654
  "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Fieldset.Name": {
4606
4655
  "issueID": "groupName",
@@ -4665,7 +4714,8 @@ const rulesData = {
4665
4714
  "E-AAA.1_3_1.ARIA6": {
4666
4715
  "issueID": "labelEmpty",
4667
4716
  "quality": 1,
4668
- "what": "Value of the aria-label attribute of the form control is empty or only whitespace"
4717
+ "what": "Value of the aria-label attribute of the form control is empty or only whitespace",
4718
+ "supersededBy": "E-AAA.4_1_2.ARIA6"
4669
4719
  },
4670
4720
  "E-AAA.4_1_2.ARIA6": {
4671
4721
  "issueID": "labelEmpty",
@@ -4690,7 +4740,8 @@ const rulesData = {
4690
4740
  "E-AAA.3_2_2.H32.2": {
4691
4741
  "issueID": "submitButton",
4692
4742
  "quality": 1,
4693
- "what": "Form has no submit button"
4743
+ "what": "Form has no submit button",
4744
+ "supersededBy": "E-WCAG2AAA.Principle3.Guideline3_2.3_2_2.H32.2"
4694
4745
  },
4695
4746
  "E-WCAG2AAA.Principle3.Guideline3_2.3_2_2.H32.2": {
4696
4747
  "issueID": "submitButton",
@@ -4700,14 +4751,15 @@ const rulesData = {
4700
4751
  "E-AAA.1_3_1.H49.AlignAttr": {
4701
4752
  "issueID": "attributeObsolete",
4702
4753
  "quality": 1,
4703
- "what": "align attribute is obsolete"
4754
+ "what": "align attribute is obsolete",
4755
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.AlignAttr"
4704
4756
  },
4705
- "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.AlignAttr": {
4757
+ "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.AlignAttr": {
4706
4758
  "issueID": "attributeObsolete",
4707
4759
  "quality": 1,
4708
4760
  "what": "align attribute is obsolete"
4709
4761
  },
4710
- "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.AlignAttr": {
4762
+ "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.AlignAttr": {
4711
4763
  "issueID": "attributeObsolete",
4712
4764
  "quality": 1,
4713
4765
  "what": "align attribute is obsolete"
@@ -4725,7 +4777,8 @@ const rulesData = {
4725
4777
  "E-AAA.1_3_1.H49.Font": {
4726
4778
  "issueID": "elementObsolete",
4727
4779
  "quality": 1,
4728
- "what": "font element is obsolete"
4780
+ "what": "font element is obsolete",
4781
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.Font"
4729
4782
  },
4730
4783
  "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.Font": {
4731
4784
  "issueID": "elementObsolete",
@@ -4919,7 +4972,8 @@ const rulesData = {
4919
4972
  "Rpt_Aria_ContentinfoWithNoMain_Implicit": {
4920
4973
  "issueID": "roleBad",
4921
4974
  "quality": 1,
4922
- "what": "Element has a contentinfo role when no element has a main role"
4975
+ "what": "Element has a contentinfo role when no element has a main role",
4976
+ "supersededBy": "aria_contentinfo_misuse"
4923
4977
  },
4924
4978
  "aria_contentinfo_misuse": {
4925
4979
  "issueID": "roleBad",
@@ -4929,22 +4983,24 @@ const rulesData = {
4929
4983
  "Rpt_Aria_ValidRole": {
4930
4984
  "issueID": "roleBad",
4931
4985
  "quality": 1,
4932
- "what": "Element has an invalid role"
4986
+ "what": "Element has an invalid role",
4987
+ "supersededBy": "aria_role_allowed"
4933
4988
  },
4934
4989
  "aria_role_allowed": {
4935
4990
  "issueID": "roleBad",
4936
4991
  "quality": 1,
4937
4992
  "what": "Element has an invalid role"
4938
4993
  },
4939
- "aria_eventhandler_role_valid": {
4994
+ "Rpt_Aria_EventHandlerMissingRole_Native_Host_Sematics": {
4940
4995
  "issueID": "roleBad",
4941
4996
  "quality": 1,
4942
- "what": "Element with an onclick, onmouseout, or onmouseover attribute has no valid ARIA role"
4997
+ "what": "Element has an event handler but no valid ARIA role",
4998
+ "supersededBy": "aria_eventhandler_role_valid"
4943
4999
  },
4944
- "Rpt_Aria_EventHandlerMissingRole_Native_Host_Sematics": {
5000
+ "aria_eventhandler_role_valid": {
4945
5001
  "issueID": "roleBad",
4946
5002
  "quality": 1,
4947
- "what": "Element has an event handler but no valid ARIA role"
5003
+ "what": "Element with an onclick, onmouseout, or onmouseover attribute has no valid ARIA role"
4948
5004
  },
4949
5005
  "combobox_haspopup_valid": {
4950
5006
  "issueID": "roleBad",
@@ -4971,11 +5027,6 @@ const rulesData = {
4971
5027
  "quality": 1,
4972
5028
  "what": "ARIA attribute is invalid for the role of its element"
4973
5029
  },
4974
- "aria_attribute_value_valid": {
4975
- "issueID": "attributeValueBad",
4976
- "quality": 1,
4977
- "what": "Value of an attribute on the element is not valid"
4978
- },
4979
5030
  "aria_attribute_required": {
4980
5031
  "issueID": "ariaMissing",
4981
5032
  "quality": 1,
@@ -4989,7 +5040,8 @@ const rulesData = {
4989
5040
  "Rpt_Aria_ValidProperty": {
4990
5041
  "issueID": "ariaAttributeBad",
4991
5042
  "quality": 1,
4992
- "what": "ARIA attribute is invalid for the role"
5043
+ "what": "ARIA attribute is invalid for the role",
5044
+ "supersededBy": "aria_attribute_allowed"
4993
5045
  },
4994
5046
  "aria_attribute_allowed": {
4995
5047
  "issueID": "ariaAttributeBad",
@@ -5002,9 +5054,15 @@ const rulesData = {
5002
5054
  "what": "ARIA attribute has an empty value"
5003
5055
  },
5004
5056
  "Rpt_Aria_ValidPropertyValue": {
5005
- "issueID": "ariaAttributeBad",
5057
+ "issueID": "attributeValueBad",
5058
+ "quality": 1,
5059
+ "what": "ARIA property value is invalid",
5060
+ "supersededBy": "aria_attribute_value_valid"
5061
+ },
5062
+ "aria_attribute_value_valid": {
5063
+ "issueID": "attributeValueBad",
5006
5064
  "quality": 1,
5007
- "what": "ARIA property value is invalid"
5065
+ "what": "Value of an ARIA attribute on the element is invalid"
5008
5066
  },
5009
5067
  "aria_attribute_redundant": {
5010
5068
  "issueID": "ariaRedundant",
@@ -5146,12 +5204,13 @@ const rulesData = {
5146
5204
  "quality": 1,
5147
5205
  "what": "input element label invisible?"
5148
5206
  },
5149
- "label_name_visible": {
5207
+ "WCAG21_Label_Accessible": {
5150
5208
  "issueID": "visibleLabelNotInName",
5151
5209
  "quality": 1,
5152
- "what": "Accessible name does not match or contain the visible label text"
5210
+ "what": "Accessible name does not match or contain the visible label text",
5211
+ "supersededBy": "label_name_visible"
5153
5212
  },
5154
- "WCAG21_Label_Accessible": {
5213
+ "label_name_visible": {
5155
5214
  "issueID": "visibleLabelNotInName",
5156
5215
  "quality": 1,
5157
5216
  "what": "Accessible name does not match or contain the visible label text"
@@ -9702,12 +9761,21 @@ const issues = deepFreeze(issuesData);
9702
9761
  const rules = deepFreeze(rulesData);
9703
9762
  const makeIssueRules = (ruleTable, issueTable = issues) => {
9704
9763
  const errors = [];
9705
- const checkEntry = (engineID, variabilityName, ruleID, entry) => {
9706
- const { issueID, quality, what } = entry;
9764
+ const checkEntry = (engineID, variabilityName, ruleID, entry, engineRuleIDs) => {
9765
+ const { issueID, quality, what, supersededBy, outcome, uncertainty, review, ignore } = entry;
9707
9766
  if (!ruleID.length) errors.push(`${engineID}.${variabilityName} has a rule with an empty ruleID`);
9708
9767
  if (typeof issueID !== "string" || !issueID.length || !(issueID in issueTable)) errors.push(`${engineID}.${variabilityName}.${ruleID} has an invalid issueID (${JSON.stringify(issueID)})`);
9709
9768
  if (typeof quality !== "number") errors.push(`${engineID}.${variabilityName}.${ruleID} has a non-numeric quality (${JSON.stringify(quality)})`);
9710
9769
  if (typeof what !== "string" || !what.length) errors.push(`${engineID}.${variabilityName}.${ruleID} has a non-string or empty what (${JSON.stringify(what)})`);
9770
+ if (supersededBy !== void 0 && supersededBy !== null) {
9771
+ if (typeof supersededBy !== "string" || !supersededBy.length) errors.push(`${engineID}.${variabilityName}.${ruleID} has a non-string, non-null, or empty supersededBy (${JSON.stringify(supersededBy)})`);
9772
+ else if (supersededBy === ruleID) errors.push(`${engineID}.${variabilityName}.${ruleID} has supersededBy naming itself`);
9773
+ else if (!engineRuleIDs.has(supersededBy)) errors.push(`${engineID}.${variabilityName}.${ruleID} has supersededBy (${supersededBy}), which is not a rule of ${engineID}`);
9774
+ }
9775
+ if (outcome !== void 0 && !outcomes.includes(outcome)) errors.push(`${engineID}.${variabilityName}.${ruleID} has an invalid outcome (${JSON.stringify(outcome)})`);
9776
+ if (uncertainty !== void 0 && !uncertainties.includes(uncertainty)) errors.push(`${engineID}.${variabilityName}.${ruleID} has an invalid uncertainty (${JSON.stringify(uncertainty)})`);
9777
+ if (review !== void 0 && (typeof review !== "string" || !review.length)) errors.push(`${engineID}.${variabilityName}.${ruleID} has a non-string or empty review (${JSON.stringify(review)})`);
9778
+ if (ignore !== void 0 && !whyIgnore.includes(ignore)) errors.push(`${engineID}.${variabilityName}.${ruleID} has an invalid ignore (${JSON.stringify(ignore)})`);
9711
9779
  if (variabilityName === "variable") {
9712
9780
  if (!/[.*+?^${}()|[\]\\]/.test(ruleID)) errors.push(`${engineID}.${variabilityName}.${ruleID} has no regex metacharacters, so it should be an invariant rule`);
9713
9781
  else try {
@@ -9719,8 +9787,9 @@ const makeIssueRules = (ruleTable, issueTable = issues) => {
9719
9787
  };
9720
9788
  const issueRules = {};
9721
9789
  Object.entries(ruleTable).forEach(([engineID, { invariant, variable }]) => {
9790
+ const engineRuleIDs = /* @__PURE__ */ new Set([...Object.keys(invariant), ...Object.keys(variable)]);
9722
9791
  Object.entries(invariant).forEach(([ruleID, entry]) => {
9723
- checkEntry(engineID, "invariant", ruleID, entry);
9792
+ checkEntry(engineID, "invariant", ruleID, entry, engineRuleIDs);
9724
9793
  const { issueID } = entry;
9725
9794
  issueRules[issueID] ??= {};
9726
9795
  issueRules[issueID][engineID] ??= {
@@ -9730,7 +9799,7 @@ const makeIssueRules = (ruleTable, issueTable = issues) => {
9730
9799
  issueRules[issueID][engineID].invariant.push(ruleID);
9731
9800
  });
9732
9801
  Object.entries(variable).forEach(([ruleID, entry]) => {
9733
- checkEntry(engineID, "variable", ruleID, entry);
9802
+ checkEntry(engineID, "variable", ruleID, entry, engineRuleIDs);
9734
9803
  const { issueID } = entry;
9735
9804
  issueRules[issueID] ??= {};
9736
9805
  issueRules[issueID][engineID] ??= {
package/dist/index.d.cts CHANGED
@@ -1,6 +1,12 @@
1
1
  //#region src/index.d.ts
2
+ declare const outcomes: readonly ['failed', 'cantTell'];
3
+ declare const uncertainties: readonly ['not-computable', 'judgement-required', 'runtime-dependent', 'spec-only', 'equivalence-unknown', 'out-of-scope'];
4
+ declare const whyIgnore: readonly ['invalid', 'irrelevant', 'duplicative', 'unreliable'];
2
5
  type IssueID = keyof typeof issuesData;
3
6
  type IssueEngineRuleCounts = Record<string, number>;
7
+ type Outcome = typeof outcomes[number];
8
+ type Uncertainty = typeof uncertainties[number];
9
+ type Ignore = typeof whyIgnore[number];
4
10
  interface Issue {
5
11
  summary: string;
6
12
  why: string;
@@ -16,6 +22,11 @@ interface RuleEntry {
16
22
  issueID: IssueID;
17
23
  quality: number;
18
24
  what: string;
25
+ supersededBy?: string | null;
26
+ outcome?: Outcome;
27
+ uncertainty?: Uncertainty;
28
+ review?: string;
29
+ ignore?: Ignore;
19
30
  }
20
31
  interface EngineRules {
21
32
  invariant: Record<string, RuleEntry>;
@@ -2278,4 +2289,4 @@ declare const getEngineRuleCounts: (ruleTable?: Record<string, EngineRules>) =>
2278
2289
  declare const issueRules: Record<string, Record<string, ruleIDsByType>>;
2279
2290
  declare const issueStats: Record<string, IssueEngineRuleCounts>;
2280
2291
  //#endregion
2281
- export { IssueEngineRuleCounts, getEditableData, getEngineRuleCounts, getSingleEngineIssues, issueRules, issueStats, issues, makeIssueRules, makeIssueStats, ruleIDsByType, rules };
2292
+ export { Ignore, IssueEngineRuleCounts, Outcome, Uncertainty, getEditableData, getEngineRuleCounts, getSingleEngineIssues, issueRules, issueStats, issues, makeIssueRules, makeIssueStats, ruleIDsByType, rules };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,12 @@
1
1
  //#region src/index.d.ts
2
+ declare const outcomes: readonly ['failed', 'cantTell'];
3
+ declare const uncertainties: readonly ['not-computable', 'judgement-required', 'runtime-dependent', 'spec-only', 'equivalence-unknown', 'out-of-scope'];
4
+ declare const whyIgnore: readonly ['invalid', 'irrelevant', 'duplicative', 'unreliable'];
2
5
  type IssueID = keyof typeof issuesData;
3
6
  type IssueEngineRuleCounts = Record<string, number>;
7
+ type Outcome = typeof outcomes[number];
8
+ type Uncertainty = typeof uncertainties[number];
9
+ type Ignore = typeof whyIgnore[number];
4
10
  interface Issue {
5
11
  summary: string;
6
12
  why: string;
@@ -16,6 +22,11 @@ interface RuleEntry {
16
22
  issueID: IssueID;
17
23
  quality: number;
18
24
  what: string;
25
+ supersededBy?: string | null;
26
+ outcome?: Outcome;
27
+ uncertainty?: Uncertainty;
28
+ review?: string;
29
+ ignore?: Ignore;
19
30
  }
20
31
  interface EngineRules {
21
32
  invariant: Record<string, RuleEntry>;
@@ -2278,4 +2289,4 @@ declare const getEngineRuleCounts: (ruleTable?: Record<string, EngineRules>) =>
2278
2289
  declare const issueRules: Record<string, Record<string, ruleIDsByType>>;
2279
2290
  declare const issueStats: Record<string, IssueEngineRuleCounts>;
2280
2291
  //#endregion
2281
- export { IssueEngineRuleCounts, getEditableData, getEngineRuleCounts, getSingleEngineIssues, issueRules, issueStats, issues, makeIssueRules, makeIssueStats, ruleIDsByType, rules };
2292
+ export { Ignore, IssueEngineRuleCounts, Outcome, Uncertainty, getEditableData, getEngineRuleCounts, getSingleEngineIssues, issueRules, issueStats, issues, makeIssueRules, makeIssueStats, ruleIDsByType, rules };
package/dist/index.mjs CHANGED
@@ -1,4 +1,19 @@
1
1
  //#region src/index.ts
2
+ const outcomes = ["failed", "cantTell"];
3
+ const uncertainties = [
4
+ "not-computable",
5
+ "judgement-required",
6
+ "runtime-dependent",
7
+ "spec-only",
8
+ "equivalence-unknown",
9
+ "out-of-scope"
10
+ ];
11
+ const whyIgnore = [
12
+ "invalid",
13
+ "irrelevant",
14
+ "duplicative",
15
+ "unreliable"
16
+ ];
2
17
  const issuesData = {
3
18
  "ignorable": {
4
19
  "summary": "ignorable",
@@ -2244,7 +2259,8 @@ const rulesData = {
2244
2259
  "cantTellTextContrast": {
2245
2260
  "issueID": "ignorable",
2246
2261
  "quality": 1,
2247
- "what": "Test of text contrast could not give a conclusive result [invalid]"
2262
+ "what": "Test of text contrast could not give a conclusive result [invalid]",
2263
+ "supersededBy": null
2248
2264
  },
2249
2265
  "r73": {
2250
2266
  "issueID": "ignorable",
@@ -2559,7 +2575,8 @@ const rulesData = {
2559
2575
  "cantTell": {
2560
2576
  "issueID": "notValidatable",
2561
2577
  "quality": 1,
2562
- "what": "Test could not give a conclusive result"
2578
+ "what": "Test could not give a conclusive result",
2579
+ "supersededBy": "r66"
2563
2580
  }
2564
2581
  },
2565
2582
  "variable": {}
@@ -3879,7 +3896,8 @@ const rulesData = {
3879
3896
  "E-AAA.4_1_1.F77": {
3880
3897
  "issueID": "duplicateID",
3881
3898
  "quality": 1,
3882
- "what": "Duplicate id attribute value"
3899
+ "what": "Duplicate id attribute value",
3900
+ "supersededBy": "E-WCAG2AAA.Principle4.Guideline4_1.4_1_1.F77"
3883
3901
  },
3884
3902
  "E-WCAG2AAA.Principle4.Guideline4_1.4_1_1.F77": {
3885
3903
  "issueID": "duplicateID",
@@ -3929,7 +3947,8 @@ const rulesData = {
3929
3947
  "E-H36": {
3930
3948
  "issueID": "imageButtonNoText",
3931
3949
  "quality": 1,
3932
- "what": "Image submit button has no alt attribute"
3950
+ "what": "Image submit button has no alt attribute",
3951
+ "supersededBy": "E-AAA.1_1_1.H36"
3933
3952
  },
3934
3953
  "E-AAA.1_1_1.H36": {
3935
3954
  "issueID": "imageButtonNoText",
@@ -3944,7 +3963,8 @@ const rulesData = {
3944
3963
  "E-AAA.1_1_1.H37": {
3945
3964
  "issueID": "imageNoText",
3946
3965
  "quality": 1,
3947
- "what": "img element has no alt attribute"
3966
+ "what": "img element has no alt attribute",
3967
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_1.1_1_1.H37"
3948
3968
  },
3949
3969
  "E-WCAG2AAA.Principle1.Guideline1_1.1_1_1.H37": {
3950
3970
  "issueID": "imageNoText",
@@ -3969,7 +3989,8 @@ const rulesData = {
3969
3989
  "E-AAA.3_1_1.H57.2": {
3970
3990
  "issueID": "pageLanguage",
3971
3991
  "quality": 1,
3972
- "what": "html element has no lang or xml:lang attribute"
3992
+ "what": "html element has no lang or xml:lang attribute",
3993
+ "supersededBy": "E-WCAG2AAA.Principle3.Guideline3_1.3_1_1.H57.2"
3973
3994
  },
3974
3995
  "E-WCAG2AAA.Principle3.Guideline3_1.3_1_1.H57.2": {
3975
3996
  "issueID": "pageLanguage",
@@ -4014,7 +4035,8 @@ const rulesData = {
4014
4035
  "W-AAA.2_1_1.G90": {
4015
4036
  "issueID": "eventKeyboardRisk",
4016
4037
  "quality": 1,
4017
- "what": "Event handler functionality is not available by keyboard?"
4038
+ "what": "Event handler functionality is not available by keyboard?",
4039
+ "supersededBy": "W-WCAG2AAA.Principle2.Guideline2_1.2_1_1.G90"
4018
4040
  },
4019
4041
  "W-WCAG2AAA.Principle2.Guideline2_1.2_1_1.G90": {
4020
4042
  "issueID": "eventKeyboardRisk",
@@ -4024,7 +4046,8 @@ const rulesData = {
4024
4046
  "W-AAA.2_1_1.SCR20.MouseOut": {
4025
4047
  "issueID": "eventKeyboardRisk",
4026
4048
  "quality": 1,
4027
- "what": "Mousing-out functionality is not available by keyboard?"
4049
+ "what": "Mousing-out functionality is not available by keyboard?",
4050
+ "supersededBy": "W-WCAG2AAA.Principle2.Guideline2_1.2_1_1.SCR20.MouseOut"
4028
4051
  },
4029
4052
  "W-WCAG2AAA.Principle2.Guideline2_1.2_1_1.SCR20.MouseOut": {
4030
4053
  "issueID": "eventKeyboardRisk",
@@ -4034,7 +4057,8 @@ const rulesData = {
4034
4057
  "W-AAA.2_1_1.SCR20.MouseOver": {
4035
4058
  "issueID": "eventKeyboardRisk",
4036
4059
  "quality": 1,
4037
- "what": "Mousing-over functionality is not available by keyboard?"
4060
+ "what": "Mousing-over functionality is not available by keyboard?",
4061
+ "supersededBy": "W-WCAG2AAA.Principle2.Guideline2_1.2_1_1.SCR20.MouseOver"
4038
4062
  },
4039
4063
  "W-WCAG2AAA.Principle2.Guideline2_1.2_1_1.SCR20.MouseOver": {
4040
4064
  "issueID": "eventKeyboardRisk",
@@ -4054,7 +4078,8 @@ const rulesData = {
4054
4078
  "E-AAA.2_4_1.G1,G123,G124.NoSuchID": {
4055
4079
  "issueID": "internalLinkBroken",
4056
4080
  "quality": 1,
4057
- "what": "Internal link references a nonexistent destination"
4081
+ "what": "Internal link references a nonexistent destination",
4082
+ "supersededBy": "E-WCAG2AAA.Principle2.Guideline2_4.2_4_1.G1,G123,G124.NoSuchID"
4058
4083
  },
4059
4084
  "E-WCAG2AAA.Principle2.Guideline2_4.2_4_1.G1,G123,G124.NoSuchID": {
4060
4085
  "issueID": "internalLinkBroken",
@@ -4079,7 +4104,8 @@ const rulesData = {
4079
4104
  "E-AAA.1_3_1.ARIA16,ARIA9": {
4080
4105
  "issueID": "labelBadID",
4081
4106
  "quality": 1,
4082
- "what": "aria-labelledby attribute references a nonexistent element"
4107
+ "what": "aria-labelledby attribute references a nonexistent element",
4108
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.ARIA16,ARIA9"
4083
4109
  },
4084
4110
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.ARIA16,ARIA9": {
4085
4111
  "issueID": "labelBadID",
@@ -4094,7 +4120,8 @@ const rulesData = {
4094
4120
  "E-AAA.4_1_2.H91.A.Empty": {
4095
4121
  "issueID": "linkNoText",
4096
4122
  "quality": 1,
4097
- "what": "a element has an id attribute but no href attribute or text"
4123
+ "what": "a element has an id attribute but no href attribute or text",
4124
+ "supersededBy": "W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.A.Empty"
4098
4125
  },
4099
4126
  "W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.A.Empty": {
4100
4127
  "issueID": "linkNoText",
@@ -4104,7 +4131,8 @@ const rulesData = {
4104
4131
  "E-AAA.4_1_2.H91.A.EmptyNoId": {
4105
4132
  "issueID": "linkNoText",
4106
4133
  "quality": 1,
4107
- "what": "Link has no name or id attribute or value"
4134
+ "what": "Link has no name or id attribute or value",
4135
+ "supersededBy": "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.A.EmptyNoId"
4108
4136
  },
4109
4137
  "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.A.EmptyNoId": {
4110
4138
  "issueID": "linkNoText",
@@ -4129,7 +4157,8 @@ const rulesData = {
4129
4157
  "E-AAA.1_1_1.H30.2": {
4130
4158
  "issueID": "imageLinkNoText",
4131
4159
  "quality": 1,
4132
- "what": "img element is the only link content but has no text alternative"
4160
+ "what": "img element is the only link content but has no text alternative",
4161
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_1.1_1_1.H30.2"
4133
4162
  },
4134
4163
  "E-WCAG2AAA.Principle1.Guideline1_1.1_1_1.H30.2": {
4135
4164
  "issueID": "imageLinkNoText",
@@ -4139,7 +4168,8 @@ const rulesData = {
4139
4168
  "E-AAA.4_1_2.H91.A.Placeholder": {
4140
4169
  "issueID": "linkBrokenRisk",
4141
4170
  "quality": 1,
4142
- "what": "Link has text but no href, id, or name attribute"
4171
+ "what": "Link has text but no href, id, or name attribute",
4172
+ "supersededBy": "W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.A.Placeholder"
4143
4173
  },
4144
4174
  "W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.A.Placeholder": {
4145
4175
  "issueID": "linkBrokenRisk",
@@ -4149,7 +4179,8 @@ const rulesData = {
4149
4179
  "E-AAA.2_4_8.H59.2b": {
4150
4180
  "issueID": "linkElNoHref",
4151
4181
  "quality": 1,
4152
- "what": "link element is missing a non-empty href for the linked resource"
4182
+ "what": "link element is missing a non-empty href for the linked resource",
4183
+ "supersededBy": "E-WCAG2AAA.Principle2.Guideline2_4.2_4_8.H59.2b"
4153
4184
  },
4154
4185
  "E-WCAG2AAA.Principle2.Guideline2_4.2_4_8.H59.2b": {
4155
4186
  "issueID": "linkElNoHref",
@@ -4169,7 +4200,8 @@ const rulesData = {
4169
4200
  "E-AAA.4_1_2.H91.Textarea.Name": {
4170
4201
  "issueID": "textAreaNoText",
4171
4202
  "quality": 1,
4172
- "what": "textarea element has no accessible name"
4203
+ "what": "textarea element has no accessible name",
4204
+ "supersededBy": "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Textarea.Name"
4173
4205
  },
4174
4206
  "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Textarea.Name": {
4175
4207
  "issueID": "textAreaNoText",
@@ -4179,7 +4211,8 @@ const rulesData = {
4179
4211
  "E-AAA.1_1_1.H2.EG3": {
4180
4212
  "issueID": "linkAltSame",
4181
4213
  "quality": 1,
4182
- "what": "alt value of the link img element duplicates the text of a link beside it"
4214
+ "what": "alt value of the link img element duplicates the text of a link beside it",
4215
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_1.1_1_1.H2.EG3"
4183
4216
  },
4184
4217
  "E-WCAG2AAA.Principle1.Guideline1_1.1_1_1.H2.EG3": {
4185
4218
  "issueID": "linkAltSame",
@@ -4209,7 +4242,8 @@ const rulesData = {
4209
4242
  "E-AAA.4_1_2.H91.Div.Name": {
4210
4243
  "issueID": "buttonNoText",
4211
4244
  "quality": 1,
4212
- "what": "div element with button role has no accessible name"
4245
+ "what": "div element with button role has no accessible name",
4246
+ "supersededBy": "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Div.Name"
4213
4247
  },
4214
4248
  "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Div.Name": {
4215
4249
  "issueID": "buttonNoText",
@@ -4244,7 +4278,8 @@ const rulesData = {
4244
4278
  "E-AAA.1_3_1.F92,ARIA4": {
4245
4279
  "issueID": "presentationChild",
4246
4280
  "quality": 1,
4247
- "what": "Element has presentation role but semantic child"
4281
+ "what": "Element has presentation role but semantic child",
4282
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.F92,ARIA4"
4248
4283
  },
4249
4284
  "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.F92,ARIA4": {
4250
4285
  "issueID": "presentationChild",
@@ -4264,7 +4299,8 @@ const rulesData = {
4264
4299
  "E-AAA.2_4_8.H59.2a": {
4265
4300
  "issueID": "linkElementBad",
4266
4301
  "quality": 1,
4267
- "what": "Element has no nonempty rel attribute for the type"
4302
+ "what": "Element has no nonempty rel attribute for the type",
4303
+ "supersededBy": "E-WCAG2AAA.Principle2.Guideline2_4.2_4_8.H59.2a"
4268
4304
  },
4269
4305
  "E-WCAG2AAA.Principle2.Guideline2_4.2_4_8.H59.2a": {
4270
4306
  "issueID": "linkElementBad",
@@ -4289,7 +4325,8 @@ const rulesData = {
4289
4325
  "E-AAA.1_3_5.H98": {
4290
4326
  "issueID": "autocompleteBad",
4291
4327
  "quality": 1,
4292
- "what": "autocomplete attribute and the input type are mismatched"
4328
+ "what": "autocomplete attribute and the input type are mismatched",
4329
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_3.1_3_5.H98"
4293
4330
  },
4294
4331
  "E-WCAG2AAA.Principle1.Guideline1_3.1_3_5.H98": {
4295
4332
  "issueID": "autocompleteBad",
@@ -4314,7 +4351,8 @@ const rulesData = {
4314
4351
  "E-AAA.1_4_6.G18.Fail": {
4315
4352
  "issueID": "contrastAA",
4316
4353
  "quality": 1,
4317
- "what": "Contrast between the text and its background is less than 4.5:1"
4354
+ "what": "Contrast between the text and its background is less than 4.5:1",
4355
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_4.1_4_6.G18.Fail"
4318
4356
  },
4319
4357
  "E-WCAG2AAA.Principle1.Guideline1_4.1_4_6.G18.Fail": {
4320
4358
  "issueID": "contrastAA",
@@ -4429,7 +4467,8 @@ const rulesData = {
4429
4467
  "E-AAA.1_3_1.H42.2": {
4430
4468
  "issueID": "headingEmpty",
4431
4469
  "quality": 1,
4432
- "what": "Heading is empty"
4470
+ "what": "Heading is empty",
4471
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H42.2"
4433
4472
  },
4434
4473
  "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H42.2": {
4435
4474
  "issueID": "headingEmpty",
@@ -4449,7 +4488,8 @@ const rulesData = {
4449
4488
  "W-AAA.1_3_1.H65": {
4450
4489
  "issueID": "titleEmpty",
4451
4490
  "quality": .5,
4452
- "what": "title attribute of the form control is empty or only whitespace"
4491
+ "what": "title attribute of the form control is empty or only whitespace",
4492
+ "supersededBy": "W-AAA.4_1_2.H65"
4453
4493
  },
4454
4494
  "W-AAA.4_1_2.H65": {
4455
4495
  "issueID": "titleEmpty",
@@ -4484,7 +4524,8 @@ const rulesData = {
4484
4524
  "E-AAA.1_3_1.H49.I": {
4485
4525
  "issueID": "nonSemanticText",
4486
4526
  "quality": 1,
4487
- "what": "Special text is italicized nonsemantically"
4527
+ "what": "Special text is italicized nonsemantically",
4528
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.I"
4488
4529
  },
4489
4530
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.I": {
4490
4531
  "issueID": "nonSemanticText",
@@ -4499,7 +4540,8 @@ const rulesData = {
4499
4540
  "E-AAA.1_3_1.H49.Small": {
4500
4541
  "issueID": "nonSemanticText",
4501
4542
  "quality": 1,
4502
- "what": "Special text is made small nonsemantically"
4543
+ "what": "Special text is made small nonsemantically",
4544
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.Small"
4503
4545
  },
4504
4546
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.Small": {
4505
4547
  "issueID": "nonSemanticText",
@@ -4514,7 +4556,8 @@ const rulesData = {
4514
4556
  "W-AAA.1_3_1.H42": {
4515
4557
  "issueID": "pseudoHeadingRisk",
4516
4558
  "quality": 1,
4517
- "what": "Heading coding is not used but the element is intended as a heading?"
4559
+ "what": "Heading coding is not used but the element is intended as a heading?",
4560
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H42"
4518
4561
  },
4519
4562
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H42": {
4520
4563
  "issueID": "pseudoHeadingRisk",
@@ -4524,7 +4567,8 @@ const rulesData = {
4524
4567
  "W-AAA.1_3_1.H48.1": {
4525
4568
  "issueID": "pseudoListRisk",
4526
4569
  "quality": 1,
4527
- "what": "Content simulates an unordered list without a ul?"
4570
+ "what": "Content simulates an unordered list without a ul?",
4571
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H48.1"
4528
4572
  },
4529
4573
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H48.1": {
4530
4574
  "issueID": "pseudoListRisk",
@@ -4534,7 +4578,8 @@ const rulesData = {
4534
4578
  "W-AAA.1_3_1.H48.2": {
4535
4579
  "issueID": "pseudoOrderedListRisk",
4536
4580
  "quality": 1,
4537
- "what": "Ordered list fails to be coded as such?"
4581
+ "what": "Ordered list fails to be coded as such?",
4582
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H48.2"
4538
4583
  },
4539
4584
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H48.2": {
4540
4585
  "issueID": "pseudoOrderedListRisk",
@@ -4559,7 +4604,8 @@ const rulesData = {
4559
4604
  "E-AAA.4_1_2.H91.Select.Value": {
4560
4605
  "issueID": "selectNoText",
4561
4606
  "quality": 1,
4562
- "what": "Element is select but its value has no accessible name"
4607
+ "what": "Element is select but its value has no accessible name",
4608
+ "supersededBy": "W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Select.Value"
4563
4609
  },
4564
4610
  "W-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Select.Value": {
4565
4611
  "issueID": "selectNoText",
@@ -4569,7 +4615,8 @@ const rulesData = {
4569
4615
  "W-AAA.1_3_1.H85.2": {
4570
4616
  "issueID": "selectFlatRisk",
4571
4617
  "quality": 1,
4572
- "what": "Selection list contains groups of related options not grouped with optgroup?"
4618
+ "what": "Selection list contains groups of related options not grouped with optgroup?",
4619
+ "supersededBy": "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H85.2"
4573
4620
  },
4574
4621
  "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H85.2": {
4575
4622
  "issueID": "selectFlatRisk",
@@ -4589,7 +4636,8 @@ const rulesData = {
4589
4636
  "E-AAA.1_3_1.H71.NoLegend": {
4590
4637
  "issueID": "legendMissing",
4591
4638
  "quality": 1,
4592
- "what": "Element has no legend element"
4639
+ "what": "Element has no legend element",
4640
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H71.NoLegend"
4593
4641
  },
4594
4642
  "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H71.NoLegend": {
4595
4643
  "issueID": "legendMissing",
@@ -4599,7 +4647,8 @@ const rulesData = {
4599
4647
  "E-AAA.4_1_2.H91.Fieldset.Name": {
4600
4648
  "issueID": "groupName",
4601
4649
  "quality": 1,
4602
- "what": "fieldset element has no accessible name"
4650
+ "what": "fieldset element has no accessible name",
4651
+ "supersededBy": "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Fieldset.Name"
4603
4652
  },
4604
4653
  "E-WCAG2AAA.Principle4.Guideline4_1.4_1_2.H91.Fieldset.Name": {
4605
4654
  "issueID": "groupName",
@@ -4664,7 +4713,8 @@ const rulesData = {
4664
4713
  "E-AAA.1_3_1.ARIA6": {
4665
4714
  "issueID": "labelEmpty",
4666
4715
  "quality": 1,
4667
- "what": "Value of the aria-label attribute of the form control is empty or only whitespace"
4716
+ "what": "Value of the aria-label attribute of the form control is empty or only whitespace",
4717
+ "supersededBy": "E-AAA.4_1_2.ARIA6"
4668
4718
  },
4669
4719
  "E-AAA.4_1_2.ARIA6": {
4670
4720
  "issueID": "labelEmpty",
@@ -4689,7 +4739,8 @@ const rulesData = {
4689
4739
  "E-AAA.3_2_2.H32.2": {
4690
4740
  "issueID": "submitButton",
4691
4741
  "quality": 1,
4692
- "what": "Form has no submit button"
4742
+ "what": "Form has no submit button",
4743
+ "supersededBy": "E-WCAG2AAA.Principle3.Guideline3_2.3_2_2.H32.2"
4693
4744
  },
4694
4745
  "E-WCAG2AAA.Principle3.Guideline3_2.3_2_2.H32.2": {
4695
4746
  "issueID": "submitButton",
@@ -4699,14 +4750,15 @@ const rulesData = {
4699
4750
  "E-AAA.1_3_1.H49.AlignAttr": {
4700
4751
  "issueID": "attributeObsolete",
4701
4752
  "quality": 1,
4702
- "what": "align attribute is obsolete"
4753
+ "what": "align attribute is obsolete",
4754
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.AlignAttr"
4703
4755
  },
4704
- "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.AlignAttr": {
4756
+ "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.AlignAttr": {
4705
4757
  "issueID": "attributeObsolete",
4706
4758
  "quality": 1,
4707
4759
  "what": "align attribute is obsolete"
4708
4760
  },
4709
- "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.AlignAttr": {
4761
+ "W-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.AlignAttr": {
4710
4762
  "issueID": "attributeObsolete",
4711
4763
  "quality": 1,
4712
4764
  "what": "align attribute is obsolete"
@@ -4724,7 +4776,8 @@ const rulesData = {
4724
4776
  "E-AAA.1_3_1.H49.Font": {
4725
4777
  "issueID": "elementObsolete",
4726
4778
  "quality": 1,
4727
- "what": "font element is obsolete"
4779
+ "what": "font element is obsolete",
4780
+ "supersededBy": "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.Font"
4728
4781
  },
4729
4782
  "E-WCAG2AAA.Principle1.Guideline1_3.1_3_1.H49.Font": {
4730
4783
  "issueID": "elementObsolete",
@@ -4918,7 +4971,8 @@ const rulesData = {
4918
4971
  "Rpt_Aria_ContentinfoWithNoMain_Implicit": {
4919
4972
  "issueID": "roleBad",
4920
4973
  "quality": 1,
4921
- "what": "Element has a contentinfo role when no element has a main role"
4974
+ "what": "Element has a contentinfo role when no element has a main role",
4975
+ "supersededBy": "aria_contentinfo_misuse"
4922
4976
  },
4923
4977
  "aria_contentinfo_misuse": {
4924
4978
  "issueID": "roleBad",
@@ -4928,22 +4982,24 @@ const rulesData = {
4928
4982
  "Rpt_Aria_ValidRole": {
4929
4983
  "issueID": "roleBad",
4930
4984
  "quality": 1,
4931
- "what": "Element has an invalid role"
4985
+ "what": "Element has an invalid role",
4986
+ "supersededBy": "aria_role_allowed"
4932
4987
  },
4933
4988
  "aria_role_allowed": {
4934
4989
  "issueID": "roleBad",
4935
4990
  "quality": 1,
4936
4991
  "what": "Element has an invalid role"
4937
4992
  },
4938
- "aria_eventhandler_role_valid": {
4993
+ "Rpt_Aria_EventHandlerMissingRole_Native_Host_Sematics": {
4939
4994
  "issueID": "roleBad",
4940
4995
  "quality": 1,
4941
- "what": "Element with an onclick, onmouseout, or onmouseover attribute has no valid ARIA role"
4996
+ "what": "Element has an event handler but no valid ARIA role",
4997
+ "supersededBy": "aria_eventhandler_role_valid"
4942
4998
  },
4943
- "Rpt_Aria_EventHandlerMissingRole_Native_Host_Sematics": {
4999
+ "aria_eventhandler_role_valid": {
4944
5000
  "issueID": "roleBad",
4945
5001
  "quality": 1,
4946
- "what": "Element has an event handler but no valid ARIA role"
5002
+ "what": "Element with an onclick, onmouseout, or onmouseover attribute has no valid ARIA role"
4947
5003
  },
4948
5004
  "combobox_haspopup_valid": {
4949
5005
  "issueID": "roleBad",
@@ -4970,11 +5026,6 @@ const rulesData = {
4970
5026
  "quality": 1,
4971
5027
  "what": "ARIA attribute is invalid for the role of its element"
4972
5028
  },
4973
- "aria_attribute_value_valid": {
4974
- "issueID": "attributeValueBad",
4975
- "quality": 1,
4976
- "what": "Value of an attribute on the element is not valid"
4977
- },
4978
5029
  "aria_attribute_required": {
4979
5030
  "issueID": "ariaMissing",
4980
5031
  "quality": 1,
@@ -4988,7 +5039,8 @@ const rulesData = {
4988
5039
  "Rpt_Aria_ValidProperty": {
4989
5040
  "issueID": "ariaAttributeBad",
4990
5041
  "quality": 1,
4991
- "what": "ARIA attribute is invalid for the role"
5042
+ "what": "ARIA attribute is invalid for the role",
5043
+ "supersededBy": "aria_attribute_allowed"
4992
5044
  },
4993
5045
  "aria_attribute_allowed": {
4994
5046
  "issueID": "ariaAttributeBad",
@@ -5001,9 +5053,15 @@ const rulesData = {
5001
5053
  "what": "ARIA attribute has an empty value"
5002
5054
  },
5003
5055
  "Rpt_Aria_ValidPropertyValue": {
5004
- "issueID": "ariaAttributeBad",
5056
+ "issueID": "attributeValueBad",
5057
+ "quality": 1,
5058
+ "what": "ARIA property value is invalid",
5059
+ "supersededBy": "aria_attribute_value_valid"
5060
+ },
5061
+ "aria_attribute_value_valid": {
5062
+ "issueID": "attributeValueBad",
5005
5063
  "quality": 1,
5006
- "what": "ARIA property value is invalid"
5064
+ "what": "Value of an ARIA attribute on the element is invalid"
5007
5065
  },
5008
5066
  "aria_attribute_redundant": {
5009
5067
  "issueID": "ariaRedundant",
@@ -5145,12 +5203,13 @@ const rulesData = {
5145
5203
  "quality": 1,
5146
5204
  "what": "input element label invisible?"
5147
5205
  },
5148
- "label_name_visible": {
5206
+ "WCAG21_Label_Accessible": {
5149
5207
  "issueID": "visibleLabelNotInName",
5150
5208
  "quality": 1,
5151
- "what": "Accessible name does not match or contain the visible label text"
5209
+ "what": "Accessible name does not match or contain the visible label text",
5210
+ "supersededBy": "label_name_visible"
5152
5211
  },
5153
- "WCAG21_Label_Accessible": {
5212
+ "label_name_visible": {
5154
5213
  "issueID": "visibleLabelNotInName",
5155
5214
  "quality": 1,
5156
5215
  "what": "Accessible name does not match or contain the visible label text"
@@ -9701,12 +9760,21 @@ const issues = deepFreeze(issuesData);
9701
9760
  const rules = deepFreeze(rulesData);
9702
9761
  const makeIssueRules = (ruleTable, issueTable = issues) => {
9703
9762
  const errors = [];
9704
- const checkEntry = (engineID, variabilityName, ruleID, entry) => {
9705
- const { issueID, quality, what } = entry;
9763
+ const checkEntry = (engineID, variabilityName, ruleID, entry, engineRuleIDs) => {
9764
+ const { issueID, quality, what, supersededBy, outcome, uncertainty, review, ignore } = entry;
9706
9765
  if (!ruleID.length) errors.push(`${engineID}.${variabilityName} has a rule with an empty ruleID`);
9707
9766
  if (typeof issueID !== "string" || !issueID.length || !(issueID in issueTable)) errors.push(`${engineID}.${variabilityName}.${ruleID} has an invalid issueID (${JSON.stringify(issueID)})`);
9708
9767
  if (typeof quality !== "number") errors.push(`${engineID}.${variabilityName}.${ruleID} has a non-numeric quality (${JSON.stringify(quality)})`);
9709
9768
  if (typeof what !== "string" || !what.length) errors.push(`${engineID}.${variabilityName}.${ruleID} has a non-string or empty what (${JSON.stringify(what)})`);
9769
+ if (supersededBy !== void 0 && supersededBy !== null) {
9770
+ if (typeof supersededBy !== "string" || !supersededBy.length) errors.push(`${engineID}.${variabilityName}.${ruleID} has a non-string, non-null, or empty supersededBy (${JSON.stringify(supersededBy)})`);
9771
+ else if (supersededBy === ruleID) errors.push(`${engineID}.${variabilityName}.${ruleID} has supersededBy naming itself`);
9772
+ else if (!engineRuleIDs.has(supersededBy)) errors.push(`${engineID}.${variabilityName}.${ruleID} has supersededBy (${supersededBy}), which is not a rule of ${engineID}`);
9773
+ }
9774
+ if (outcome !== void 0 && !outcomes.includes(outcome)) errors.push(`${engineID}.${variabilityName}.${ruleID} has an invalid outcome (${JSON.stringify(outcome)})`);
9775
+ if (uncertainty !== void 0 && !uncertainties.includes(uncertainty)) errors.push(`${engineID}.${variabilityName}.${ruleID} has an invalid uncertainty (${JSON.stringify(uncertainty)})`);
9776
+ if (review !== void 0 && (typeof review !== "string" || !review.length)) errors.push(`${engineID}.${variabilityName}.${ruleID} has a non-string or empty review (${JSON.stringify(review)})`);
9777
+ if (ignore !== void 0 && !whyIgnore.includes(ignore)) errors.push(`${engineID}.${variabilityName}.${ruleID} has an invalid ignore (${JSON.stringify(ignore)})`);
9710
9778
  if (variabilityName === "variable") {
9711
9779
  if (!/[.*+?^${}()|[\]\\]/.test(ruleID)) errors.push(`${engineID}.${variabilityName}.${ruleID} has no regex metacharacters, so it should be an invariant rule`);
9712
9780
  else try {
@@ -9718,8 +9786,9 @@ const makeIssueRules = (ruleTable, issueTable = issues) => {
9718
9786
  };
9719
9787
  const issueRules = {};
9720
9788
  Object.entries(ruleTable).forEach(([engineID, { invariant, variable }]) => {
9789
+ const engineRuleIDs = /* @__PURE__ */ new Set([...Object.keys(invariant), ...Object.keys(variable)]);
9721
9790
  Object.entries(invariant).forEach(([ruleID, entry]) => {
9722
- checkEntry(engineID, "invariant", ruleID, entry);
9791
+ checkEntry(engineID, "invariant", ruleID, entry, engineRuleIDs);
9723
9792
  const { issueID } = entry;
9724
9793
  issueRules[issueID] ??= {};
9725
9794
  issueRules[issueID][engineID] ??= {
@@ -9729,7 +9798,7 @@ const makeIssueRules = (ruleTable, issueTable = issues) => {
9729
9798
  issueRules[issueID][engineID].invariant.push(ruleID);
9730
9799
  });
9731
9800
  Object.entries(variable).forEach(([ruleID, entry]) => {
9732
- checkEntry(engineID, "variable", ruleID, entry);
9801
+ checkEntry(engineID, "variable", ruleID, entry, engineRuleIDs);
9733
9802
  const { issueID } = entry;
9734
9803
  issueRules[issueID] ??= {};
9735
9804
  issueRules[issueID][engineID] ??= {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testaro-issues",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "description": "A classification of about 1500 rules of 10 rule engines into about 400 issues. The rule engines are those in the ensemble of Testaro, which tests web pages for front-end quality (accessibility, usability, and standards conformance).",
6
6
  "main": "./dist/index.cjs",