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/cjs/core.js CHANGED
@@ -2009,9 +2009,10 @@ class HtmlElement extends DOMNode {
2009
2009
  /* if a unique id is present, use it and short-circuit */
2010
2010
  if (cur.id) {
2011
2011
  const escaped = escapeSelectorComponent(cur.id);
2012
- const matches = root.querySelectorAll(`#${escaped}`);
2012
+ const selector = escaped.match(/^\d/) ? `[id="${escaped}"]` : `#${escaped}`;
2013
+ const matches = root.querySelectorAll(selector);
2013
2014
  if (matches.length === 1) {
2014
- parts.push(`#${escaped}`);
2015
+ parts.push(selector);
2015
2016
  break;
2016
2017
  }
2017
2018
  }
@@ -3011,7 +3012,7 @@ var TRANSFORMER_API;
3011
3012
  /** @public */
3012
3013
  const name = "html-validate";
3013
3014
  /** @public */
3014
- const version = "6.8.0";
3015
+ const version = "6.9.0";
3015
3016
  /** @public */
3016
3017
  const homepage = "https://html-validate.org";
3017
3018
  /** @public */
@@ -3332,7 +3333,7 @@ function ruleDocumentationUrl(filename) {
3332
3333
  return `${homepage}/rules/${normalized}.html`;
3333
3334
  }
3334
3335
 
3335
- const defaults$q = {
3336
+ const defaults$r = {
3336
3337
  allowExternal: true,
3337
3338
  allowRelative: true,
3338
3339
  allowAbsolute: true,
@@ -3376,7 +3377,7 @@ function matchList(value, list) {
3376
3377
  }
3377
3378
  class AllowedLinks extends Rule {
3378
3379
  constructor(options) {
3379
- super({ ...defaults$q, ...options });
3380
+ super({ ...defaults$r, ...options });
3380
3381
  this.allowExternal = parseAllow(this.options.allowExternal);
3381
3382
  this.allowRelative = parseAllow(this.options.allowRelative);
3382
3383
  this.allowAbsolute = parseAllow(this.options.allowAbsolute);
@@ -3677,13 +3678,13 @@ class CaseStyle {
3677
3678
  }
3678
3679
  }
3679
3680
 
3680
- const defaults$p = {
3681
+ const defaults$q = {
3681
3682
  style: "lowercase",
3682
3683
  ignoreForeign: true,
3683
3684
  };
3684
3685
  class AttrCase extends Rule {
3685
3686
  constructor(options) {
3686
- super({ ...defaults$p, ...options });
3687
+ super({ ...defaults$q, ...options });
3687
3688
  this.style = new CaseStyle(this.options.style, "attr-case");
3688
3689
  }
3689
3690
  static schema() {
@@ -4022,7 +4023,7 @@ class AttrDelimiter extends Rule {
4022
4023
  }
4023
4024
 
4024
4025
  const DEFAULT_PATTERN = "[a-z0-9-:]+";
4025
- const defaults$o = {
4026
+ const defaults$p = {
4026
4027
  pattern: DEFAULT_PATTERN,
4027
4028
  ignoreForeign: true,
4028
4029
  };
@@ -4059,7 +4060,7 @@ function generateDescription(name, pattern) {
4059
4060
  }
4060
4061
  class AttrPattern extends Rule {
4061
4062
  constructor(options) {
4062
- super({ ...defaults$o, ...options });
4063
+ super({ ...defaults$p, ...options });
4063
4064
  this.pattern = generateRegexp(this.options.pattern);
4064
4065
  }
4065
4066
  static schema() {
@@ -4119,13 +4120,13 @@ var QuoteStyle;
4119
4120
  QuoteStyle["DOUBLE_QUOTE"] = "\"";
4120
4121
  QuoteStyle["AUTO_QUOTE"] = "auto";
4121
4122
  })(QuoteStyle || (QuoteStyle = {}));
4122
- const defaults$n = {
4123
+ const defaults$o = {
4123
4124
  style: "auto",
4124
4125
  unquoted: false,
4125
4126
  };
4126
4127
  class AttrQuotes extends Rule {
4127
4128
  constructor(options) {
4128
- super({ ...defaults$n, ...options });
4129
+ super({ ...defaults$o, ...options });
4129
4130
  this.style = parseStyle$4(this.options.style);
4130
4131
  }
4131
4132
  static schema() {
@@ -4290,12 +4291,12 @@ class AttributeAllowedValues extends Rule {
4290
4291
  }
4291
4292
  }
4292
4293
 
4293
- const defaults$m = {
4294
+ const defaults$n = {
4294
4295
  style: "omit",
4295
4296
  };
4296
4297
  class AttributeBooleanStyle extends Rule {
4297
4298
  constructor(options) {
4298
- super({ ...defaults$m, ...options });
4299
+ super({ ...defaults$n, ...options });
4299
4300
  this.hasInvalidStyle = parseStyle$3(this.options.style);
4300
4301
  }
4301
4302
  static schema() {
@@ -4371,12 +4372,12 @@ function reportMessage$1(attr, style) {
4371
4372
  return "";
4372
4373
  }
4373
4374
 
4374
- const defaults$l = {
4375
+ const defaults$m = {
4375
4376
  style: "omit",
4376
4377
  };
4377
4378
  class AttributeEmptyStyle extends Rule {
4378
4379
  constructor(options) {
4379
- super({ ...defaults$l, ...options });
4380
+ super({ ...defaults$m, ...options });
4380
4381
  this.hasInvalidStyle = parseStyle$2(this.options.style);
4381
4382
  }
4382
4383
  static schema() {
@@ -4484,12 +4485,12 @@ function describePattern(pattern) {
4484
4485
  }
4485
4486
  }
4486
4487
 
4487
- const defaults$k = {
4488
+ const defaults$l = {
4488
4489
  pattern: "kebabcase",
4489
4490
  };
4490
4491
  class ClassPattern extends Rule {
4491
4492
  constructor(options) {
4492
- super({ ...defaults$k, ...options });
4493
+ super({ ...defaults$l, ...options });
4493
4494
  this.pattern = parsePattern(this.options.pattern);
4494
4495
  }
4495
4496
  static schema() {
@@ -4598,13 +4599,13 @@ class CloseOrder extends Rule {
4598
4599
  }
4599
4600
  }
4600
4601
 
4601
- const defaults$j = {
4602
+ const defaults$k = {
4602
4603
  include: null,
4603
4604
  exclude: null,
4604
4605
  };
4605
4606
  class Deprecated extends Rule {
4606
4607
  constructor(options) {
4607
- super({ ...defaults$j, ...options });
4608
+ super({ ...defaults$k, ...options });
4608
4609
  }
4609
4610
  static schema() {
4610
4611
  return {
@@ -4767,12 +4768,12 @@ class NoStyleTag$1 extends Rule {
4767
4768
  }
4768
4769
  }
4769
4770
 
4770
- const defaults$i = {
4771
+ const defaults$j = {
4771
4772
  style: "uppercase",
4772
4773
  };
4773
4774
  class DoctypeStyle extends Rule {
4774
4775
  constructor(options) {
4775
- super({ ...defaults$i, ...options });
4776
+ super({ ...defaults$j, ...options });
4776
4777
  }
4777
4778
  static schema() {
4778
4779
  return {
@@ -4804,12 +4805,12 @@ class DoctypeStyle extends Rule {
4804
4805
  }
4805
4806
  }
4806
4807
 
4807
- const defaults$h = {
4808
+ const defaults$i = {
4808
4809
  style: "lowercase",
4809
4810
  };
4810
4811
  class ElementCase extends Rule {
4811
4812
  constructor(options) {
4812
- super({ ...defaults$h, ...options });
4813
+ super({ ...defaults$i, ...options });
4813
4814
  this.style = new CaseStyle(this.options.style, "element-case");
4814
4815
  }
4815
4816
  static schema() {
@@ -4875,14 +4876,14 @@ class ElementCase extends Rule {
4875
4876
  }
4876
4877
  }
4877
4878
 
4878
- const defaults$g = {
4879
+ const defaults$h = {
4879
4880
  pattern: "^[a-z][a-z0-9\\-._]*-[a-z0-9\\-._]*$",
4880
4881
  whitelist: [],
4881
4882
  blacklist: [],
4882
4883
  };
4883
4884
  class ElementName extends Rule {
4884
4885
  constructor(options) {
4885
- super({ ...defaults$g, ...options });
4886
+ super({ ...defaults$h, ...options });
4886
4887
  // eslint-disable-next-line security/detect-non-literal-regexp
4887
4888
  this.pattern = new RegExp(this.options.pattern);
4888
4889
  }
@@ -4923,7 +4924,7 @@ class ElementName extends Rule {
4923
4924
  ...context.blacklist.map((cur) => `- ${cur}`),
4924
4925
  ];
4925
4926
  }
4926
- if (context.pattern !== defaults$g.pattern) {
4927
+ if (context.pattern !== defaults$h.pattern) {
4927
4928
  return [
4928
4929
  `<${context.tagName}> is not a valid element name. This project is configured to only allow names matching the following regular expression:`,
4929
4930
  "",
@@ -5325,7 +5326,7 @@ class EmptyTitle extends Rule {
5325
5326
  }
5326
5327
  }
5327
5328
 
5328
- const defaults$f = {
5329
+ const defaults$g = {
5329
5330
  allowMultipleH1: false,
5330
5331
  minInitialRank: "h1",
5331
5332
  sectioningRoots: ["dialog", '[role="dialog"]'],
@@ -5356,7 +5357,7 @@ function parseMaxInitial(value) {
5356
5357
  }
5357
5358
  class HeadingLevel extends Rule {
5358
5359
  constructor(options) {
5359
- super({ ...defaults$f, ...options });
5360
+ super({ ...defaults$g, ...options });
5360
5361
  this.stack = [];
5361
5362
  this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
5362
5363
  this.sectionRoots = this.options.sectioningRoots.map((it) => new Pattern(it));
@@ -5514,12 +5515,12 @@ class HeadingLevel extends Rule {
5514
5515
  }
5515
5516
  }
5516
5517
 
5517
- const defaults$e = {
5518
+ const defaults$f = {
5518
5519
  pattern: "kebabcase",
5519
5520
  };
5520
5521
  class IdPattern extends Rule {
5521
5522
  constructor(options) {
5522
- super({ ...defaults$e, ...options });
5523
+ super({ ...defaults$f, ...options });
5523
5524
  this.pattern = parsePattern(this.options.pattern);
5524
5525
  }
5525
5526
  static schema() {
@@ -5870,12 +5871,12 @@ function findLabelByParent(el) {
5870
5871
  return [];
5871
5872
  }
5872
5873
 
5873
- const defaults$d = {
5874
+ const defaults$e = {
5874
5875
  maxlength: 70,
5875
5876
  };
5876
5877
  class LongTitle extends Rule {
5877
5878
  constructor(options) {
5878
- super({ ...defaults$d, ...options });
5879
+ super({ ...defaults$e, ...options });
5879
5880
  this.maxlength = this.options.maxlength;
5880
5881
  }
5881
5882
  static schema() {
@@ -6022,13 +6023,13 @@ class MultipleLabeledControls extends Rule {
6022
6023
  }
6023
6024
  }
6024
6025
 
6025
- const defaults$c = {
6026
+ const defaults$d = {
6026
6027
  include: null,
6027
6028
  exclude: null,
6028
6029
  };
6029
6030
  class NoAutoplay extends Rule {
6030
6031
  constructor(options) {
6031
- super({ ...defaults$c, ...options });
6032
+ super({ ...defaults$d, ...options });
6032
6033
  }
6033
6034
  documentation(context) {
6034
6035
  const tagName = context ? ` on <${context.tagName}>` : "";
@@ -6269,14 +6270,14 @@ Omitted end tags can be ambigious for humans to read and many editors have troub
6269
6270
  }
6270
6271
  }
6271
6272
 
6272
- const defaults$b = {
6273
+ const defaults$c = {
6273
6274
  include: null,
6274
6275
  exclude: null,
6275
6276
  allowedProperties: ["display"],
6276
6277
  };
6277
6278
  class NoInlineStyle extends Rule {
6278
6279
  constructor(options) {
6279
- super({ ...defaults$b, ...options });
6280
+ super({ ...defaults$c, ...options });
6280
6281
  }
6281
6282
  static schema() {
6282
6283
  return {
@@ -6478,7 +6479,7 @@ class NoMultipleMain extends Rule {
6478
6479
  }
6479
6480
  }
6480
6481
 
6481
- const defaults$a = {
6482
+ const defaults$b = {
6482
6483
  relaxed: false,
6483
6484
  };
6484
6485
  const textRegexp = /([<>]|&(?![a-zA-Z0-9#]+;))/g;
@@ -6495,7 +6496,7 @@ const replacementTable = {
6495
6496
  };
6496
6497
  class NoRawCharacters extends Rule {
6497
6498
  constructor(options) {
6498
- super({ ...defaults$a, ...options });
6499
+ super({ ...defaults$b, ...options });
6499
6500
  this.relaxed = this.options.relaxed;
6500
6501
  }
6501
6502
  static schema() {
@@ -6673,13 +6674,13 @@ class NoRedundantRole extends Rule {
6673
6674
  }
6674
6675
 
6675
6676
  const xmlns = /^(.+):.+$/;
6676
- const defaults$9 = {
6677
+ const defaults$a = {
6677
6678
  ignoreForeign: true,
6678
6679
  ignoreXML: true,
6679
6680
  };
6680
6681
  class NoSelfClosing extends Rule {
6681
6682
  constructor(options) {
6682
- super({ ...defaults$9, ...options });
6683
+ super({ ...defaults$a, ...options });
6683
6684
  }
6684
6685
  static schema() {
6685
6686
  return {
@@ -6812,13 +6813,13 @@ const replacement = {
6812
6813
  reset: '<button type="reset">',
6813
6814
  image: '<button type="button">',
6814
6815
  };
6815
- const defaults$8 = {
6816
+ const defaults$9 = {
6816
6817
  include: null,
6817
6818
  exclude: null,
6818
6819
  };
6819
6820
  class PreferButton extends Rule {
6820
6821
  constructor(options) {
6821
- super({ ...defaults$8, ...options });
6822
+ super({ ...defaults$9, ...options });
6822
6823
  }
6823
6824
  static schema() {
6824
6825
  return {
@@ -6893,7 +6894,7 @@ class PreferButton extends Rule {
6893
6894
  }
6894
6895
  }
6895
6896
 
6896
- const defaults$7 = {
6897
+ const defaults$8 = {
6897
6898
  mapping: {
6898
6899
  article: "article",
6899
6900
  banner: "header",
@@ -6923,7 +6924,7 @@ const defaults$7 = {
6923
6924
  };
6924
6925
  class PreferNativeElement extends Rule {
6925
6926
  constructor(options) {
6926
- super({ ...defaults$7, ...options });
6927
+ super({ ...defaults$8, ...options });
6927
6928
  }
6928
6929
  static schema() {
6929
6930
  return {
@@ -7043,7 +7044,7 @@ class PreferTbody extends Rule {
7043
7044
  }
7044
7045
  }
7045
7046
 
7046
- const defaults$6 = {
7047
+ const defaults$7 = {
7047
7048
  target: "all",
7048
7049
  };
7049
7050
  const crossorigin = new RegExp("^(\\w+://|//)"); /* e.g. https:// or // */
@@ -7053,7 +7054,7 @@ const supportSri = {
7053
7054
  };
7054
7055
  class RequireSri extends Rule {
7055
7056
  constructor(options) {
7056
- super({ ...defaults$6, ...options });
7057
+ super({ ...defaults$7, ...options });
7057
7058
  this.target = this.options.target;
7058
7059
  }
7059
7060
  static schema() {
@@ -7181,7 +7182,7 @@ class SvgFocusable extends Rule {
7181
7182
  }
7182
7183
  }
7183
7184
 
7184
- const defaults$5 = {
7185
+ const defaults$6 = {
7185
7186
  characters: [
7186
7187
  { pattern: " ", replacement: "&nbsp;", description: "non-breaking space" },
7187
7188
  { pattern: "-", replacement: "&#8209;", description: "non-breaking hyphen" },
@@ -7224,7 +7225,7 @@ function matchAll(text, regexp) {
7224
7225
  }
7225
7226
  class TelNonBreaking extends Rule {
7226
7227
  constructor(options) {
7227
- super({ ...defaults$5, ...options });
7228
+ super({ ...defaults$6, ...options });
7228
7229
  this.regex = constructRegex(this.options.characters);
7229
7230
  }
7230
7231
  static schema() {
@@ -9303,6 +9304,95 @@ class UnknownCharReference extends Rule {
9303
9304
  }
9304
9305
  }
9305
9306
 
9307
+ var RuleContext;
9308
+ (function (RuleContext) {
9309
+ RuleContext[RuleContext["EMPTY"] = 1] = "EMPTY";
9310
+ RuleContext[RuleContext["WHITESPACE"] = 2] = "WHITESPACE";
9311
+ RuleContext[RuleContext["LEADING_CHARACTER"] = 3] = "LEADING_CHARACTER";
9312
+ RuleContext[RuleContext["DISALLOWED_CHARACTER"] = 4] = "DISALLOWED_CHARACTER";
9313
+ })(RuleContext || (RuleContext = {}));
9314
+ const defaults$5 = {
9315
+ relaxed: false,
9316
+ };
9317
+ class ValidID extends Rule {
9318
+ constructor(options) {
9319
+ super({ ...defaults$5, ...options });
9320
+ }
9321
+ static schema() {
9322
+ return {
9323
+ relaxed: {
9324
+ type: "boolean",
9325
+ },
9326
+ };
9327
+ }
9328
+ documentation(context) {
9329
+ const { relaxed } = this.options;
9330
+ const message = context
9331
+ ? this.messages[context].replace("id", "ID").replace(/^(.)/, (m) => m.toUpperCase())
9332
+ : "Element ID is not valid";
9333
+ const relaxedDescription = relaxed
9334
+ ? []
9335
+ : [
9336
+ " - ID must begin with a letter",
9337
+ " - ID must only contain alphanumerical characters, `-` and `_`",
9338
+ ];
9339
+ return {
9340
+ description: [
9341
+ `${message}.`,
9342
+ "",
9343
+ "Under the current configuration the following rules are applied:",
9344
+ "",
9345
+ " - ID must not be empty",
9346
+ " - ID must not contain any whitespace characters",
9347
+ ...relaxedDescription,
9348
+ ].join("\n"),
9349
+ url: ruleDocumentationUrl("@/rules/valid-id.ts"),
9350
+ };
9351
+ }
9352
+ setup() {
9353
+ this.on("attr", this.isRelevant, (event) => {
9354
+ const { value } = event;
9355
+ if (value === null || value instanceof DynamicValue) {
9356
+ return;
9357
+ }
9358
+ if (value === "") {
9359
+ const context = RuleContext.EMPTY;
9360
+ this.report(event.target, this.messages[context], event.location, context);
9361
+ return;
9362
+ }
9363
+ if (value.match(/\s/)) {
9364
+ const context = RuleContext.WHITESPACE;
9365
+ this.report(event.target, this.messages[context], event.valueLocation, context);
9366
+ return;
9367
+ }
9368
+ const { relaxed } = this.options;
9369
+ if (relaxed) {
9370
+ return;
9371
+ }
9372
+ if (value.match(/^[^a-zA-Z]/)) {
9373
+ const context = RuleContext.LEADING_CHARACTER;
9374
+ this.report(event.target, this.messages[context], event.valueLocation, context);
9375
+ return;
9376
+ }
9377
+ if (value.match(/[^a-zA-Z0-9-_]/)) {
9378
+ const context = RuleContext.DISALLOWED_CHARACTER;
9379
+ this.report(event.target, this.messages[context], event.valueLocation, context);
9380
+ }
9381
+ });
9382
+ }
9383
+ get messages() {
9384
+ return {
9385
+ [RuleContext.EMPTY]: "element id must not be empty",
9386
+ [RuleContext.WHITESPACE]: "element id must not contain whitespace",
9387
+ [RuleContext.LEADING_CHARACTER]: "element id must begin with a letter",
9388
+ [RuleContext.DISALLOWED_CHARACTER]: "element id must only contain alphanumerical, dash and underscore characters",
9389
+ };
9390
+ }
9391
+ isRelevant(event) {
9392
+ return event.key === "id";
9393
+ }
9394
+ }
9395
+
9306
9396
  var Style$1;
9307
9397
  (function (Style) {
9308
9398
  Style[Style["Any"] = 0] = "Any";
@@ -9814,6 +9904,7 @@ const bundledRules = {
9814
9904
  "tel-non-breaking": TelNonBreaking,
9815
9905
  "text-content": TextContent,
9816
9906
  "unrecognized-char-ref": UnknownCharReference,
9907
+ "valid-id": ValidID,
9817
9908
  void: Void,
9818
9909
  "void-content": VoidContent,
9819
9910
  "void-style": VoidStyle,
@@ -9911,6 +10002,7 @@ const config$1 = {
9911
10002
  "tel-non-breaking": "error",
9912
10003
  "text-content": "error",
9913
10004
  "unrecognized-char-ref": "error",
10005
+ "valid-id": ["error", { relaxed: false }],
9914
10006
  void: "off",
9915
10007
  "void-content": "error",
9916
10008
  "void-style": "error",
@@ -9946,6 +10038,7 @@ const config = {
9946
10038
  "no-raw-characters": ["error", { relaxed: true }],
9947
10039
  "script-element": "error",
9948
10040
  "unrecognized-char-ref": "error",
10041
+ "valid-id": ["error", { relaxed: true }],
9949
10042
  "void-content": "error",
9950
10043
  },
9951
10044
  };