html-validate 6.8.0 → 6.9.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/es/core.js CHANGED
@@ -1978,9 +1978,10 @@ class HtmlElement extends DOMNode {
1978
1978
  /* if a unique id is present, use it and short-circuit */
1979
1979
  if (cur.id) {
1980
1980
  const escaped = escapeSelectorComponent(cur.id);
1981
- const matches = root.querySelectorAll(`#${escaped}`);
1981
+ const selector = escaped.match(/^\d/) ? `[id="${escaped}"]` : `#${escaped}`;
1982
+ const matches = root.querySelectorAll(selector);
1982
1983
  if (matches.length === 1) {
1983
- parts.push(`#${escaped}`);
1984
+ parts.push(selector);
1984
1985
  break;
1985
1986
  }
1986
1987
  }
@@ -2980,7 +2981,7 @@ var TRANSFORMER_API;
2980
2981
  /** @public */
2981
2982
  const name = "html-validate";
2982
2983
  /** @public */
2983
- const version = "6.8.0";
2984
+ const version = "6.9.0";
2984
2985
  /** @public */
2985
2986
  const homepage = "https://html-validate.org";
2986
2987
  /** @public */
@@ -3301,7 +3302,7 @@ function ruleDocumentationUrl(filename) {
3301
3302
  return `${homepage}/rules/${normalized}.html`;
3302
3303
  }
3303
3304
 
3304
- const defaults$q = {
3305
+ const defaults$r = {
3305
3306
  allowExternal: true,
3306
3307
  allowRelative: true,
3307
3308
  allowAbsolute: true,
@@ -3345,7 +3346,7 @@ function matchList(value, list) {
3345
3346
  }
3346
3347
  class AllowedLinks extends Rule {
3347
3348
  constructor(options) {
3348
- super({ ...defaults$q, ...options });
3349
+ super({ ...defaults$r, ...options });
3349
3350
  this.allowExternal = parseAllow(this.options.allowExternal);
3350
3351
  this.allowRelative = parseAllow(this.options.allowRelative);
3351
3352
  this.allowAbsolute = parseAllow(this.options.allowAbsolute);
@@ -3646,13 +3647,13 @@ class CaseStyle {
3646
3647
  }
3647
3648
  }
3648
3649
 
3649
- const defaults$p = {
3650
+ const defaults$q = {
3650
3651
  style: "lowercase",
3651
3652
  ignoreForeign: true,
3652
3653
  };
3653
3654
  class AttrCase extends Rule {
3654
3655
  constructor(options) {
3655
- super({ ...defaults$p, ...options });
3656
+ super({ ...defaults$q, ...options });
3656
3657
  this.style = new CaseStyle(this.options.style, "attr-case");
3657
3658
  }
3658
3659
  static schema() {
@@ -3991,7 +3992,7 @@ class AttrDelimiter extends Rule {
3991
3992
  }
3992
3993
 
3993
3994
  const DEFAULT_PATTERN = "[a-z0-9-:]+";
3994
- const defaults$o = {
3995
+ const defaults$p = {
3995
3996
  pattern: DEFAULT_PATTERN,
3996
3997
  ignoreForeign: true,
3997
3998
  };
@@ -4028,7 +4029,7 @@ function generateDescription(name, pattern) {
4028
4029
  }
4029
4030
  class AttrPattern extends Rule {
4030
4031
  constructor(options) {
4031
- super({ ...defaults$o, ...options });
4032
+ super({ ...defaults$p, ...options });
4032
4033
  this.pattern = generateRegexp(this.options.pattern);
4033
4034
  }
4034
4035
  static schema() {
@@ -4088,13 +4089,13 @@ var QuoteStyle;
4088
4089
  QuoteStyle["DOUBLE_QUOTE"] = "\"";
4089
4090
  QuoteStyle["AUTO_QUOTE"] = "auto";
4090
4091
  })(QuoteStyle || (QuoteStyle = {}));
4091
- const defaults$n = {
4092
+ const defaults$o = {
4092
4093
  style: "auto",
4093
4094
  unquoted: false,
4094
4095
  };
4095
4096
  class AttrQuotes extends Rule {
4096
4097
  constructor(options) {
4097
- super({ ...defaults$n, ...options });
4098
+ super({ ...defaults$o, ...options });
4098
4099
  this.style = parseStyle$4(this.options.style);
4099
4100
  }
4100
4101
  static schema() {
@@ -4259,12 +4260,12 @@ class AttributeAllowedValues extends Rule {
4259
4260
  }
4260
4261
  }
4261
4262
 
4262
- const defaults$m = {
4263
+ const defaults$n = {
4263
4264
  style: "omit",
4264
4265
  };
4265
4266
  class AttributeBooleanStyle extends Rule {
4266
4267
  constructor(options) {
4267
- super({ ...defaults$m, ...options });
4268
+ super({ ...defaults$n, ...options });
4268
4269
  this.hasInvalidStyle = parseStyle$3(this.options.style);
4269
4270
  }
4270
4271
  static schema() {
@@ -4340,12 +4341,12 @@ function reportMessage$1(attr, style) {
4340
4341
  return "";
4341
4342
  }
4342
4343
 
4343
- const defaults$l = {
4344
+ const defaults$m = {
4344
4345
  style: "omit",
4345
4346
  };
4346
4347
  class AttributeEmptyStyle extends Rule {
4347
4348
  constructor(options) {
4348
- super({ ...defaults$l, ...options });
4349
+ super({ ...defaults$m, ...options });
4349
4350
  this.hasInvalidStyle = parseStyle$2(this.options.style);
4350
4351
  }
4351
4352
  static schema() {
@@ -4453,12 +4454,12 @@ function describePattern(pattern) {
4453
4454
  }
4454
4455
  }
4455
4456
 
4456
- const defaults$k = {
4457
+ const defaults$l = {
4457
4458
  pattern: "kebabcase",
4458
4459
  };
4459
4460
  class ClassPattern extends Rule {
4460
4461
  constructor(options) {
4461
- super({ ...defaults$k, ...options });
4462
+ super({ ...defaults$l, ...options });
4462
4463
  this.pattern = parsePattern(this.options.pattern);
4463
4464
  }
4464
4465
  static schema() {
@@ -4567,13 +4568,13 @@ class CloseOrder extends Rule {
4567
4568
  }
4568
4569
  }
4569
4570
 
4570
- const defaults$j = {
4571
+ const defaults$k = {
4571
4572
  include: null,
4572
4573
  exclude: null,
4573
4574
  };
4574
4575
  class Deprecated extends Rule {
4575
4576
  constructor(options) {
4576
- super({ ...defaults$j, ...options });
4577
+ super({ ...defaults$k, ...options });
4577
4578
  }
4578
4579
  static schema() {
4579
4580
  return {
@@ -4736,12 +4737,12 @@ class NoStyleTag$1 extends Rule {
4736
4737
  }
4737
4738
  }
4738
4739
 
4739
- const defaults$i = {
4740
+ const defaults$j = {
4740
4741
  style: "uppercase",
4741
4742
  };
4742
4743
  class DoctypeStyle extends Rule {
4743
4744
  constructor(options) {
4744
- super({ ...defaults$i, ...options });
4745
+ super({ ...defaults$j, ...options });
4745
4746
  }
4746
4747
  static schema() {
4747
4748
  return {
@@ -4773,12 +4774,12 @@ class DoctypeStyle extends Rule {
4773
4774
  }
4774
4775
  }
4775
4776
 
4776
- const defaults$h = {
4777
+ const defaults$i = {
4777
4778
  style: "lowercase",
4778
4779
  };
4779
4780
  class ElementCase extends Rule {
4780
4781
  constructor(options) {
4781
- super({ ...defaults$h, ...options });
4782
+ super({ ...defaults$i, ...options });
4782
4783
  this.style = new CaseStyle(this.options.style, "element-case");
4783
4784
  }
4784
4785
  static schema() {
@@ -4844,14 +4845,14 @@ class ElementCase extends Rule {
4844
4845
  }
4845
4846
  }
4846
4847
 
4847
- const defaults$g = {
4848
+ const defaults$h = {
4848
4849
  pattern: "^[a-z][a-z0-9\\-._]*-[a-z0-9\\-._]*$",
4849
4850
  whitelist: [],
4850
4851
  blacklist: [],
4851
4852
  };
4852
4853
  class ElementName extends Rule {
4853
4854
  constructor(options) {
4854
- super({ ...defaults$g, ...options });
4855
+ super({ ...defaults$h, ...options });
4855
4856
  // eslint-disable-next-line security/detect-non-literal-regexp
4856
4857
  this.pattern = new RegExp(this.options.pattern);
4857
4858
  }
@@ -4892,7 +4893,7 @@ class ElementName extends Rule {
4892
4893
  ...context.blacklist.map((cur) => `- ${cur}`),
4893
4894
  ];
4894
4895
  }
4895
- if (context.pattern !== defaults$g.pattern) {
4896
+ if (context.pattern !== defaults$h.pattern) {
4896
4897
  return [
4897
4898
  `<${context.tagName}> is not a valid element name. This project is configured to only allow names matching the following regular expression:`,
4898
4899
  "",
@@ -5294,7 +5295,7 @@ class EmptyTitle extends Rule {
5294
5295
  }
5295
5296
  }
5296
5297
 
5297
- const defaults$f = {
5298
+ const defaults$g = {
5298
5299
  allowMultipleH1: false,
5299
5300
  minInitialRank: "h1",
5300
5301
  sectioningRoots: ["dialog", '[role="dialog"]'],
@@ -5325,7 +5326,7 @@ function parseMaxInitial(value) {
5325
5326
  }
5326
5327
  class HeadingLevel extends Rule {
5327
5328
  constructor(options) {
5328
- super({ ...defaults$f, ...options });
5329
+ super({ ...defaults$g, ...options });
5329
5330
  this.stack = [];
5330
5331
  this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
5331
5332
  this.sectionRoots = this.options.sectioningRoots.map((it) => new Pattern(it));
@@ -5483,12 +5484,12 @@ class HeadingLevel extends Rule {
5483
5484
  }
5484
5485
  }
5485
5486
 
5486
- const defaults$e = {
5487
+ const defaults$f = {
5487
5488
  pattern: "kebabcase",
5488
5489
  };
5489
5490
  class IdPattern extends Rule {
5490
5491
  constructor(options) {
5491
- super({ ...defaults$e, ...options });
5492
+ super({ ...defaults$f, ...options });
5492
5493
  this.pattern = parsePattern(this.options.pattern);
5493
5494
  }
5494
5495
  static schema() {
@@ -5839,12 +5840,12 @@ function findLabelByParent(el) {
5839
5840
  return [];
5840
5841
  }
5841
5842
 
5842
- const defaults$d = {
5843
+ const defaults$e = {
5843
5844
  maxlength: 70,
5844
5845
  };
5845
5846
  class LongTitle extends Rule {
5846
5847
  constructor(options) {
5847
- super({ ...defaults$d, ...options });
5848
+ super({ ...defaults$e, ...options });
5848
5849
  this.maxlength = this.options.maxlength;
5849
5850
  }
5850
5851
  static schema() {
@@ -5991,13 +5992,13 @@ class MultipleLabeledControls extends Rule {
5991
5992
  }
5992
5993
  }
5993
5994
 
5994
- const defaults$c = {
5995
+ const defaults$d = {
5995
5996
  include: null,
5996
5997
  exclude: null,
5997
5998
  };
5998
5999
  class NoAutoplay extends Rule {
5999
6000
  constructor(options) {
6000
- super({ ...defaults$c, ...options });
6001
+ super({ ...defaults$d, ...options });
6001
6002
  }
6002
6003
  documentation(context) {
6003
6004
  const tagName = context ? ` on <${context.tagName}>` : "";
@@ -6238,14 +6239,14 @@ Omitted end tags can be ambigious for humans to read and many editors have troub
6238
6239
  }
6239
6240
  }
6240
6241
 
6241
- const defaults$b = {
6242
+ const defaults$c = {
6242
6243
  include: null,
6243
6244
  exclude: null,
6244
6245
  allowedProperties: ["display"],
6245
6246
  };
6246
6247
  class NoInlineStyle extends Rule {
6247
6248
  constructor(options) {
6248
- super({ ...defaults$b, ...options });
6249
+ super({ ...defaults$c, ...options });
6249
6250
  }
6250
6251
  static schema() {
6251
6252
  return {
@@ -6447,7 +6448,7 @@ class NoMultipleMain extends Rule {
6447
6448
  }
6448
6449
  }
6449
6450
 
6450
- const defaults$a = {
6451
+ const defaults$b = {
6451
6452
  relaxed: false,
6452
6453
  };
6453
6454
  const textRegexp = /([<>]|&(?![a-zA-Z0-9#]+;))/g;
@@ -6464,7 +6465,7 @@ const replacementTable = {
6464
6465
  };
6465
6466
  class NoRawCharacters extends Rule {
6466
6467
  constructor(options) {
6467
- super({ ...defaults$a, ...options });
6468
+ super({ ...defaults$b, ...options });
6468
6469
  this.relaxed = this.options.relaxed;
6469
6470
  }
6470
6471
  static schema() {
@@ -6642,13 +6643,13 @@ class NoRedundantRole extends Rule {
6642
6643
  }
6643
6644
 
6644
6645
  const xmlns = /^(.+):.+$/;
6645
- const defaults$9 = {
6646
+ const defaults$a = {
6646
6647
  ignoreForeign: true,
6647
6648
  ignoreXML: true,
6648
6649
  };
6649
6650
  class NoSelfClosing extends Rule {
6650
6651
  constructor(options) {
6651
- super({ ...defaults$9, ...options });
6652
+ super({ ...defaults$a, ...options });
6652
6653
  }
6653
6654
  static schema() {
6654
6655
  return {
@@ -6781,13 +6782,13 @@ const replacement = {
6781
6782
  reset: '<button type="reset">',
6782
6783
  image: '<button type="button">',
6783
6784
  };
6784
- const defaults$8 = {
6785
+ const defaults$9 = {
6785
6786
  include: null,
6786
6787
  exclude: null,
6787
6788
  };
6788
6789
  class PreferButton extends Rule {
6789
6790
  constructor(options) {
6790
- super({ ...defaults$8, ...options });
6791
+ super({ ...defaults$9, ...options });
6791
6792
  }
6792
6793
  static schema() {
6793
6794
  return {
@@ -6862,7 +6863,7 @@ class PreferButton extends Rule {
6862
6863
  }
6863
6864
  }
6864
6865
 
6865
- const defaults$7 = {
6866
+ const defaults$8 = {
6866
6867
  mapping: {
6867
6868
  article: "article",
6868
6869
  banner: "header",
@@ -6892,7 +6893,7 @@ const defaults$7 = {
6892
6893
  };
6893
6894
  class PreferNativeElement extends Rule {
6894
6895
  constructor(options) {
6895
- super({ ...defaults$7, ...options });
6896
+ super({ ...defaults$8, ...options });
6896
6897
  }
6897
6898
  static schema() {
6898
6899
  return {
@@ -7012,7 +7013,7 @@ class PreferTbody extends Rule {
7012
7013
  }
7013
7014
  }
7014
7015
 
7015
- const defaults$6 = {
7016
+ const defaults$7 = {
7016
7017
  target: "all",
7017
7018
  };
7018
7019
  const crossorigin = new RegExp("^(\\w+://|//)"); /* e.g. https:// or // */
@@ -7022,7 +7023,7 @@ const supportSri = {
7022
7023
  };
7023
7024
  class RequireSri extends Rule {
7024
7025
  constructor(options) {
7025
- super({ ...defaults$6, ...options });
7026
+ super({ ...defaults$7, ...options });
7026
7027
  this.target = this.options.target;
7027
7028
  }
7028
7029
  static schema() {
@@ -7150,7 +7151,7 @@ class SvgFocusable extends Rule {
7150
7151
  }
7151
7152
  }
7152
7153
 
7153
- const defaults$5 = {
7154
+ const defaults$6 = {
7154
7155
  characters: [
7155
7156
  { pattern: " ", replacement: "&nbsp;", description: "non-breaking space" },
7156
7157
  { pattern: "-", replacement: "&#8209;", description: "non-breaking hyphen" },
@@ -7193,7 +7194,7 @@ function matchAll(text, regexp) {
7193
7194
  }
7194
7195
  class TelNonBreaking extends Rule {
7195
7196
  constructor(options) {
7196
- super({ ...defaults$5, ...options });
7197
+ super({ ...defaults$6, ...options });
7197
7198
  this.regex = constructRegex(this.options.characters);
7198
7199
  }
7199
7200
  static schema() {
@@ -9272,6 +9273,95 @@ class UnknownCharReference extends Rule {
9272
9273
  }
9273
9274
  }
9274
9275
 
9276
+ var RuleContext;
9277
+ (function (RuleContext) {
9278
+ RuleContext[RuleContext["EMPTY"] = 1] = "EMPTY";
9279
+ RuleContext[RuleContext["WHITESPACE"] = 2] = "WHITESPACE";
9280
+ RuleContext[RuleContext["LEADING_CHARACTER"] = 3] = "LEADING_CHARACTER";
9281
+ RuleContext[RuleContext["DISALLOWED_CHARACTER"] = 4] = "DISALLOWED_CHARACTER";
9282
+ })(RuleContext || (RuleContext = {}));
9283
+ const defaults$5 = {
9284
+ relaxed: false,
9285
+ };
9286
+ class ValidID extends Rule {
9287
+ constructor(options) {
9288
+ super({ ...defaults$5, ...options });
9289
+ }
9290
+ static schema() {
9291
+ return {
9292
+ relaxed: {
9293
+ type: "boolean",
9294
+ },
9295
+ };
9296
+ }
9297
+ documentation(context) {
9298
+ const { relaxed } = this.options;
9299
+ const message = context
9300
+ ? this.messages[context].replace("id", "ID").replace(/^(.)/, (m) => m.toUpperCase())
9301
+ : "Element ID is not valid";
9302
+ const relaxedDescription = relaxed
9303
+ ? []
9304
+ : [
9305
+ " - ID must begin with a letter",
9306
+ " - ID must only contain alphanumerical characters, `-` and `_`",
9307
+ ];
9308
+ return {
9309
+ description: [
9310
+ `${message}.`,
9311
+ "",
9312
+ "Under the current configuration the following rules are applied:",
9313
+ "",
9314
+ " - ID must not be empty",
9315
+ " - ID must not contain any whitespace characters",
9316
+ ...relaxedDescription,
9317
+ ].join("\n"),
9318
+ url: ruleDocumentationUrl("@/rules/valid-id.ts"),
9319
+ };
9320
+ }
9321
+ setup() {
9322
+ this.on("attr", this.isRelevant, (event) => {
9323
+ const { value } = event;
9324
+ if (value === null || value instanceof DynamicValue) {
9325
+ return;
9326
+ }
9327
+ if (value === "") {
9328
+ const context = RuleContext.EMPTY;
9329
+ this.report(event.target, this.messages[context], event.location, context);
9330
+ return;
9331
+ }
9332
+ if (value.match(/\s/)) {
9333
+ const context = RuleContext.WHITESPACE;
9334
+ this.report(event.target, this.messages[context], event.valueLocation, context);
9335
+ return;
9336
+ }
9337
+ const { relaxed } = this.options;
9338
+ if (relaxed) {
9339
+ return;
9340
+ }
9341
+ if (value.match(/^[^a-zA-Z]/)) {
9342
+ const context = RuleContext.LEADING_CHARACTER;
9343
+ this.report(event.target, this.messages[context], event.valueLocation, context);
9344
+ return;
9345
+ }
9346
+ if (value.match(/[^a-zA-Z0-9-_]/)) {
9347
+ const context = RuleContext.DISALLOWED_CHARACTER;
9348
+ this.report(event.target, this.messages[context], event.valueLocation, context);
9349
+ }
9350
+ });
9351
+ }
9352
+ get messages() {
9353
+ return {
9354
+ [RuleContext.EMPTY]: "element id must not be empty",
9355
+ [RuleContext.WHITESPACE]: "element id must not contain whitespace",
9356
+ [RuleContext.LEADING_CHARACTER]: "element id must begin with a letter",
9357
+ [RuleContext.DISALLOWED_CHARACTER]: "element id must only contain alphanumerical, dash and underscore characters",
9358
+ };
9359
+ }
9360
+ isRelevant(event) {
9361
+ return event.key === "id";
9362
+ }
9363
+ }
9364
+
9275
9365
  var Style$1;
9276
9366
  (function (Style) {
9277
9367
  Style[Style["Any"] = 0] = "Any";
@@ -9783,6 +9873,7 @@ const bundledRules = {
9783
9873
  "tel-non-breaking": TelNonBreaking,
9784
9874
  "text-content": TextContent,
9785
9875
  "unrecognized-char-ref": UnknownCharReference,
9876
+ "valid-id": ValidID,
9786
9877
  void: Void,
9787
9878
  "void-content": VoidContent,
9788
9879
  "void-style": VoidStyle,
@@ -9880,6 +9971,7 @@ const config$1 = {
9880
9971
  "tel-non-breaking": "error",
9881
9972
  "text-content": "error",
9882
9973
  "unrecognized-char-ref": "error",
9974
+ "valid-id": ["error", { relaxed: false }],
9883
9975
  void: "off",
9884
9976
  "void-content": "error",
9885
9977
  "void-style": "error",
@@ -9915,6 +10007,7 @@ const config = {
9915
10007
  "no-raw-characters": ["error", { relaxed: true }],
9916
10008
  "script-element": "error",
9917
10009
  "unrecognized-char-ref": "error",
10010
+ "valid-id": ["error", { relaxed: true }],
9918
10011
  "void-content": "error",
9919
10012
  },
9920
10013
  };