html-validate 9.6.0 → 9.7.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/cjs/core.js CHANGED
@@ -666,6 +666,11 @@ const patternProperties = {
666
666
  }
667
667
  ]
668
668
  },
669
+ templateRoot: {
670
+ title: "Mark element as an element ignoring DOM ancestry, i.e. <template>.",
671
+ description: "The <template> element can contain any elements.",
672
+ type: "boolean"
673
+ },
669
674
  deprecatedAttributes: {
670
675
  title: "List of deprecated attributes",
671
676
  type: "array",
@@ -1107,6 +1112,7 @@ function migrateElement(src) {
1107
1112
  textContent: src.textContent,
1108
1113
  focusable: src.focusable ?? false,
1109
1114
  implicitRole,
1115
+ templateRoot: src.templateRoot === true,
1110
1116
  aria: {
1111
1117
  implicitRole,
1112
1118
  naming: normalizeAriaNaming(src.aria?.naming)
@@ -4113,7 +4119,7 @@ class Rule {
4113
4119
  }
4114
4120
  }
4115
4121
 
4116
- const defaults$x = {
4122
+ const defaults$y = {
4117
4123
  allowExternal: true,
4118
4124
  allowRelative: true,
4119
4125
  allowAbsolute: true,
@@ -4157,7 +4163,7 @@ class AllowedLinks extends Rule {
4157
4163
  allowRelative;
4158
4164
  allowAbsolute;
4159
4165
  constructor(options) {
4160
- super({ ...defaults$x, ...options });
4166
+ super({ ...defaults$y, ...options });
4161
4167
  this.allowExternal = parseAllow(this.options.allowExternal);
4162
4168
  this.allowRelative = parseAllow(this.options.allowRelative);
4163
4169
  this.allowAbsolute = parseAllow(this.options.allowAbsolute);
@@ -4325,7 +4331,7 @@ class AllowedLinks extends Rule {
4325
4331
  }
4326
4332
  }
4327
4333
 
4328
- const defaults$w = {
4334
+ const defaults$x = {
4329
4335
  accessible: true
4330
4336
  };
4331
4337
  function findByTarget(target, siblings) {
@@ -4355,7 +4361,7 @@ function getDescription$1(context) {
4355
4361
  }
4356
4362
  class AreaAlt extends Rule {
4357
4363
  constructor(options) {
4358
- super({ ...defaults$w, ...options });
4364
+ super({ ...defaults$x, ...options });
4359
4365
  }
4360
4366
  static schema() {
4361
4367
  return {
@@ -4434,7 +4440,7 @@ class AriaHiddenBody extends Rule {
4434
4440
  }
4435
4441
  }
4436
4442
 
4437
- const defaults$v = {
4443
+ const defaults$w = {
4438
4444
  allowAnyNamable: false
4439
4445
  };
4440
4446
  const whitelisted = [
@@ -4476,7 +4482,7 @@ function isValidUsage(target, meta) {
4476
4482
  }
4477
4483
  class AriaLabelMisuse extends Rule {
4478
4484
  constructor(options) {
4479
- super({ ...defaults$v, ...options });
4485
+ super({ ...defaults$w, ...options });
4480
4486
  }
4481
4487
  documentation() {
4482
4488
  const valid = [
@@ -4587,14 +4593,14 @@ class CaseStyle {
4587
4593
  }
4588
4594
  }
4589
4595
 
4590
- const defaults$u = {
4596
+ const defaults$v = {
4591
4597
  style: "lowercase",
4592
4598
  ignoreForeign: true
4593
4599
  };
4594
4600
  class AttrCase extends Rule {
4595
4601
  style;
4596
4602
  constructor(options) {
4597
- super({ ...defaults$u, ...options });
4603
+ super({ ...defaults$v, ...options });
4598
4604
  this.style = new CaseStyle(this.options.style, "attr-case");
4599
4605
  }
4600
4606
  static schema() {
@@ -4952,7 +4958,7 @@ class AttrDelimiter extends Rule {
4952
4958
  }
4953
4959
 
4954
4960
  const DEFAULT_PATTERN = "[a-z0-9-:]+";
4955
- const defaults$t = {
4961
+ const defaults$u = {
4956
4962
  pattern: DEFAULT_PATTERN,
4957
4963
  ignoreForeign: true
4958
4964
  };
@@ -4985,7 +4991,7 @@ function generateDescription(name, pattern) {
4985
4991
  class AttrPattern extends Rule {
4986
4992
  pattern;
4987
4993
  constructor(options) {
4988
- super({ ...defaults$t, ...options });
4994
+ super({ ...defaults$u, ...options });
4989
4995
  this.pattern = generateRegexp(this.options.pattern);
4990
4996
  }
4991
4997
  static schema() {
@@ -5032,7 +5038,7 @@ class AttrPattern extends Rule {
5032
5038
  }
5033
5039
  }
5034
5040
 
5035
- const defaults$s = {
5041
+ const defaults$t = {
5036
5042
  style: "auto",
5037
5043
  unquoted: false
5038
5044
  };
@@ -5098,7 +5104,7 @@ class AttrQuotes extends Rule {
5098
5104
  };
5099
5105
  }
5100
5106
  constructor(options) {
5101
- super({ ...defaults$s, ...options });
5107
+ super({ ...defaults$t, ...options });
5102
5108
  this.style = parseStyle$3(this.options.style);
5103
5109
  }
5104
5110
  setup() {
@@ -5255,13 +5261,13 @@ class AttributeAllowedValues extends Rule {
5255
5261
  }
5256
5262
  }
5257
5263
 
5258
- const defaults$r = {
5264
+ const defaults$s = {
5259
5265
  style: "omit"
5260
5266
  };
5261
5267
  class AttributeBooleanStyle extends Rule {
5262
5268
  hasInvalidStyle;
5263
5269
  constructor(options) {
5264
- super({ ...defaults$r, ...options });
5270
+ super({ ...defaults$s, ...options });
5265
5271
  this.hasInvalidStyle = parseStyle$2(this.options.style);
5266
5272
  }
5267
5273
  static schema() {
@@ -5327,13 +5333,13 @@ function reportMessage$1(attr, style) {
5327
5333
  return "";
5328
5334
  }
5329
5335
 
5330
- const defaults$q = {
5336
+ const defaults$r = {
5331
5337
  style: "omit"
5332
5338
  };
5333
5339
  class AttributeEmptyStyle extends Rule {
5334
5340
  hasInvalidStyle;
5335
5341
  constructor(options) {
5336
- super({ ...defaults$q, ...options });
5342
+ super({ ...defaults$r, ...options });
5337
5343
  this.hasInvalidStyle = parseStyle$1(this.options.style);
5338
5344
  }
5339
5345
  static schema() {
@@ -5528,12 +5534,12 @@ class BasePatternRule extends Rule {
5528
5534
  }
5529
5535
  }
5530
5536
 
5531
- const defaults$p = {
5537
+ const defaults$q = {
5532
5538
  pattern: "kebabcase"
5533
5539
  };
5534
5540
  class ClassPattern extends BasePatternRule {
5535
5541
  constructor(options) {
5536
- super("class", { ...defaults$p, ...options });
5542
+ super("class", { ...defaults$q, ...options });
5537
5543
  }
5538
5544
  static schema() {
5539
5545
  return BasePatternRule.schema();
@@ -5680,13 +5686,13 @@ class CloseOrder extends Rule {
5680
5686
  }
5681
5687
  }
5682
5688
 
5683
- const defaults$o = {
5689
+ const defaults$p = {
5684
5690
  include: null,
5685
5691
  exclude: null
5686
5692
  };
5687
5693
  class Deprecated extends Rule {
5688
5694
  constructor(options) {
5689
- super({ ...defaults$o, ...options });
5695
+ super({ ...defaults$p, ...options });
5690
5696
  }
5691
5697
  static schema() {
5692
5698
  return {
@@ -5840,12 +5846,12 @@ let NoStyleTag$1 = class NoStyleTag extends Rule {
5840
5846
  }
5841
5847
  };
5842
5848
 
5843
- const defaults$n = {
5849
+ const defaults$o = {
5844
5850
  style: "uppercase"
5845
5851
  };
5846
5852
  class DoctypeStyle extends Rule {
5847
5853
  constructor(options) {
5848
- super({ ...defaults$n, ...options });
5854
+ super({ ...defaults$o, ...options });
5849
5855
  }
5850
5856
  static schema() {
5851
5857
  return {
@@ -5873,13 +5879,13 @@ class DoctypeStyle extends Rule {
5873
5879
  }
5874
5880
  }
5875
5881
 
5876
- const defaults$m = {
5882
+ const defaults$n = {
5877
5883
  style: "lowercase"
5878
5884
  };
5879
5885
  class ElementCase extends Rule {
5880
5886
  style;
5881
5887
  constructor(options) {
5882
- super({ ...defaults$m, ...options });
5888
+ super({ ...defaults$n, ...options });
5883
5889
  this.style = new CaseStyle(this.options.style, "element-case");
5884
5890
  }
5885
5891
  static schema() {
@@ -5939,7 +5945,7 @@ class ElementCase extends Rule {
5939
5945
  }
5940
5946
  }
5941
5947
 
5942
- const defaults$l = {
5948
+ const defaults$m = {
5943
5949
  pattern: "^[a-z][a-z0-9\\-._]*-[a-z0-9\\-._]*$",
5944
5950
  whitelist: [],
5945
5951
  blacklist: []
@@ -5947,7 +5953,7 @@ const defaults$l = {
5947
5953
  class ElementName extends Rule {
5948
5954
  pattern;
5949
5955
  constructor(options) {
5950
- super({ ...defaults$l, ...options });
5956
+ super({ ...defaults$m, ...options });
5951
5957
  this.pattern = new RegExp(this.options.pattern);
5952
5958
  }
5953
5959
  static schema() {
@@ -5984,7 +5990,7 @@ class ElementName extends Rule {
5984
5990
  ...context.blacklist.map((cur) => `- ${cur}`)
5985
5991
  ];
5986
5992
  }
5987
- if (context.pattern !== defaults$l.pattern) {
5993
+ if (context.pattern !== defaults$m.pattern) {
5988
5994
  return [
5989
5995
  `<${context.tagName}> is not a valid element name. This project is configured to only allow names matching the following regular expression:`,
5990
5996
  "",
@@ -6029,6 +6035,10 @@ class ElementName extends Rule {
6029
6035
  }
6030
6036
  }
6031
6037
 
6038
+ function isNativeTemplate(node) {
6039
+ const { tagName, meta } = node;
6040
+ return Boolean(tagName === "template" && meta?.templateRoot && meta?.scriptSupporting);
6041
+ }
6032
6042
  function getTransparentChildren(node, transparent) {
6033
6043
  if (typeof transparent === "boolean") {
6034
6044
  return node.childElements;
@@ -6102,7 +6112,7 @@ class ElementPermittedContent extends Rule {
6102
6112
  return false;
6103
6113
  }
6104
6114
  validatePermittedDescendant(node, parent) {
6105
- for (let cur = parent; cur && !cur.isRootElement() && cur.tagName !== "template"; cur = /* istanbul ignore next */
6115
+ for (let cur = parent; cur && !cur.isRootElement() && !isNativeTemplate(cur); cur = /* istanbul ignore next */
6106
6116
  cur.parent ?? null) {
6107
6117
  const meta = cur.meta;
6108
6118
  if (!meta) {
@@ -6470,7 +6480,7 @@ class EmptyTitle extends Rule {
6470
6480
  }
6471
6481
  }
6472
6482
 
6473
- const defaults$k = {
6483
+ const defaults$l = {
6474
6484
  allowArrayBrackets: true,
6475
6485
  allowCheckboxDefault: true,
6476
6486
  shared: ["radio", "button", "reset", "submit"]
@@ -6518,7 +6528,7 @@ function getDocumentation(context) {
6518
6528
  }
6519
6529
  class FormDupName extends Rule {
6520
6530
  constructor(options) {
6521
- super({ ...defaults$k, ...options });
6531
+ super({ ...defaults$l, ...options });
6522
6532
  }
6523
6533
  static schema() {
6524
6534
  return {
@@ -6677,7 +6687,7 @@ class FormDupName extends Rule {
6677
6687
  }
6678
6688
  }
6679
6689
 
6680
- const defaults$j = {
6690
+ const defaults$k = {
6681
6691
  allowMultipleH1: false,
6682
6692
  minInitialRank: "h1",
6683
6693
  sectioningRoots: ["dialog", '[role="dialog"]', '[role="alertdialog"]']
@@ -6709,7 +6719,7 @@ class HeadingLevel extends Rule {
6709
6719
  sectionRoots;
6710
6720
  stack = [];
6711
6721
  constructor(options) {
6712
- super({ ...defaults$j, ...options });
6722
+ super({ ...defaults$k, ...options });
6713
6723
  this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
6714
6724
  this.sectionRoots = this.options.sectioningRoots.map((it) => new Compound(it));
6715
6725
  this.stack.push({
@@ -6946,12 +6956,12 @@ class HiddenFocusable extends Rule {
6946
6956
  }
6947
6957
  }
6948
6958
 
6949
- const defaults$i = {
6959
+ const defaults$j = {
6950
6960
  pattern: "kebabcase"
6951
6961
  };
6952
6962
  class IdPattern extends BasePatternRule {
6953
6963
  constructor(options) {
6954
- super("id", { ...defaults$i, ...options });
6964
+ super("id", { ...defaults$j, ...options });
6955
6965
  }
6956
6966
  static schema() {
6957
6967
  return BasePatternRule.schema();
@@ -7269,13 +7279,13 @@ function findLabelByParent(el) {
7269
7279
  return [];
7270
7280
  }
7271
7281
 
7272
- const defaults$h = {
7282
+ const defaults$i = {
7273
7283
  maxlength: 70
7274
7284
  };
7275
7285
  class LongTitle extends Rule {
7276
7286
  maxlength;
7277
7287
  constructor(options) {
7278
- super({ ...defaults$h, ...options });
7288
+ super({ ...defaults$i, ...options });
7279
7289
  this.maxlength = this.options.maxlength;
7280
7290
  }
7281
7291
  static schema() {
@@ -7303,12 +7313,12 @@ class LongTitle extends Rule {
7303
7313
  }
7304
7314
  }
7305
7315
 
7306
- const defaults$g = {
7316
+ const defaults$h = {
7307
7317
  allowLongDelay: false
7308
7318
  };
7309
7319
  class MetaRefresh extends Rule {
7310
7320
  constructor(options) {
7311
- super({ ...defaults$g, ...options });
7321
+ super({ ...defaults$h, ...options });
7312
7322
  }
7313
7323
  documentation() {
7314
7324
  return {
@@ -7493,12 +7503,12 @@ class MultipleLabeledControls extends Rule {
7493
7503
  }
7494
7504
  }
7495
7505
 
7496
- const defaults$f = {
7506
+ const defaults$g = {
7497
7507
  pattern: "camelcase"
7498
7508
  };
7499
7509
  class NamePattern extends BasePatternRule {
7500
7510
  constructor(options) {
7501
- super("name", { ...defaults$f, ...options });
7511
+ super("name", { ...defaults$g, ...options });
7502
7512
  }
7503
7513
  static schema() {
7504
7514
  return BasePatternRule.schema();
@@ -7587,13 +7597,13 @@ class NoAbstractRole extends Rule {
7587
7597
  }
7588
7598
  }
7589
7599
 
7590
- const defaults$e = {
7600
+ const defaults$f = {
7591
7601
  include: null,
7592
7602
  exclude: null
7593
7603
  };
7594
7604
  class NoAutoplay extends Rule {
7595
7605
  constructor(options) {
7596
- super({ ...defaults$e, ...options });
7606
+ super({ ...defaults$f, ...options });
7597
7607
  }
7598
7608
  documentation(context) {
7599
7609
  return {
@@ -7912,14 +7922,14 @@ Omitted end tags can be ambigious for humans to read and many editors have troub
7912
7922
  }
7913
7923
  }
7914
7924
 
7915
- const defaults$d = {
7925
+ const defaults$e = {
7916
7926
  include: null,
7917
7927
  exclude: null,
7918
7928
  allowedProperties: ["display"]
7919
7929
  };
7920
7930
  class NoInlineStyle extends Rule {
7921
7931
  constructor(options) {
7922
- super({ ...defaults$d, ...options });
7932
+ super({ ...defaults$e, ...options });
7923
7933
  }
7924
7934
  static schema() {
7925
7935
  return {
@@ -8105,7 +8115,7 @@ class NoMultipleMain extends Rule {
8105
8115
  }
8106
8116
  }
8107
8117
 
8108
- const defaults$c = {
8118
+ const defaults$d = {
8109
8119
  relaxed: false
8110
8120
  };
8111
8121
  const textRegexp = /([<>]|&(?![a-zA-Z0-9#]+;))/g;
@@ -8123,7 +8133,7 @@ const replacementTable = {
8123
8133
  class NoRawCharacters extends Rule {
8124
8134
  relaxed;
8125
8135
  constructor(options) {
8126
- super({ ...defaults$c, ...options });
8136
+ super({ ...defaults$d, ...options });
8127
8137
  this.relaxed = this.options.relaxed;
8128
8138
  }
8129
8139
  static schema() {
@@ -8296,13 +8306,13 @@ class NoRedundantRole extends Rule {
8296
8306
  }
8297
8307
 
8298
8308
  const xmlns = /^(.+):.+$/;
8299
- const defaults$b = {
8309
+ const defaults$c = {
8300
8310
  ignoreForeign: true,
8301
8311
  ignoreXML: true
8302
8312
  };
8303
8313
  class NoSelfClosing extends Rule {
8304
8314
  constructor(options) {
8305
- super({ ...defaults$b, ...options });
8315
+ super({ ...defaults$c, ...options });
8306
8316
  }
8307
8317
  static schema() {
8308
8318
  return {
@@ -8386,13 +8396,13 @@ class NoTrailingWhitespace extends Rule {
8386
8396
  }
8387
8397
  }
8388
8398
 
8389
- const defaults$a = {
8399
+ const defaults$b = {
8390
8400
  include: null,
8391
8401
  exclude: null
8392
8402
  };
8393
8403
  class NoUnknownElements extends Rule {
8394
8404
  constructor(options) {
8395
- super({ ...defaults$a, ...options });
8405
+ super({ ...defaults$b, ...options });
8396
8406
  }
8397
8407
  static schema() {
8398
8408
  return {
@@ -8498,13 +8508,13 @@ const replacement = {
8498
8508
  reset: '<button type="reset">',
8499
8509
  image: '<button type="button">'
8500
8510
  };
8501
- const defaults$9 = {
8511
+ const defaults$a = {
8502
8512
  include: null,
8503
8513
  exclude: null
8504
8514
  };
8505
8515
  class PreferButton extends Rule {
8506
8516
  constructor(options) {
8507
- super({ ...defaults$9, ...options });
8517
+ super({ ...defaults$a, ...options });
8508
8518
  }
8509
8519
  static schema() {
8510
8520
  return {
@@ -8570,7 +8580,7 @@ class PreferButton extends Rule {
8570
8580
  }
8571
8581
  }
8572
8582
 
8573
- const defaults$8 = {
8583
+ const defaults$9 = {
8574
8584
  mapping: {
8575
8585
  article: "article",
8576
8586
  banner: "header",
@@ -8600,7 +8610,7 @@ const defaults$8 = {
8600
8610
  };
8601
8611
  class PreferNativeElement extends Rule {
8602
8612
  constructor(options) {
8603
- super({ ...defaults$8, ...options });
8613
+ super({ ...defaults$9, ...options });
8604
8614
  }
8605
8615
  static schema() {
8606
8616
  return {
@@ -8714,12 +8724,12 @@ class PreferTbody extends Rule {
8714
8724
  }
8715
8725
  }
8716
8726
 
8717
- const defaults$7 = {
8727
+ const defaults$8 = {
8718
8728
  tags: ["script", "style"]
8719
8729
  };
8720
8730
  class RequireCSPNonce extends Rule {
8721
8731
  constructor(options) {
8722
- super({ ...defaults$7, ...options });
8732
+ super({ ...defaults$8, ...options });
8723
8733
  }
8724
8734
  static schema() {
8725
8735
  return {
@@ -8766,7 +8776,7 @@ class RequireCSPNonce extends Rule {
8766
8776
  }
8767
8777
  }
8768
8778
 
8769
- const defaults$6 = {
8779
+ const defaults$7 = {
8770
8780
  target: "all",
8771
8781
  include: null,
8772
8782
  exclude: null
@@ -8795,7 +8805,7 @@ function linkSupportsSri(node) {
8795
8805
  class RequireSri extends Rule {
8796
8806
  target;
8797
8807
  constructor(options) {
8798
- super({ ...defaults$6, ...options });
8808
+ super({ ...defaults$7, ...options });
8799
8809
  this.target = this.options.target;
8800
8810
  }
8801
8811
  static schema() {
@@ -8968,7 +8978,7 @@ class SvgFocusable extends Rule {
8968
8978
  }
8969
8979
  }
8970
8980
 
8971
- const defaults$5 = {
8981
+ const defaults$6 = {
8972
8982
  characters: [
8973
8983
  { pattern: " ", replacement: "&nbsp;", description: "non-breaking space" },
8974
8984
  { pattern: "-", replacement: "&#8209;", description: "non-breaking hyphen" }
@@ -9000,7 +9010,7 @@ function matchAll(text, regexp) {
9000
9010
  class TelNonBreaking extends Rule {
9001
9011
  regex;
9002
9012
  constructor(options) {
9003
- super({ ...defaults$5, ...options });
9013
+ super({ ...defaults$6, ...options });
9004
9014
  this.regex = constructRegex(this.options.characters);
9005
9015
  }
9006
9016
  static schema() {
@@ -9375,7 +9385,7 @@ class UniqueLandmark extends Rule {
9375
9385
  }
9376
9386
  }
9377
9387
 
9378
- const defaults$4 = {
9388
+ const defaults$5 = {
9379
9389
  ignoreCase: false,
9380
9390
  requireSemicolon: true
9381
9391
  };
@@ -9409,7 +9419,7 @@ function getDescription(context, options) {
9409
9419
  }
9410
9420
  class UnknownCharReference extends Rule {
9411
9421
  constructor(options) {
9412
- super({ ...defaults$4, ...options });
9422
+ super({ ...defaults$5, ...options });
9413
9423
  }
9414
9424
  static schema() {
9415
9425
  return {
@@ -10025,12 +10035,12 @@ class ValidAutocomplete extends Rule {
10025
10035
  }
10026
10036
  }
10027
10037
 
10028
- const defaults$3 = {
10038
+ const defaults$4 = {
10029
10039
  relaxed: false
10030
10040
  };
10031
10041
  class ValidID extends Rule {
10032
10042
  constructor(options) {
10033
- super({ ...defaults$3, ...options });
10043
+ super({ ...defaults$4, ...options });
10034
10044
  }
10035
10045
  static schema() {
10036
10046
  return {
@@ -10136,13 +10146,13 @@ class VoidContent extends Rule {
10136
10146
  }
10137
10147
  }
10138
10148
 
10139
- const defaults$2 = {
10149
+ const defaults$3 = {
10140
10150
  style: "omit"
10141
10151
  };
10142
10152
  class VoidStyle extends Rule {
10143
10153
  style;
10144
10154
  constructor(options) {
10145
- super({ ...defaults$2, ...options });
10155
+ super({ ...defaults$3, ...options });
10146
10156
  this.style = parseStyle(this.options.style);
10147
10157
  }
10148
10158
  static schema() {
@@ -10343,13 +10353,13 @@ class H36 extends Rule {
10343
10353
  }
10344
10354
  }
10345
10355
 
10346
- const defaults$1 = {
10356
+ const defaults$2 = {
10347
10357
  allowEmpty: true,
10348
10358
  alias: []
10349
10359
  };
10350
10360
  class H37 extends Rule {
10351
10361
  constructor(options) {
10352
- super({ ...defaults$1, ...options });
10362
+ super({ ...defaults$2, ...options });
10353
10363
  if (!Array.isArray(this.options.alias)) {
10354
10364
  this.options.alias = [this.options.alias];
10355
10365
  }
@@ -10411,9 +10421,62 @@ class H37 extends Rule {
10411
10421
  }
10412
10422
  }
10413
10423
 
10424
+ const defaults$1 = {
10425
+ strict: false
10426
+ };
10414
10427
  const { enum: validScopes } = elements.html5.th.attributes?.scope;
10415
10428
  const joinedScopes = utils_naturalJoin.naturalJoin(validScopes);
10429
+ const td = 0;
10430
+ const th = 1;
10431
+ function getShape(cells) {
10432
+ const rows = cells.length;
10433
+ const cols = cells[0].length;
10434
+ return { rows, cols };
10435
+ }
10436
+ function isSimpleTable(table) {
10437
+ const haveHeadersAttr = table.querySelector("> tr > [headers], > tbody > tr > [headers]");
10438
+ if (haveHeadersAttr) {
10439
+ return false;
10440
+ }
10441
+ const rows = table.querySelectorAll("> tr, > thead > tr, > tbody > tr");
10442
+ if (rows.length === 0) {
10443
+ return false;
10444
+ }
10445
+ const cells = rows.map((tr) => tr.querySelectorAll("> *").map((el) => el.is("th") ? th : td));
10446
+ if (cells[0].length === 0) {
10447
+ return false;
10448
+ }
10449
+ const numColumns = cells[0].length;
10450
+ if (!cells.every((row) => row.length === numColumns)) {
10451
+ return false;
10452
+ }
10453
+ const shape = getShape(cells);
10454
+ const headersPerRow = cells.map((row) => row.reduce((sum, cell) => sum + cell, 0));
10455
+ const headersPerColumn = Array(shape.cols).fill(0).map((_, index) => {
10456
+ return cells.reduce((sum, it) => sum + it[index], 0);
10457
+ });
10458
+ const [firstRow, ...otherRows] = headersPerRow;
10459
+ if (firstRow === shape.cols && otherRows.every((row) => row === 0)) {
10460
+ return true;
10461
+ }
10462
+ const [firstCol, ...otherCols] = headersPerColumn;
10463
+ const haveThead = Boolean(table.querySelector("> thead"));
10464
+ if (firstCol === shape.rows && otherCols.every((col) => col === 0) && !haveThead) {
10465
+ return true;
10466
+ }
10467
+ return false;
10468
+ }
10416
10469
  class H63 extends Rule {
10470
+ constructor(options) {
10471
+ super({ ...defaults$1, ...options });
10472
+ }
10473
+ static schema() {
10474
+ return {
10475
+ strict: {
10476
+ type: "boolean"
10477
+ }
10478
+ };
10479
+ }
10417
10480
  documentation() {
10418
10481
  return {
10419
10482
  description: "H63: Using the scope attribute to associate header cells and data cells in data tables",
@@ -10421,23 +10484,31 @@ class H63 extends Rule {
10421
10484
  };
10422
10485
  }
10423
10486
  setup() {
10424
- this.on("tag:ready", (event) => {
10487
+ const { strict } = this.options;
10488
+ this.on("element:ready", (event) => {
10425
10489
  const node = event.target;
10426
- if (node.tagName !== "th") {
10490
+ if (!node.is("table")) {
10427
10491
  return;
10428
10492
  }
10429
- const scope = node.getAttribute("scope");
10493
+ if (strict || !isSimpleTable(node)) {
10494
+ this.validateTable(node);
10495
+ }
10496
+ });
10497
+ }
10498
+ validateTable(node) {
10499
+ for (const th2 of node.querySelectorAll("th")) {
10500
+ const scope = th2.getAttribute("scope");
10430
10501
  const value = scope?.value;
10431
10502
  if (value instanceof DynamicValue) {
10432
- return;
10503
+ continue;
10433
10504
  }
10434
10505
  if (value && validScopes.includes(value)) {
10435
- return;
10506
+ continue;
10436
10507
  }
10437
10508
  const message = `<th> element must have a valid scope attribute: ${joinedScopes}`;
10438
- const location = scope?.valueLocation ?? scope?.keyLocation ?? node.location;
10439
- this.report(node, message, location);
10440
- });
10509
+ const location = scope?.valueLocation ?? scope?.keyLocation ?? th2.location;
10510
+ this.report(th2, message, location);
10511
+ }
10441
10512
  }
10442
10513
  }
10443
10514
 
@@ -11729,7 +11800,7 @@ class EventHandler {
11729
11800
  }
11730
11801
 
11731
11802
  const name = "html-validate";
11732
- const version = "9.6.0";
11803
+ const version = "9.7.0";
11733
11804
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
11734
11805
 
11735
11806
  function freeze(src) {