html-validate 6.7.1 → 6.9.1

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
@@ -243,6 +243,42 @@ var ajvSchemaDraft = {
243
243
  }
244
244
  };
245
245
 
246
+ function stringify(value) {
247
+ if (typeof value === "string") {
248
+ return String(value);
249
+ }
250
+ else {
251
+ return JSON.stringify(value);
252
+ }
253
+ }
254
+ /**
255
+ * Represents an `Error` created from arbitrary values.
256
+ *
257
+ * @public
258
+ */
259
+ class WrappedError extends Error {
260
+ constructor(message) {
261
+ super(stringify(message));
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Ensures the value is an Error.
267
+ *
268
+ * If the passed value is not an `Error` instance a [[WrappedError]] is
269
+ * constructed with the stringified value.
270
+ *
271
+ * @internal
272
+ */
273
+ function ensureError(value) {
274
+ if (value instanceof Error) {
275
+ return value;
276
+ }
277
+ else {
278
+ return new WrappedError(value);
279
+ }
280
+ }
281
+
246
282
  class NestedError extends Error {
247
283
  constructor(message, nested) {
248
284
  super(message);
@@ -931,7 +967,7 @@ class MetaTable {
931
967
  if (err instanceof SchemaValidationError) {
932
968
  throw err;
933
969
  }
934
- throw new UserError(`Failed to load element metadata from "${filename}"`, err);
970
+ throw new UserError(`Failed to load element metadata from "${filename}"`, ensureError(err));
935
971
  }
936
972
  }
937
973
  /**
@@ -1202,6 +1238,27 @@ class Attribute {
1202
1238
  }
1203
1239
  }
1204
1240
 
1241
+ function getCSSDeclarations(value) {
1242
+ return value
1243
+ .trim()
1244
+ .split(";")
1245
+ .filter(Boolean)
1246
+ .map((it) => {
1247
+ const [property, value] = it.split(":", 2);
1248
+ return [property.trim(), value ? value.trim() : ""];
1249
+ });
1250
+ }
1251
+ /**
1252
+ * @internal
1253
+ */
1254
+ function parseCssDeclaration(value) {
1255
+ if (!value || value instanceof DynamicValue) {
1256
+ return {};
1257
+ }
1258
+ const pairs = getCSSDeclarations(value);
1259
+ return Object.fromEntries(pairs);
1260
+ }
1261
+
1205
1262
  function sliceSize(size, begin, end) {
1206
1263
  if (typeof size !== "number") {
1207
1264
  return size;
@@ -1957,9 +2014,10 @@ class HtmlElement extends DOMNode {
1957
2014
  /* if a unique id is present, use it and short-circuit */
1958
2015
  if (cur.id) {
1959
2016
  const escaped = escapeSelectorComponent(cur.id);
1960
- const matches = root.querySelectorAll(`#${escaped}`);
2017
+ const selector = escaped.match(/^\d/) ? `[id="${escaped}"]` : `#${escaped}`;
2018
+ const matches = root.querySelectorAll(selector);
1961
2019
  if (matches.length === 1) {
1962
- parts.push(`#${escaped}`);
2020
+ parts.push(selector);
1963
2021
  break;
1964
2022
  }
1965
2023
  }
@@ -2150,6 +2208,10 @@ class HtmlElement extends DOMNode {
2150
2208
  get id() {
2151
2209
  return this.getAttributeValue("id");
2152
2210
  }
2211
+ get style() {
2212
+ const attr = this.getAttribute("style");
2213
+ return parseCssDeclaration(attr === null || attr === void 0 ? void 0 : attr.value);
2214
+ }
2153
2215
  /**
2154
2216
  * Returns the first child element or null if there are no child elements.
2155
2217
  */
@@ -2955,7 +3017,7 @@ var TRANSFORMER_API;
2955
3017
  /** @public */
2956
3018
  const name = "html-validate";
2957
3019
  /** @public */
2958
- const version = "6.7.1";
3020
+ const version = "6.9.1";
2959
3021
  /** @public */
2960
3022
  const homepage = "https://html-validate.org";
2961
3023
  /** @public */
@@ -3276,7 +3338,7 @@ function ruleDocumentationUrl(filename) {
3276
3338
  return `${homepage}/rules/${normalized}.html`;
3277
3339
  }
3278
3340
 
3279
- const defaults$q = {
3341
+ const defaults$r = {
3280
3342
  allowExternal: true,
3281
3343
  allowRelative: true,
3282
3344
  allowAbsolute: true,
@@ -3320,7 +3382,7 @@ function matchList(value, list) {
3320
3382
  }
3321
3383
  class AllowedLinks extends Rule {
3322
3384
  constructor(options) {
3323
- super({ ...defaults$q, ...options });
3385
+ super({ ...defaults$r, ...options });
3324
3386
  this.allowExternal = parseAllow(this.options.allowExternal);
3325
3387
  this.allowRelative = parseAllow(this.options.allowRelative);
3326
3388
  this.allowAbsolute = parseAllow(this.options.allowAbsolute);
@@ -3621,13 +3683,13 @@ class CaseStyle {
3621
3683
  }
3622
3684
  }
3623
3685
 
3624
- const defaults$p = {
3686
+ const defaults$q = {
3625
3687
  style: "lowercase",
3626
3688
  ignoreForeign: true,
3627
3689
  };
3628
3690
  class AttrCase extends Rule {
3629
3691
  constructor(options) {
3630
- super({ ...defaults$p, ...options });
3692
+ super({ ...defaults$q, ...options });
3631
3693
  this.style = new CaseStyle(this.options.style, "attr-case");
3632
3694
  }
3633
3695
  static schema() {
@@ -3943,9 +4005,6 @@ class Lexer {
3943
4005
  }
3944
4006
 
3945
4007
  const whitespace = /(\s+)/;
3946
- function isRelevant$3(event) {
3947
- return event.type === TokenType.ATTR_VALUE;
3948
- }
3949
4008
  class AttrDelimiter extends Rule {
3950
4009
  documentation() {
3951
4010
  return {
@@ -3954,8 +4013,12 @@ class AttrDelimiter extends Rule {
3954
4013
  };
3955
4014
  }
3956
4015
  setup() {
3957
- this.on("token", isRelevant$3, (event) => {
3958
- const delimiter = event.data[1];
4016
+ this.on("token", (event) => {
4017
+ const { token } = event;
4018
+ if (token.type !== TokenType.ATTR_VALUE) {
4019
+ return;
4020
+ }
4021
+ const delimiter = token.data[1];
3959
4022
  const match = whitespace.exec(delimiter);
3960
4023
  if (match) {
3961
4024
  const location = sliceLocation(event.location, 0, delimiter.length);
@@ -3966,7 +4029,7 @@ class AttrDelimiter extends Rule {
3966
4029
  }
3967
4030
 
3968
4031
  const DEFAULT_PATTERN = "[a-z0-9-:]+";
3969
- const defaults$o = {
4032
+ const defaults$p = {
3970
4033
  pattern: DEFAULT_PATTERN,
3971
4034
  ignoreForeign: true,
3972
4035
  };
@@ -4003,7 +4066,7 @@ function generateDescription(name, pattern) {
4003
4066
  }
4004
4067
  class AttrPattern extends Rule {
4005
4068
  constructor(options) {
4006
- super({ ...defaults$o, ...options });
4069
+ super({ ...defaults$p, ...options });
4007
4070
  this.pattern = generateRegexp(this.options.pattern);
4008
4071
  }
4009
4072
  static schema() {
@@ -4063,13 +4126,13 @@ var QuoteStyle;
4063
4126
  QuoteStyle["DOUBLE_QUOTE"] = "\"";
4064
4127
  QuoteStyle["AUTO_QUOTE"] = "auto";
4065
4128
  })(QuoteStyle || (QuoteStyle = {}));
4066
- const defaults$n = {
4129
+ const defaults$o = {
4067
4130
  style: "auto",
4068
4131
  unquoted: false,
4069
4132
  };
4070
4133
  class AttrQuotes extends Rule {
4071
4134
  constructor(options) {
4072
- super({ ...defaults$n, ...options });
4135
+ super({ ...defaults$o, ...options });
4073
4136
  this.style = parseStyle$4(this.options.style);
4074
4137
  }
4075
4138
  static schema() {
@@ -4234,12 +4297,12 @@ class AttributeAllowedValues extends Rule {
4234
4297
  }
4235
4298
  }
4236
4299
 
4237
- const defaults$m = {
4300
+ const defaults$n = {
4238
4301
  style: "omit",
4239
4302
  };
4240
4303
  class AttributeBooleanStyle extends Rule {
4241
4304
  constructor(options) {
4242
- super({ ...defaults$m, ...options });
4305
+ super({ ...defaults$n, ...options });
4243
4306
  this.hasInvalidStyle = parseStyle$3(this.options.style);
4244
4307
  }
4245
4308
  static schema() {
@@ -4315,12 +4378,12 @@ function reportMessage$1(attr, style) {
4315
4378
  return "";
4316
4379
  }
4317
4380
 
4318
- const defaults$l = {
4381
+ const defaults$m = {
4319
4382
  style: "omit",
4320
4383
  };
4321
4384
  class AttributeEmptyStyle extends Rule {
4322
4385
  constructor(options) {
4323
- super({ ...defaults$l, ...options });
4386
+ super({ ...defaults$m, ...options });
4324
4387
  this.hasInvalidStyle = parseStyle$2(this.options.style);
4325
4388
  }
4326
4389
  static schema() {
@@ -4428,12 +4491,12 @@ function describePattern(pattern) {
4428
4491
  }
4429
4492
  }
4430
4493
 
4431
- const defaults$k = {
4494
+ const defaults$l = {
4432
4495
  pattern: "kebabcase",
4433
4496
  };
4434
4497
  class ClassPattern extends Rule {
4435
4498
  constructor(options) {
4436
- super({ ...defaults$k, ...options });
4499
+ super({ ...defaults$l, ...options });
4437
4500
  this.pattern = parsePattern(this.options.pattern);
4438
4501
  }
4439
4502
  static schema() {
@@ -4542,13 +4605,13 @@ class CloseOrder extends Rule {
4542
4605
  }
4543
4606
  }
4544
4607
 
4545
- const defaults$j = {
4608
+ const defaults$k = {
4546
4609
  include: null,
4547
4610
  exclude: null,
4548
4611
  };
4549
4612
  class Deprecated extends Rule {
4550
4613
  constructor(options) {
4551
- super({ ...defaults$j, ...options });
4614
+ super({ ...defaults$k, ...options });
4552
4615
  }
4553
4616
  static schema() {
4554
4617
  return {
@@ -4711,12 +4774,12 @@ class NoStyleTag$1 extends Rule {
4711
4774
  }
4712
4775
  }
4713
4776
 
4714
- const defaults$i = {
4777
+ const defaults$j = {
4715
4778
  style: "uppercase",
4716
4779
  };
4717
4780
  class DoctypeStyle extends Rule {
4718
4781
  constructor(options) {
4719
- super({ ...defaults$i, ...options });
4782
+ super({ ...defaults$j, ...options });
4720
4783
  }
4721
4784
  static schema() {
4722
4785
  return {
@@ -4748,12 +4811,12 @@ class DoctypeStyle extends Rule {
4748
4811
  }
4749
4812
  }
4750
4813
 
4751
- const defaults$h = {
4814
+ const defaults$i = {
4752
4815
  style: "lowercase",
4753
4816
  };
4754
4817
  class ElementCase extends Rule {
4755
4818
  constructor(options) {
4756
- super({ ...defaults$h, ...options });
4819
+ super({ ...defaults$i, ...options });
4757
4820
  this.style = new CaseStyle(this.options.style, "element-case");
4758
4821
  }
4759
4822
  static schema() {
@@ -4819,14 +4882,14 @@ class ElementCase extends Rule {
4819
4882
  }
4820
4883
  }
4821
4884
 
4822
- const defaults$g = {
4885
+ const defaults$h = {
4823
4886
  pattern: "^[a-z][a-z0-9\\-._]*-[a-z0-9\\-._]*$",
4824
4887
  whitelist: [],
4825
4888
  blacklist: [],
4826
4889
  };
4827
4890
  class ElementName extends Rule {
4828
4891
  constructor(options) {
4829
- super({ ...defaults$g, ...options });
4892
+ super({ ...defaults$h, ...options });
4830
4893
  // eslint-disable-next-line security/detect-non-literal-regexp
4831
4894
  this.pattern = new RegExp(this.options.pattern);
4832
4895
  }
@@ -4867,7 +4930,7 @@ class ElementName extends Rule {
4867
4930
  ...context.blacklist.map((cur) => `- ${cur}`),
4868
4931
  ];
4869
4932
  }
4870
- if (context.pattern !== defaults$g.pattern) {
4933
+ if (context.pattern !== defaults$h.pattern) {
4871
4934
  return [
4872
4935
  `<${context.tagName}> is not a valid element name. This project is configured to only allow names matching the following regular expression:`,
4873
4936
  "",
@@ -5269,7 +5332,7 @@ class EmptyTitle extends Rule {
5269
5332
  }
5270
5333
  }
5271
5334
 
5272
- const defaults$f = {
5335
+ const defaults$g = {
5273
5336
  allowMultipleH1: false,
5274
5337
  minInitialRank: "h1",
5275
5338
  sectioningRoots: ["dialog", '[role="dialog"]'],
@@ -5300,7 +5363,7 @@ function parseMaxInitial(value) {
5300
5363
  }
5301
5364
  class HeadingLevel extends Rule {
5302
5365
  constructor(options) {
5303
- super({ ...defaults$f, ...options });
5366
+ super({ ...defaults$g, ...options });
5304
5367
  this.stack = [];
5305
5368
  this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
5306
5369
  this.sectionRoots = this.options.sectioningRoots.map((it) => new Pattern(it));
@@ -5458,12 +5521,12 @@ class HeadingLevel extends Rule {
5458
5521
  }
5459
5522
  }
5460
5523
 
5461
- const defaults$e = {
5524
+ const defaults$f = {
5462
5525
  pattern: "kebabcase",
5463
5526
  };
5464
5527
  class IdPattern extends Rule {
5465
5528
  constructor(options) {
5466
- super({ ...defaults$e, ...options });
5529
+ super({ ...defaults$f, ...options });
5467
5530
  this.pattern = parsePattern(this.options.pattern);
5468
5531
  }
5469
5532
  static schema() {
@@ -5814,12 +5877,12 @@ function findLabelByParent(el) {
5814
5877
  return [];
5815
5878
  }
5816
5879
 
5817
- const defaults$d = {
5880
+ const defaults$e = {
5818
5881
  maxlength: 70,
5819
5882
  };
5820
5883
  class LongTitle extends Rule {
5821
5884
  constructor(options) {
5822
- super({ ...defaults$d, ...options });
5885
+ super({ ...defaults$e, ...options });
5823
5886
  this.maxlength = this.options.maxlength;
5824
5887
  }
5825
5888
  static schema() {
@@ -5966,13 +6029,13 @@ class MultipleLabeledControls extends Rule {
5966
6029
  }
5967
6030
  }
5968
6031
 
5969
- const defaults$c = {
6032
+ const defaults$d = {
5970
6033
  include: null,
5971
6034
  exclude: null,
5972
6035
  };
5973
6036
  class NoAutoplay extends Rule {
5974
6037
  constructor(options) {
5975
- super({ ...defaults$c, ...options });
6038
+ super({ ...defaults$d, ...options });
5976
6039
  }
5977
6040
  documentation(context) {
5978
6041
  const tagName = context ? ` on <${context.tagName}>` : "";
@@ -6213,24 +6276,14 @@ Omitted end tags can be ambigious for humans to read and many editors have troub
6213
6276
  }
6214
6277
  }
6215
6278
 
6216
- const defaults$b = {
6279
+ const defaults$c = {
6217
6280
  include: null,
6218
6281
  exclude: null,
6219
6282
  allowedProperties: ["display"],
6220
6283
  };
6221
- function getCSSDeclarations(value) {
6222
- return value
6223
- .trim()
6224
- .split(";")
6225
- .filter(Boolean)
6226
- .map((it) => {
6227
- const [property, value] = it.split(":", 2);
6228
- return { property: property.trim(), value: value ? value.trim() : undefined };
6229
- });
6230
- }
6231
6284
  class NoInlineStyle extends Rule {
6232
6285
  constructor(options) {
6233
- super({ ...defaults$b, ...options });
6286
+ super({ ...defaults$c, ...options });
6234
6287
  }
6235
6288
  static schema() {
6236
6289
  return {
@@ -6308,18 +6361,15 @@ class NoInlineStyle extends Rule {
6308
6361
  return true;
6309
6362
  }
6310
6363
  allPropertiesAllowed(value) {
6311
- if (typeof value !== "string") {
6312
- return false;
6313
- }
6314
6364
  const allowProperties = this.options.allowedProperties;
6315
6365
  /* quick path: no properties are allowed, no need to check each one individually */
6316
6366
  if (allowProperties.length === 0) {
6317
6367
  return false;
6318
6368
  }
6319
- const declarations = getCSSDeclarations(value);
6369
+ const declarations = Object.keys(parseCssDeclaration(value));
6320
6370
  return (declarations.length > 0 &&
6321
6371
  declarations.every((it) => {
6322
- return allowProperties.includes(it.property);
6372
+ return allowProperties.includes(it);
6323
6373
  }));
6324
6374
  }
6325
6375
  }
@@ -6435,7 +6485,7 @@ class NoMultipleMain extends Rule {
6435
6485
  }
6436
6486
  }
6437
6487
 
6438
- const defaults$a = {
6488
+ const defaults$b = {
6439
6489
  relaxed: false,
6440
6490
  };
6441
6491
  const textRegexp = /([<>]|&(?![a-zA-Z0-9#]+;))/g;
@@ -6452,7 +6502,7 @@ const replacementTable = {
6452
6502
  };
6453
6503
  class NoRawCharacters extends Rule {
6454
6504
  constructor(options) {
6455
- super({ ...defaults$a, ...options });
6505
+ super({ ...defaults$b, ...options });
6456
6506
  this.relaxed = this.options.relaxed;
6457
6507
  }
6458
6508
  static schema() {
@@ -6630,13 +6680,13 @@ class NoRedundantRole extends Rule {
6630
6680
  }
6631
6681
 
6632
6682
  const xmlns = /^(.+):.+$/;
6633
- const defaults$9 = {
6683
+ const defaults$a = {
6634
6684
  ignoreForeign: true,
6635
6685
  ignoreXML: true,
6636
6686
  };
6637
6687
  class NoSelfClosing extends Rule {
6638
6688
  constructor(options) {
6639
- super({ ...defaults$9, ...options });
6689
+ super({ ...defaults$a, ...options });
6640
6690
  }
6641
6691
  static schema() {
6642
6692
  return {
@@ -6769,13 +6819,13 @@ const replacement = {
6769
6819
  reset: '<button type="reset">',
6770
6820
  image: '<button type="button">',
6771
6821
  };
6772
- const defaults$8 = {
6822
+ const defaults$9 = {
6773
6823
  include: null,
6774
6824
  exclude: null,
6775
6825
  };
6776
6826
  class PreferButton extends Rule {
6777
6827
  constructor(options) {
6778
- super({ ...defaults$8, ...options });
6828
+ super({ ...defaults$9, ...options });
6779
6829
  }
6780
6830
  static schema() {
6781
6831
  return {
@@ -6850,7 +6900,7 @@ class PreferButton extends Rule {
6850
6900
  }
6851
6901
  }
6852
6902
 
6853
- const defaults$7 = {
6903
+ const defaults$8 = {
6854
6904
  mapping: {
6855
6905
  article: "article",
6856
6906
  banner: "header",
@@ -6880,7 +6930,7 @@ const defaults$7 = {
6880
6930
  };
6881
6931
  class PreferNativeElement extends Rule {
6882
6932
  constructor(options) {
6883
- super({ ...defaults$7, ...options });
6933
+ super({ ...defaults$8, ...options });
6884
6934
  }
6885
6935
  static schema() {
6886
6936
  return {
@@ -7000,7 +7050,7 @@ class PreferTbody extends Rule {
7000
7050
  }
7001
7051
  }
7002
7052
 
7003
- const defaults$6 = {
7053
+ const defaults$7 = {
7004
7054
  target: "all",
7005
7055
  };
7006
7056
  const crossorigin = new RegExp("^(\\w+://|//)"); /* e.g. https:// or // */
@@ -7010,7 +7060,7 @@ const supportSri = {
7010
7060
  };
7011
7061
  class RequireSri extends Rule {
7012
7062
  constructor(options) {
7013
- super({ ...defaults$6, ...options });
7063
+ super({ ...defaults$7, ...options });
7014
7064
  this.target = this.options.target;
7015
7065
  }
7016
7066
  static schema() {
@@ -7138,12 +7188,13 @@ class SvgFocusable extends Rule {
7138
7188
  }
7139
7189
  }
7140
7190
 
7141
- const defaults$5 = {
7191
+ const defaults$6 = {
7142
7192
  characters: [
7143
7193
  { pattern: " ", replacement: "&nbsp;", description: "non-breaking space" },
7144
7194
  { pattern: "-", replacement: "&#8209;", description: "non-breaking hyphen" },
7145
7195
  ],
7146
7196
  ignoreClasses: [],
7197
+ ignoreStyle: true,
7147
7198
  };
7148
7199
  function constructRegex(characters) {
7149
7200
  const disallowed = characters
@@ -7180,7 +7231,7 @@ function matchAll(text, regexp) {
7180
7231
  }
7181
7232
  class TelNonBreaking extends Rule {
7182
7233
  constructor(options) {
7183
- super({ ...defaults$5, ...options });
7234
+ super({ ...defaults$6, ...options });
7184
7235
  this.regex = constructRegex(this.options.characters);
7185
7236
  }
7186
7237
  static schema() {
@@ -7209,6 +7260,9 @@ class TelNonBreaking extends Rule {
7209
7260
  type: "string",
7210
7261
  },
7211
7262
  },
7263
+ ignoreStyle: {
7264
+ type: "boolean",
7265
+ },
7212
7266
  };
7213
7267
  }
7214
7268
  documentation(context) {
@@ -7235,10 +7289,7 @@ class TelNonBreaking extends Rule {
7235
7289
  setup() {
7236
7290
  this.on("element:ready", this.isRelevant, (event) => {
7237
7291
  const { target } = event;
7238
- const { ignoreClasses } = this.options;
7239
- /* skip if element has a class in the ignore list */
7240
- const isIgnored = ignoreClasses.some((it) => target.classList.contains(it));
7241
- if (isIgnored) {
7292
+ if (this.isIgnored(target)) {
7242
7293
  return;
7243
7294
  }
7244
7295
  this.walk(target, target);
@@ -7257,6 +7308,25 @@ class TelNonBreaking extends Rule {
7257
7308
  }
7258
7309
  return true;
7259
7310
  }
7311
+ isIgnoredClass(node) {
7312
+ const { ignoreClasses } = this.options;
7313
+ const { classList } = node;
7314
+ return ignoreClasses.some((it) => classList.contains(it));
7315
+ }
7316
+ isIgnoredStyle(node) {
7317
+ const { ignoreStyle } = this.options;
7318
+ const { style } = node;
7319
+ if (!ignoreStyle) {
7320
+ return false;
7321
+ }
7322
+ if (style["white-space"] === "nowrap" || style["white-space"] === "pre") {
7323
+ return true;
7324
+ }
7325
+ return false;
7326
+ }
7327
+ isIgnored(node) {
7328
+ return this.isIgnoredClass(node) || this.isIgnoredStyle(node);
7329
+ }
7260
7330
  walk(anchor, node) {
7261
7331
  for (const child of node.childNodes) {
7262
7332
  if (isTextNode(child)) {
@@ -9240,6 +9310,95 @@ class UnknownCharReference extends Rule {
9240
9310
  }
9241
9311
  }
9242
9312
 
9313
+ var RuleContext;
9314
+ (function (RuleContext) {
9315
+ RuleContext[RuleContext["EMPTY"] = 1] = "EMPTY";
9316
+ RuleContext[RuleContext["WHITESPACE"] = 2] = "WHITESPACE";
9317
+ RuleContext[RuleContext["LEADING_CHARACTER"] = 3] = "LEADING_CHARACTER";
9318
+ RuleContext[RuleContext["DISALLOWED_CHARACTER"] = 4] = "DISALLOWED_CHARACTER";
9319
+ })(RuleContext || (RuleContext = {}));
9320
+ const defaults$5 = {
9321
+ relaxed: false,
9322
+ };
9323
+ class ValidID extends Rule {
9324
+ constructor(options) {
9325
+ super({ ...defaults$5, ...options });
9326
+ }
9327
+ static schema() {
9328
+ return {
9329
+ relaxed: {
9330
+ type: "boolean",
9331
+ },
9332
+ };
9333
+ }
9334
+ documentation(context) {
9335
+ const { relaxed } = this.options;
9336
+ const message = context
9337
+ ? this.messages[context].replace("id", "ID").replace(/^(.)/, (m) => m.toUpperCase())
9338
+ : "Element ID is not valid";
9339
+ const relaxedDescription = relaxed
9340
+ ? []
9341
+ : [
9342
+ " - ID must begin with a letter",
9343
+ " - ID must only contain alphanumerical characters, `-` and `_`",
9344
+ ];
9345
+ return {
9346
+ description: [
9347
+ `${message}.`,
9348
+ "",
9349
+ "Under the current configuration the following rules are applied:",
9350
+ "",
9351
+ " - ID must not be empty",
9352
+ " - ID must not contain any whitespace characters",
9353
+ ...relaxedDescription,
9354
+ ].join("\n"),
9355
+ url: ruleDocumentationUrl("@/rules/valid-id.ts"),
9356
+ };
9357
+ }
9358
+ setup() {
9359
+ this.on("attr", this.isRelevant, (event) => {
9360
+ const { value } = event;
9361
+ if (value === null || value instanceof DynamicValue) {
9362
+ return;
9363
+ }
9364
+ if (value === "") {
9365
+ const context = RuleContext.EMPTY;
9366
+ this.report(event.target, this.messages[context], event.location, context);
9367
+ return;
9368
+ }
9369
+ if (value.match(/\s/)) {
9370
+ const context = RuleContext.WHITESPACE;
9371
+ this.report(event.target, this.messages[context], event.valueLocation, context);
9372
+ return;
9373
+ }
9374
+ const { relaxed } = this.options;
9375
+ if (relaxed) {
9376
+ return;
9377
+ }
9378
+ if (value.match(/^[^a-zA-Z]/)) {
9379
+ const context = RuleContext.LEADING_CHARACTER;
9380
+ this.report(event.target, this.messages[context], event.valueLocation, context);
9381
+ return;
9382
+ }
9383
+ if (value.match(/[^a-zA-Z0-9-_]/)) {
9384
+ const context = RuleContext.DISALLOWED_CHARACTER;
9385
+ this.report(event.target, this.messages[context], event.valueLocation, context);
9386
+ }
9387
+ });
9388
+ }
9389
+ get messages() {
9390
+ return {
9391
+ [RuleContext.EMPTY]: "element id must not be empty",
9392
+ [RuleContext.WHITESPACE]: "element id must not contain whitespace",
9393
+ [RuleContext.LEADING_CHARACTER]: "element id must begin with a letter",
9394
+ [RuleContext.DISALLOWED_CHARACTER]: "element id must only contain alphanumerical, dash and underscore characters",
9395
+ };
9396
+ }
9397
+ isRelevant(event) {
9398
+ return event.key === "id";
9399
+ }
9400
+ }
9401
+
9243
9402
  var Style$1;
9244
9403
  (function (Style) {
9245
9404
  Style[Style["Any"] = 0] = "Any";
@@ -9751,6 +9910,7 @@ const bundledRules = {
9751
9910
  "tel-non-breaking": TelNonBreaking,
9752
9911
  "text-content": TextContent,
9753
9912
  "unrecognized-char-ref": UnknownCharReference,
9913
+ "valid-id": ValidID,
9754
9914
  void: Void,
9755
9915
  "void-content": VoidContent,
9756
9916
  "void-style": VoidStyle,
@@ -9848,6 +10008,7 @@ const config$1 = {
9848
10008
  "tel-non-breaking": "error",
9849
10009
  "text-content": "error",
9850
10010
  "unrecognized-char-ref": "error",
10011
+ "valid-id": ["error", { relaxed: false }],
9851
10012
  void: "off",
9852
10013
  "void-content": "error",
9853
10014
  "void-style": "error",
@@ -9883,6 +10044,7 @@ const config = {
9883
10044
  "no-raw-characters": ["error", { relaxed: true }],
9884
10045
  "script-element": "error",
9885
10046
  "unrecognized-char-ref": "error",
10047
+ "valid-id": ["error", { relaxed: true }],
9886
10048
  "void-content": "error",
9887
10049
  },
9888
10050
  };
@@ -9952,7 +10114,7 @@ class ResolvedConfig {
9952
10114
  }
9953
10115
  catch (err) {
9954
10116
  const message = err instanceof Error ? err.message : String(err);
9955
- throw new NestedError(`When transforming "${source.filename}": ${message}`, err);
10117
+ throw new NestedError(`When transforming "${source.filename}": ${message}`, ensureError(err));
9956
10118
  }
9957
10119
  }
9958
10120
  else {
@@ -10024,7 +10186,7 @@ function loadFromFile(filename) {
10024
10186
  json = requireUncached(filename);
10025
10187
  }
10026
10188
  catch (err) {
10027
- throw new ConfigError(`Failed to read configuration from "${filename}"`, err);
10189
+ throw new ConfigError(`Failed to read configuration from "${filename}"`, ensureError(err));
10028
10190
  }
10029
10191
  /* expand any relative paths */
10030
10192
  for (const key of ["extends", "elements", "plugins"]) {
@@ -10212,7 +10374,7 @@ class Config {
10212
10374
  }
10213
10375
  let filename;
10214
10376
  /* try searching builtin metadata */
10215
- filename = path.join(projectRoot, "elements", `${entry}.json`);
10377
+ filename = path.join(projectRoot, "elements", `${entry}.js`);
10216
10378
  if (fs.existsSync(filename)) {
10217
10379
  metaTable.loadFromFile(filename);
10218
10380
  continue;
@@ -10229,7 +10391,7 @@ class Config {
10229
10391
  }
10230
10392
  catch (err) {
10231
10393
  const message = err instanceof Error ? err.message : String(err);
10232
- throw new ConfigError(`Failed to load elements from "${entry}": ${message}`, err);
10394
+ throw new ConfigError(`Failed to load elements from "${entry}": ${message}`, ensureError(err));
10233
10395
  }
10234
10396
  }
10235
10397
  metaTable.init();
@@ -10306,7 +10468,7 @@ class Config {
10306
10468
  }
10307
10469
  catch (err) {
10308
10470
  const message = err instanceof Error ? err.message : String(err);
10309
- throw new ConfigError(`Failed to load plugin "${moduleName}": ${message}`, err);
10471
+ throw new ConfigError(`Failed to load plugin "${moduleName}": ${message}`, ensureError(err));
10310
10472
  }
10311
10473
  });
10312
10474
  }
@@ -10399,7 +10561,7 @@ class Config {
10399
10561
  throw new ConfigError(`Failed to load transformer "${name}": ${err.message}`, err);
10400
10562
  }
10401
10563
  else {
10402
- throw new ConfigError(`Failed to load transformer "${name}"`, err);
10564
+ throw new ConfigError(`Failed to load transformer "${name}"`, ensureError(err));
10403
10565
  }
10404
10566
  }
10405
10567
  });
@@ -11123,6 +11285,7 @@ class Parser {
11123
11285
  location: token.location,
11124
11286
  type: token.type,
11125
11287
  data: Array.from(token.data),
11288
+ token,
11126
11289
  });
11127
11290
  }
11128
11291
  return it;
@@ -11171,6 +11334,12 @@ class Parser {
11171
11334
  }
11172
11335
  }
11173
11336
 
11337
+ function freeze(src) {
11338
+ return {
11339
+ ...src,
11340
+ selector: src.selector(),
11341
+ };
11342
+ }
11174
11343
  /**
11175
11344
  * @internal
11176
11345
  */
@@ -11222,7 +11391,9 @@ class Reporter {
11222
11391
  line: location.line,
11223
11392
  column: location.column,
11224
11393
  size: location.size || 0,
11225
- selector: node ? node.generateSelector() : null,
11394
+ selector() {
11395
+ return node ? node.generateSelector() : null;
11396
+ },
11226
11397
  context,
11227
11398
  });
11228
11399
  }
@@ -11236,7 +11407,7 @@ class Reporter {
11236
11407
  const report = {
11237
11408
  valid: this.isValid(),
11238
11409
  results: Object.keys(this.result).map((filePath) => {
11239
- const messages = Array.from(this.result[filePath]).sort(messageSort);
11410
+ const messages = Array.from(this.result[filePath], freeze).sort(messageSort);
11240
11411
  const source = (sources || []).find((source) => { var _a; return filePath === ((_a = source.filename) !== null && _a !== void 0 ? _a : ""); });
11241
11412
  return {
11242
11413
  filePath,
@@ -11433,8 +11604,9 @@ class Engine {
11433
11604
  getRuleDocumentation(ruleId, context // eslint-disable-line @typescript-eslint/explicit-module-boundary-types
11434
11605
  ) {
11435
11606
  const rules = this.config.getRules();
11436
- if (rules.has(ruleId)) {
11437
- const [, options] = rules.get(ruleId);
11607
+ const ruleData = rules.get(ruleId);
11608
+ if (ruleData) {
11609
+ const [, options] = ruleData;
11438
11610
  const rule = this.instantiateRule(ruleId, options);
11439
11611
  return rule.documentation(context);
11440
11612
  }
@@ -11638,7 +11810,7 @@ class Engine {
11638
11810
  line: location.line,
11639
11811
  column: location.column,
11640
11812
  size: location.size || 0,
11641
- selector: null,
11813
+ selector: () => null,
11642
11814
  });
11643
11815
  }
11644
11816
  }
@@ -12161,6 +12333,7 @@ const formatter$4 = checkstyleFormatter;
12161
12333
  const defaults = {
12162
12334
  showLink: true,
12163
12335
  showSummary: true,
12336
+ showSelector: false,
12164
12337
  };
12165
12338
  /**
12166
12339
  * Codeframe formatter based on ESLint codeframe.
@@ -12216,6 +12389,7 @@ function getEndLocation(message, source) {
12216
12389
  * @returns The formatted output.
12217
12390
  */
12218
12391
  function formatMessage(message, parentResult, options) {
12392
+ var _a;
12219
12393
  const type = message.severity === 2 ? kleur.red("error") : kleur.yellow("warning");
12220
12394
  const msg = `${kleur.bold(message.message.replace(/([^ ])\.$/, "$1"))}`;
12221
12395
  const ruleId = kleur.dim(`(${message.ruleId})`);
@@ -12238,6 +12412,9 @@ function formatMessage(message, parentResult, options) {
12238
12412
  end: getEndLocation(message, sourceCode),
12239
12413
  }, { highlightCode: false }));
12240
12414
  }
12415
+ if (options.showSelector) {
12416
+ result.push(`${kleur.bold("Selector:")} ${(_a = message.selector) !== null && _a !== void 0 ? _a : "-"}`);
12417
+ }
12241
12418
  if (options.showLink && message.ruleUrl) {
12242
12419
  result.push(`${kleur.bold("Details:")} ${message.ruleUrl}`);
12243
12420
  }
@@ -12360,5 +12537,5 @@ function getFormatter(name) {
12360
12537
  return (_a = availableFormatters[name]) !== null && _a !== void 0 ? _a : null;
12361
12538
  }
12362
12539
 
12363
- export { Config as C, DynamicValue as D, EventHandler as E, FileSystemConfigLoader as F, HtmlValidate as H, MetaTable as M, NodeClosed as N, Parser as P, Rule as R, Severity as S, TextNode as T, UserError as U, ConfigError as a, ConfigLoader as b, StaticConfigLoader as c, HtmlElement as d, SchemaValidationError as e, MetaCopyableProperty as f, Reporter as g, TemplateExtractor as h, getFormatter as i, compatibilityCheck as j, TokenType as k, legacyRequire as l, bugs as m, name as n, presets as p, ruleExists as r, version as v };
12540
+ export { Config as C, DynamicValue as D, EventHandler as E, FileSystemConfigLoader as F, HtmlValidate as H, MetaTable as M, NodeClosed as N, Parser as P, Rule as R, Severity as S, TextNode as T, UserError as U, WrappedError as W, ConfigError as a, ConfigLoader as b, StaticConfigLoader as c, HtmlElement as d, SchemaValidationError as e, NestedError as f, MetaCopyableProperty as g, Reporter as h, TemplateExtractor as i, getFormatter as j, ensureError as k, legacyRequire as l, compatibilityCheck as m, codeframe as n, name as o, presets as p, bugs as q, ruleExists as r, version as v };
12364
12541
  //# sourceMappingURL=core.js.map