html-validate 10.6.0 → 10.8.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
@@ -4008,7 +4008,7 @@ class Rule {
4008
4008
  }
4009
4009
  }
4010
4010
 
4011
- const defaults$y = {
4011
+ const defaults$A = {
4012
4012
  allowExternal: true,
4013
4013
  allowRelative: true,
4014
4014
  allowAbsolute: true,
@@ -4052,7 +4052,7 @@ class AllowedLinks extends Rule {
4052
4052
  allowRelative;
4053
4053
  allowAbsolute;
4054
4054
  constructor(options) {
4055
- super({ ...defaults$y, ...options });
4055
+ super({ ...defaults$A, ...options });
4056
4056
  this.allowExternal = parseAllow(this.options.allowExternal);
4057
4057
  this.allowRelative = parseAllow(this.options.allowRelative);
4058
4058
  this.allowAbsolute = parseAllow(this.options.allowAbsolute);
@@ -4220,7 +4220,7 @@ class AllowedLinks extends Rule {
4220
4220
  }
4221
4221
  }
4222
4222
 
4223
- const defaults$x = {
4223
+ const defaults$z = {
4224
4224
  accessible: true
4225
4225
  };
4226
4226
  function findByTarget(target, siblings) {
@@ -4250,7 +4250,7 @@ function getDescription$1(context) {
4250
4250
  }
4251
4251
  class AreaAlt extends Rule {
4252
4252
  constructor(options) {
4253
- super({ ...defaults$x, ...options });
4253
+ super({ ...defaults$z, ...options });
4254
4254
  }
4255
4255
  static schema() {
4256
4256
  return {
@@ -4329,8 +4329,12 @@ class AriaHiddenBody extends Rule {
4329
4329
  }
4330
4330
  }
4331
4331
 
4332
- const defaults$w = {
4333
- allowAnyNamable: false
4332
+ const defaults$y = {
4333
+ allowAnyNamable: false,
4334
+ elements: {
4335
+ include: null,
4336
+ exclude: null
4337
+ }
4334
4338
  };
4335
4339
  const allowlist = /* @__PURE__ */ new Set([
4336
4340
  "main",
@@ -4373,7 +4377,26 @@ function isValidUsage(target, meta) {
4373
4377
  }
4374
4378
  class AriaLabelMisuse extends Rule {
4375
4379
  constructor(options) {
4376
- super({ ...defaults$w, ...options });
4380
+ super({ ...defaults$y, ...options });
4381
+ }
4382
+ static schema() {
4383
+ return {
4384
+ allowAnyNamable: {
4385
+ type: "boolean"
4386
+ },
4387
+ elements: {
4388
+ type: "object",
4389
+ properties: {
4390
+ include: {
4391
+ anyOf: [{ type: "array", items: { type: "string" } }, { type: "null" }]
4392
+ },
4393
+ exclude: {
4394
+ anyOf: [{ type: "array", items: { type: "string" } }, { type: "null" }]
4395
+ }
4396
+ },
4397
+ additionalProperties: false
4398
+ }
4399
+ };
4377
4400
  }
4378
4401
  documentation(context) {
4379
4402
  const valid = [
@@ -4431,6 +4454,9 @@ class AriaLabelMisuse extends Rule {
4431
4454
  if (!meta) {
4432
4455
  return;
4433
4456
  }
4457
+ if (this.shouldIgnoreElement(target)) {
4458
+ return;
4459
+ }
4434
4460
  if (isValidUsage(target, meta)) {
4435
4461
  return;
4436
4462
  }
@@ -4455,6 +4481,9 @@ class AriaLabelMisuse extends Rule {
4455
4481
  });
4456
4482
  }
4457
4483
  }
4484
+ shouldIgnoreElement(target) {
4485
+ return isKeywordIgnored(this.options.elements, target.tagName, keywordPatternMatcher);
4486
+ }
4458
4487
  }
4459
4488
 
4460
4489
  class ConfigError extends UserError {
@@ -4517,14 +4546,14 @@ class CaseStyle {
4517
4546
  }
4518
4547
  }
4519
4548
 
4520
- const defaults$v = {
4549
+ const defaults$x = {
4521
4550
  style: "lowercase",
4522
4551
  ignoreForeign: true
4523
4552
  };
4524
4553
  class AttrCase extends Rule {
4525
4554
  style;
4526
4555
  constructor(options) {
4527
- super({ ...defaults$v, ...options });
4556
+ super({ ...defaults$x, ...options });
4528
4557
  this.style = new CaseStyle(this.options.style, "attr-case");
4529
4558
  }
4530
4559
  static schema() {
@@ -4631,7 +4660,7 @@ const MATCH_TEXTAREA_DATA = /^[^]*?(?=<\/textarea)/;
4631
4660
  const MATCH_TEXTAREA_END = /^<(\/)(textarea)/;
4632
4661
  const MATCH_TITLE_DATA = /^[^]*?(?=<\/title)/;
4633
4662
  const MATCH_TITLE_END = /^<(\/)(title)/;
4634
- const MATCH_DIRECTIVE = /^(<!--\s*\[html-validate-)([a-z0-9-]+)(\s*)(.*?)(]?\s*-->)/;
4663
+ const MATCH_DIRECTIVE = /^(<!--\s*\[?)(html-validate-)([a-z0-9-]+)(\s*)(.*?)(]?\s*-->)/;
4635
4664
  const MATCH_COMMENT = /^<!--([^]*?)-->/;
4636
4665
  const MATCH_CONDITIONAL = /^<!\[([^\]]*?)\]>/;
4637
4666
  class InvalidTokenError extends Error {
@@ -4929,7 +4958,7 @@ class AttrDelimiter extends Rule {
4929
4958
  }
4930
4959
 
4931
4960
  const DEFAULT_PATTERN = "[a-z0-9-:]+";
4932
- const defaults$u = {
4961
+ const defaults$w = {
4933
4962
  pattern: DEFAULT_PATTERN,
4934
4963
  ignoreForeign: true
4935
4964
  };
@@ -4962,7 +4991,7 @@ function generateDescription(name, pattern) {
4962
4991
  class AttrPattern extends Rule {
4963
4992
  pattern;
4964
4993
  constructor(options) {
4965
- super({ ...defaults$u, ...options });
4994
+ super({ ...defaults$w, ...options });
4966
4995
  this.pattern = generateRegexp(this.options.pattern);
4967
4996
  }
4968
4997
  static schema() {
@@ -5009,7 +5038,7 @@ class AttrPattern extends Rule {
5009
5038
  }
5010
5039
  }
5011
5040
 
5012
- const defaults$t = {
5041
+ const defaults$v = {
5013
5042
  style: "auto",
5014
5043
  unquoted: false
5015
5044
  };
@@ -5075,7 +5104,7 @@ class AttrQuotes extends Rule {
5075
5104
  };
5076
5105
  }
5077
5106
  constructor(options) {
5078
- super({ ...defaults$t, ...options });
5107
+ super({ ...defaults$v, ...options });
5079
5108
  this.style = parseStyle$3(this.options.style);
5080
5109
  }
5081
5110
  setup() {
@@ -5231,13 +5260,13 @@ class AttributeAllowedValues extends Rule {
5231
5260
  }
5232
5261
  }
5233
5262
 
5234
- const defaults$s = {
5263
+ const defaults$u = {
5235
5264
  style: "omit"
5236
5265
  };
5237
5266
  class AttributeBooleanStyle extends Rule {
5238
5267
  hasInvalidStyle;
5239
5268
  constructor(options) {
5240
- super({ ...defaults$s, ...options });
5269
+ super({ ...defaults$u, ...options });
5241
5270
  this.hasInvalidStyle = parseStyle$2(this.options.style);
5242
5271
  }
5243
5272
  static schema() {
@@ -5307,13 +5336,13 @@ function reportMessage$1(attr, style) {
5307
5336
  return "";
5308
5337
  }
5309
5338
 
5310
- const defaults$r = {
5339
+ const defaults$t = {
5311
5340
  style: "omit"
5312
5341
  };
5313
5342
  class AttributeEmptyStyle extends Rule {
5314
5343
  hasInvalidStyle;
5315
5344
  constructor(options) {
5316
- super({ ...defaults$r, ...options });
5345
+ super({ ...defaults$t, ...options });
5317
5346
  this.hasInvalidStyle = parseStyle$1(this.options.style);
5318
5347
  }
5319
5348
  static schema() {
@@ -5430,6 +5459,122 @@ class AttributeMisuse extends Rule {
5430
5459
  }
5431
5460
  }
5432
5461
 
5462
+ const defaults$s = {
5463
+ preferred: void 0
5464
+ };
5465
+ function isPasswordInput(event) {
5466
+ const { target } = event;
5467
+ if (!target.is("input")) {
5468
+ return false;
5469
+ }
5470
+ const type = target.getAttribute("type");
5471
+ return type?.value?.toString().toLowerCase() === "password";
5472
+ }
5473
+ function isGroupingToken(token) {
5474
+ return token.startsWith("section-") || token === "shipping" || token === "billing";
5475
+ }
5476
+ class AutocompletePassword extends Rule {
5477
+ preferred;
5478
+ constructor(options) {
5479
+ super({ ...defaults$s, ...options });
5480
+ this.preferred = options.preferred?.toLowerCase();
5481
+ }
5482
+ static schema() {
5483
+ return {
5484
+ preferred: {
5485
+ type: "string"
5486
+ }
5487
+ };
5488
+ }
5489
+ documentation(context) {
5490
+ const url = "https://html-validate.org/rules/autocomplete-password.html";
5491
+ switch (context.kind) {
5492
+ case "preferred-mismatch":
5493
+ return {
5494
+ description: [
5495
+ `\`<input type="password">\` should use \`autocomplete="${context.preferred}"\`.`,
5496
+ "",
5497
+ `The configured preferred autocomplete value is \`"${context.preferred}"\` but the element uses \`"${context.value}"\`.`
5498
+ ].join("\n"),
5499
+ url
5500
+ };
5501
+ case "off":
5502
+ case "missing":
5503
+ default: {
5504
+ const error = context.kind === "off" ? '`<input type="password">` should not use `autocomplete="off"`.' : '`<input type="password">` must have the `autocomplete` attribute.';
5505
+ return {
5506
+ description: [
5507
+ error,
5508
+ "",
5509
+ "Browsers and password managers often ignore the absence of autocomplete and autofill password fields anyway, which can lead to unexpected behavior where users unknowingly submit autofilled passwords for unrelated fields.",
5510
+ "",
5511
+ "Use one of the following values:",
5512
+ "",
5513
+ '- `autocomplete="new-password"` for password creation forms',
5514
+ '- `autocomplete="current-password"` for login forms'
5515
+ ].join("\n"),
5516
+ url
5517
+ };
5518
+ }
5519
+ }
5520
+ }
5521
+ setup() {
5522
+ this.on("tag:ready", isPasswordInput, (event) => {
5523
+ const { preferred } = this;
5524
+ const { target } = event;
5525
+ const autocomplete = target.getAttribute("autocomplete");
5526
+ if (!autocomplete) {
5527
+ const context = { kind: "missing" };
5528
+ this.report({
5529
+ node: target,
5530
+ message: '<input type="password"> is missing required "autocomplete" attribute',
5531
+ location: target.location,
5532
+ context
5533
+ });
5534
+ return;
5535
+ }
5536
+ if (autocomplete.isDynamic || !autocomplete.value) {
5537
+ return;
5538
+ }
5539
+ const raw = autocomplete.value.toString().toLowerCase();
5540
+ const tokens = new DOMTokenList(raw, autocomplete.valueLocation);
5541
+ const index = tokens.findIndex((token) => !isGroupingToken(token));
5542
+ const value = tokens.item(index);
5543
+ const location = tokens.location(index);
5544
+ if (!value) {
5545
+ return;
5546
+ }
5547
+ if (value === "off") {
5548
+ const context = { kind: "off" };
5549
+ this.report({
5550
+ node: target,
5551
+ message: '<input type="password"> should not use autocomplete="off"',
5552
+ /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- location must be present if value is */
5553
+ location,
5554
+ context
5555
+ });
5556
+ return;
5557
+ }
5558
+ if (preferred) {
5559
+ if (value !== preferred) {
5560
+ const context = {
5561
+ kind: "preferred-mismatch",
5562
+ value,
5563
+ preferred
5564
+ };
5565
+ this.report({
5566
+ node: target,
5567
+ message: `<input type="password"> should use autocomplete="${preferred}"`,
5568
+ /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- location must be present if value is */
5569
+ location,
5570
+ context
5571
+ });
5572
+ }
5573
+ }
5574
+ });
5575
+ }
5576
+ }
5577
+
5433
5578
  const patternNamesValues = [
5434
5579
  "kebabcase",
5435
5580
  "camelcase",
@@ -5561,7 +5706,7 @@ class BasePatternRule extends Rule {
5561
5706
  }
5562
5707
  }
5563
5708
 
5564
- const defaults$q = {
5709
+ const defaults$r = {
5565
5710
  pattern: "kebabcase"
5566
5711
  };
5567
5712
  class ClassPattern extends BasePatternRule {
@@ -5569,7 +5714,7 @@ class ClassPattern extends BasePatternRule {
5569
5714
  super({
5570
5715
  ruleId: "class-pattern",
5571
5716
  attr: "class",
5572
- options: { ...defaults$q, ...options },
5717
+ options: { ...defaults$r, ...options },
5573
5718
  allowedPatterns: patternNames
5574
5719
  // allow all patterns
5575
5720
  });
@@ -5719,13 +5864,13 @@ class CloseOrder extends Rule {
5719
5864
  }
5720
5865
  }
5721
5866
 
5722
- const defaults$p = {
5867
+ const defaults$q = {
5723
5868
  include: null,
5724
5869
  exclude: null
5725
5870
  };
5726
5871
  class Deprecated extends Rule {
5727
5872
  constructor(options) {
5728
- super({ ...defaults$p, ...options });
5873
+ super({ ...defaults$q, ...options });
5729
5874
  }
5730
5875
  static schema() {
5731
5876
  return {
@@ -5879,12 +6024,12 @@ let NoStyleTag$1 = class NoStyleTag extends Rule {
5879
6024
  }
5880
6025
  };
5881
6026
 
5882
- const defaults$o = {
6027
+ const defaults$p = {
5883
6028
  style: "uppercase"
5884
6029
  };
5885
6030
  class DoctypeStyle extends Rule {
5886
6031
  constructor(options) {
5887
- super({ ...defaults$o, ...options });
6032
+ super({ ...defaults$p, ...options });
5888
6033
  }
5889
6034
  static schema() {
5890
6035
  return {
@@ -5912,13 +6057,13 @@ class DoctypeStyle extends Rule {
5912
6057
  }
5913
6058
  }
5914
6059
 
5915
- const defaults$n = {
6060
+ const defaults$o = {
5916
6061
  style: "lowercase"
5917
6062
  };
5918
6063
  class ElementCase extends Rule {
5919
6064
  style;
5920
6065
  constructor(options) {
5921
- super({ ...defaults$n, ...options });
6066
+ super({ ...defaults$o, ...options });
5922
6067
  this.style = new CaseStyle(this.options.style, "element-case");
5923
6068
  }
5924
6069
  static schema() {
@@ -5978,7 +6123,7 @@ class ElementCase extends Rule {
5978
6123
  }
5979
6124
  }
5980
6125
 
5981
- const defaults$m = {
6126
+ const defaults$n = {
5982
6127
  pattern: "^[a-z][a-z0-9\\-._]*-[a-z0-9\\-._]*$",
5983
6128
  whitelist: [],
5984
6129
  blacklist: []
@@ -5986,7 +6131,7 @@ const defaults$m = {
5986
6131
  class ElementName extends Rule {
5987
6132
  pattern;
5988
6133
  constructor(options) {
5989
- super({ ...defaults$m, ...options });
6134
+ super({ ...defaults$n, ...options });
5990
6135
  this.pattern = new RegExp(this.options.pattern);
5991
6136
  }
5992
6137
  static schema() {
@@ -6023,7 +6168,7 @@ class ElementName extends Rule {
6023
6168
  ...context.blacklist.map((cur) => `- ${cur}`)
6024
6169
  ];
6025
6170
  }
6026
- if (context.pattern !== defaults$m.pattern) {
6171
+ if (context.pattern !== defaults$n.pattern) {
6027
6172
  return [
6028
6173
  `<${context.tagName}> is not a valid element name. This project is configured to only allow names matching the following regular expression:`,
6029
6174
  "",
@@ -6540,7 +6685,7 @@ class EmptyTitle extends Rule {
6540
6685
  }
6541
6686
  }
6542
6687
 
6543
- const defaults$l = {
6688
+ const defaults$m = {
6544
6689
  allowArrayBrackets: true,
6545
6690
  allowCheckboxDefault: true,
6546
6691
  shared: ["radio", "button", "reset", "submit"]
@@ -6600,7 +6745,7 @@ function getDocumentation(context) {
6600
6745
  }
6601
6746
  class FormDupName extends Rule {
6602
6747
  constructor(options) {
6603
- super({ ...defaults$l, ...options });
6748
+ super({ ...defaults$m, ...options });
6604
6749
  }
6605
6750
  static schema() {
6606
6751
  return {
@@ -6759,7 +6904,7 @@ class FormDupName extends Rule {
6759
6904
  }
6760
6905
  }
6761
6906
 
6762
- const defaults$k = {
6907
+ const defaults$l = {
6763
6908
  allowMultipleH1: false,
6764
6909
  minInitialRank: "h1",
6765
6910
  sectioningRoots: ["dialog", '[role="dialog"]', '[role="alertdialog"]']
@@ -6791,7 +6936,7 @@ class HeadingLevel extends Rule {
6791
6936
  sectionRoots;
6792
6937
  stack = [];
6793
6938
  constructor(options) {
6794
- super({ ...defaults$k, ...options });
6939
+ super({ ...defaults$l, ...options });
6795
6940
  this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
6796
6941
  this.sectionRoots = this.options.sectioningRoots.map((it) => new Compound(it));
6797
6942
  this.stack.push({
@@ -7030,7 +7175,7 @@ class HiddenFocusable extends Rule {
7030
7175
  }
7031
7176
  }
7032
7177
 
7033
- const defaults$j = {
7178
+ const defaults$k = {
7034
7179
  pattern: "kebabcase"
7035
7180
  };
7036
7181
  function exclude$1(set, ...values) {
@@ -7046,7 +7191,7 @@ class IdPattern extends BasePatternRule {
7046
7191
  super({
7047
7192
  ruleId: "id-pattern",
7048
7193
  attr: "id",
7049
- options: { ...defaults$j, ...options },
7194
+ options: { ...defaults$k, ...options },
7050
7195
  allowedPatterns
7051
7196
  });
7052
7197
  }
@@ -7368,13 +7513,13 @@ function findLabelByParent(el) {
7368
7513
  return [];
7369
7514
  }
7370
7515
 
7371
- const defaults$i = {
7516
+ const defaults$j = {
7372
7517
  maxlength: 70
7373
7518
  };
7374
7519
  class LongTitle extends Rule {
7375
7520
  maxlength;
7376
7521
  constructor(options) {
7377
- super({ ...defaults$i, ...options });
7522
+ super({ ...defaults$j, ...options });
7378
7523
  this.maxlength = this.options.maxlength;
7379
7524
  }
7380
7525
  static schema() {
@@ -7478,12 +7623,12 @@ class MapIdName extends Rule {
7478
7623
  }
7479
7624
  }
7480
7625
 
7481
- const defaults$h = {
7626
+ const defaults$i = {
7482
7627
  allowLongDelay: false
7483
7628
  };
7484
7629
  class MetaRefresh extends Rule {
7485
7630
  constructor(options) {
7486
- super({ ...defaults$h, ...options });
7631
+ super({ ...defaults$i, ...options });
7487
7632
  }
7488
7633
  documentation() {
7489
7634
  return {
@@ -7594,7 +7739,7 @@ class MultipleLabeledControls extends Rule {
7594
7739
  }
7595
7740
  }
7596
7741
 
7597
- const defaults$g = {
7742
+ const defaults$h = {
7598
7743
  pattern: "camelcase"
7599
7744
  };
7600
7745
  function exclude(set, ...values) {
@@ -7610,7 +7755,7 @@ class NamePattern extends BasePatternRule {
7610
7755
  super({
7611
7756
  ruleId: "name-pattern",
7612
7757
  attr: "name",
7613
- options: { ...defaults$g, ...options },
7758
+ options: { ...defaults$h, ...options },
7614
7759
  allowedPatterns
7615
7760
  });
7616
7761
  }
@@ -7701,13 +7846,13 @@ class NoAbstractRole extends Rule {
7701
7846
  }
7702
7847
  }
7703
7848
 
7704
- const defaults$f = {
7849
+ const defaults$g = {
7705
7850
  include: null,
7706
7851
  exclude: null
7707
7852
  };
7708
7853
  class NoAutoplay extends Rule {
7709
7854
  constructor(options) {
7710
- super({ ...defaults$f, ...options });
7855
+ super({ ...defaults$g, ...options });
7711
7856
  }
7712
7857
  documentation(context) {
7713
7858
  return {
@@ -8029,14 +8174,14 @@ class NoImplicitInputType extends Rule {
8029
8174
  }
8030
8175
  }
8031
8176
 
8032
- const defaults$e = {
8177
+ const defaults$f = {
8033
8178
  include: null,
8034
8179
  exclude: null,
8035
8180
  allowedProperties: ["display"]
8036
8181
  };
8037
8182
  class NoInlineStyle extends Rule {
8038
8183
  constructor(options) {
8039
- super({ ...defaults$e, ...options });
8184
+ super({ ...defaults$f, ...options });
8040
8185
  }
8041
8186
  static schema() {
8042
8187
  return {
@@ -8222,7 +8367,7 @@ class NoMultipleMain extends Rule {
8222
8367
  }
8223
8368
  }
8224
8369
 
8225
- const defaults$d = {
8370
+ const defaults$e = {
8226
8371
  relaxed: false
8227
8372
  };
8228
8373
  const textRegexp = /([<>]|&(?![a-zA-Z0-9#]+;))/g;
@@ -8240,7 +8385,7 @@ const replacementTable = {
8240
8385
  class NoRawCharacters extends Rule {
8241
8386
  relaxed;
8242
8387
  constructor(options) {
8243
- super({ ...defaults$d, ...options });
8388
+ super({ ...defaults$e, ...options });
8244
8389
  this.relaxed = this.options.relaxed;
8245
8390
  }
8246
8391
  static schema() {
@@ -8420,13 +8565,13 @@ class NoRedundantRole extends Rule {
8420
8565
  }
8421
8566
 
8422
8567
  const xmlns = /^(.+):.+$/;
8423
- const defaults$c = {
8568
+ const defaults$d = {
8424
8569
  ignoreForeign: true,
8425
8570
  ignoreXML: true
8426
8571
  };
8427
8572
  class NoSelfClosing extends Rule {
8428
8573
  constructor(options) {
8429
- super({ ...defaults$c, ...options });
8574
+ super({ ...defaults$d, ...options });
8430
8575
  }
8431
8576
  static schema() {
8432
8577
  return {
@@ -8476,7 +8621,20 @@ function isRelevant(node, options) {
8476
8621
  return true;
8477
8622
  }
8478
8623
 
8624
+ const defaults$c = {
8625
+ allowTemplate: true
8626
+ };
8479
8627
  class NoStyleTag extends Rule {
8628
+ constructor(options) {
8629
+ super({ ...defaults$c, ...options });
8630
+ }
8631
+ static schema() {
8632
+ return {
8633
+ allowTemplate: {
8634
+ type: "boolean"
8635
+ }
8636
+ };
8637
+ }
8480
8638
  documentation() {
8481
8639
  return {
8482
8640
  description: "Prefer to use external stylesheets with the `<link>` tag instead of inlining the styling.",
@@ -8484,9 +8642,13 @@ class NoStyleTag extends Rule {
8484
8642
  };
8485
8643
  }
8486
8644
  setup() {
8645
+ const { allowTemplate } = this.options;
8487
8646
  this.on("tag:start", (event) => {
8488
8647
  const node = event.target;
8489
8648
  if (node.tagName === "style") {
8649
+ if (allowTemplate && node.parent?.is("template")) {
8650
+ return;
8651
+ }
8490
8652
  this.report(node, "Use external stylesheet with <link> instead of <style> tag");
8491
8653
  }
8492
8654
  });
@@ -9393,7 +9555,7 @@ function getTextFromReference(document, id) {
9393
9555
  if (!id || id instanceof DynamicValue) {
9394
9556
  return id;
9395
9557
  }
9396
- const selector = `#${id}`;
9558
+ const selector = generateIdSelector(id);
9397
9559
  const ref = document.querySelector(selector);
9398
9560
  if (ref) {
9399
9561
  return ref.textContent;
@@ -9709,9 +9871,7 @@ const fieldNameGroup = {
9709
9871
  nickname: "text",
9710
9872
  username: "username",
9711
9873
  "new-password": "password",
9712
- // eslint-disable-line sonarjs/no-hardcoded-passwords -- false positive, it is not used as a password
9713
9874
  "current-password": "password",
9714
- // eslint-disable-line sonarjs/no-hardcoded-passwords -- false positive, it is not used as a password
9715
9875
  "one-time-code": "password",
9716
9876
  "organization-title": "text",
9717
9877
  organization: "text",
@@ -10753,6 +10913,7 @@ const bundledRules = {
10753
10913
  "attribute-boolean-style": AttributeBooleanStyle,
10754
10914
  "attribute-empty-style": AttributeEmptyStyle,
10755
10915
  "attribute-misuse": AttributeMisuse,
10916
+ "autocomplete-password": AutocompletePassword,
10756
10917
  "class-pattern": ClassPattern,
10757
10918
  "close-attr": CloseAttr,
10758
10919
  "close-order": CloseOrder,
@@ -11118,6 +11279,7 @@ const config$1 = {
11118
11279
  "attribute-boolean-style": "error",
11119
11280
  "attribute-empty-style": "error",
11120
11281
  "attribute-misuse": "error",
11282
+ "autocomplete-password": "error",
11121
11283
  "close-attr": "error",
11122
11284
  "close-order": "error",
11123
11285
  deprecated: "error",
@@ -12132,7 +12294,7 @@ class EventHandler {
12132
12294
  }
12133
12295
 
12134
12296
  const name = "html-validate";
12135
- const version = "10.6.0";
12297
+ const version = "10.8.0";
12136
12298
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
12137
12299
 
12138
12300
  function freeze(src) {
@@ -12678,31 +12840,34 @@ class Parser {
12678
12840
  * @internal
12679
12841
  */
12680
12842
  consumeDirective(token) {
12681
- const [text, preamble, action, separator1, directive, postamble] = token.data;
12682
- if (!postamble.startsWith("]")) {
12683
- throw new ParserError(token.location, `Missing end bracket "]" on directive "${text}"`);
12843
+ const [text, preamble, prefix, action, separator1, directive, postamble] = token.data;
12844
+ const hasStartBracket = preamble.includes("[");
12845
+ const hasEndBracket = postamble.startsWith("]");
12846
+ if (hasStartBracket && !hasEndBracket) {
12847
+ this.trigger("parse:error", {
12848
+ location: sliceLocation(token.location, preamble.length - 1, -postamble.length),
12849
+ message: `Missing end bracket "]" on directive "${text}"`
12850
+ });
12851
+ return;
12684
12852
  }
12685
12853
  const match = /^(.*?)(?:(\s*(?:--|:)\s*)(.*))?$/.exec(directive);
12686
12854
  if (!match) {
12687
12855
  throw new Error(`Failed to parse directive "${text}"`);
12688
12856
  }
12689
12857
  if (!isValidDirective(action)) {
12858
+ const begin = preamble.length;
12859
+ const end = preamble.length + prefix.length + action.length;
12690
12860
  this.trigger("parse:error", {
12691
- location: token.location,
12861
+ location: sliceLocation(token.location, begin, -text.length + end),
12692
12862
  message: `Unknown directive "${action}"`
12693
12863
  });
12694
12864
  return;
12695
12865
  }
12696
12866
  const [, data, separator2, comment] = match;
12697
- const prefix = "html-validate-";
12698
- const actionOffset = preamble.length;
12867
+ const actionOffset = preamble.length + prefix.length;
12699
12868
  const optionsOffset = actionOffset + action.length + separator1.length;
12700
12869
  const commentOffset = optionsOffset + data.length + (separator2 || "").length;
12701
- const location = sliceLocation(
12702
- token.location,
12703
- preamble.length - prefix.length - 1,
12704
- -postamble.length + 1
12705
- );
12870
+ const location = sliceLocation(token.location, preamble.length - 1, -postamble.length + 1);
12706
12871
  const actionLocation = sliceLocation(
12707
12872
  token.location,
12708
12873
  actionOffset,