html-validate 6.7.1 → 6.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.
@@ -1,3 +1,3 @@
1
- export { A as AttributeData, X as AttributeEvent, Z as ConditionalEvent, C as Config, a as ConfigData, b as ConfigError, c as ConfigLoader, F as ConfigReadyEvent, a0 as DOMLoadEvent, a1 as DOMReadyEvent, _ as DirectiveEvent, $ as DoctypeEvent, D as DynamicValue, W as ElementReadyEvent, B as Event, z as EventCallback, E as EventDump, y as EventHandler, e as HtmlElement, H as HtmlValidate, a3 as ListenEventMap, L as Location, o as Message, j as MetaCopyableProperty, M as MetaData, h as MetaElement, i as MetaTable, N as NodeClosed, w as Parser, u as Plugin, P as ProcessElementContext, m as Report, n as Reporter, q as Result, R as Rule, k as RuleDocumentation, g as SchemaValidationError, S as Severity, l as Source, G as SourceReadyEvent, d as StaticConfigLoader, Q as TagCloseEvent, O as TagEndEvent, K as TagOpenEvent, V as TagReadyEvent, J as TagStartEvent, t as TemplateExtractor, T as TextNode, f as TokenDump, I as TokenEvent, r as TransformContext, s as Transformer, a2 as TriggerEventMap, U as UserError, Y as WhitespaceEvent, p as configPresets, x as ruleExists, v as version } from './core.js';
1
+ export { A as AttributeData, Z as AttributeEvent, f as CSSStyleDeclaration, $ as ConditionalEvent, C as Config, a as ConfigData, b as ConfigError, c as ConfigLoader, I as ConfigReadyEvent, a2 as DOMLoadEvent, a3 as DOMReadyEvent, s as DeferredMessage, a0 as DirectiveEvent, a1 as DoctypeEvent, D as DynamicValue, Y as ElementReadyEvent, G as Event, F as EventCallback, E as EventDump, B as EventHandler, e as HtmlElement, H as HtmlValidate, a5 as ListenEventMap, L as Location, q as Message, k as MetaCopyableProperty, M as MetaData, i as MetaElement, j as MetaTable, N as NodeClosed, y as Parser, x as Plugin, P as ProcessElementContext, n as Report, o as Reporter, r as Result, R as Rule, l as RuleDocumentation, h as SchemaValidationError, S as Severity, m as Source, J as SourceReadyEvent, d as StaticConfigLoader, W as TagCloseEvent, V as TagEndEvent, Q as TagOpenEvent, X as TagReadyEvent, O as TagStartEvent, w as TemplateExtractor, T as TextNode, g as TokenDump, K as TokenEvent, t as TransformContext, u as Transformer, a4 as TriggerEventMap, U as UserError, _ as WhitespaceEvent, p as configPresets, z as ruleExists, v as version } from './core.js';
2
2
  import 'ajv';
3
3
  import 'ajv/dist/types';
@@ -215,6 +215,12 @@ interface Message {
215
215
  */
216
216
  context?: any;
217
217
  }
218
+ /**
219
+ * @internal
220
+ */
221
+ interface DeferredMessage extends Omit<Message, "selector"> {
222
+ selector: () => string | null;
223
+ }
218
224
  /**
219
225
  * @public
220
226
  */
@@ -244,16 +250,14 @@ interface Report {
244
250
  * @internal
245
251
  */
246
252
  declare class Reporter {
247
- protected result: {
248
- [filename: string]: Message[];
249
- };
253
+ protected result: Record<string, DeferredMessage[]>;
250
254
  constructor();
251
255
  /**
252
256
  * Merge two or more reports into a single one.
253
257
  */
254
258
  static merge(reports: Report[]): Report;
255
259
  add<ContextType, OptionsType>(rule: Rule<ContextType, OptionsType>, message: string, severity: number, node: DOMNode | null, location: Location, context?: ContextType): void;
256
- addManual(filename: string, message: Message): void;
260
+ addManual(filename: string, message: DeferredMessage): void;
257
261
  save(sources?: Source[]): Report;
258
262
  protected isValid(): boolean;
259
263
  }
@@ -981,6 +985,10 @@ declare class Attribute {
981
985
  valueMatches(pattern: string, dynamicMatches?: boolean): boolean;
982
986
  }
983
987
 
988
+ interface CSSStyleDeclaration {
989
+ [key: string]: string;
990
+ }
991
+
984
992
  interface PermittedGroup {
985
993
  exclude?: string | string[];
986
994
  }
@@ -1362,6 +1370,7 @@ declare class HtmlElement extends DOMNode {
1362
1370
  * Get element ID if present.
1363
1371
  */
1364
1372
  get id(): string | null;
1373
+ get style(): CSSStyleDeclaration;
1365
1374
  /**
1366
1375
  * Returns the first child element or null if there are no child elements.
1367
1376
  */
@@ -2310,4 +2319,4 @@ declare type Formatter = (results: Result[]) => string;
2310
2319
  */
2311
2320
  declare function getFormatter(name: string): Formatter | null;
2312
2321
 
2313
- export { DoctypeEvent as $, AttributeData as A, Event as B, Config as C, DynamicValue as D, EventDump as E, ConfigReadyEvent as F, SourceReadyEvent as G, HtmlValidate as H, TokenEvent as I, TagStartEvent as J, TagOpenEvent as K, Location as L, MetaData as M, NodeClosed as N, TagEndEvent as O, ProcessElementContext as P, TagCloseEvent as Q, Rule as R, Severity as S, TextNode as T, UserError as U, TagReadyEvent as V, ElementReadyEvent as W, AttributeEvent as X, WhitespaceEvent as Y, ConditionalEvent as Z, DirectiveEvent as _, ConfigData as a, DOMLoadEvent as a0, DOMReadyEvent as a1, TriggerEventMap as a2, ListenEventMap as a3, FileSystemConfigLoader as a4, Formatter as a5, getFormatter as a6, compatibilityCheck as a7, CompatibilityOptions as a8, TokenType as a9, ConfigError as b, ConfigLoader as c, StaticConfigLoader as d, HtmlElement as e, TokenDump as f, SchemaValidationError as g, MetaElement as h, MetaTable as i, MetaCopyableProperty as j, RuleDocumentation as k, Source as l, Report as m, Reporter as n, Message as o, presets as p, Result as q, TransformContext as r, Transformer as s, TemplateExtractor as t, Plugin as u, version as v, Parser as w, ruleExists as x, EventHandler as y, EventCallback as z };
2322
+ export { ConditionalEvent as $, AttributeData as A, EventHandler as B, Config as C, DynamicValue as D, EventDump as E, EventCallback as F, Event as G, HtmlValidate as H, ConfigReadyEvent as I, SourceReadyEvent as J, TokenEvent as K, Location as L, MetaData as M, NodeClosed as N, TagStartEvent as O, ProcessElementContext as P, TagOpenEvent as Q, Rule as R, Severity as S, TextNode as T, UserError as U, TagEndEvent as V, TagCloseEvent as W, TagReadyEvent as X, ElementReadyEvent as Y, AttributeEvent as Z, WhitespaceEvent as _, ConfigData as a, DirectiveEvent as a0, DoctypeEvent as a1, DOMLoadEvent as a2, DOMReadyEvent as a3, TriggerEventMap as a4, ListenEventMap as a5, FileSystemConfigLoader as a6, Formatter as a7, getFormatter as a8, compatibilityCheck as a9, CompatibilityOptions as aa, ConfigError as b, ConfigLoader as c, StaticConfigLoader as d, HtmlElement as e, CSSStyleDeclaration as f, TokenDump as g, SchemaValidationError as h, MetaElement as i, MetaTable as j, MetaCopyableProperty as k, RuleDocumentation as l, Source as m, Report as n, Reporter as o, presets as p, Message as q, Result as r, DeferredMessage as s, TransformContext as t, Transformer as u, version as v, TemplateExtractor as w, Plugin as x, Parser as y, ruleExists as z };
package/dist/cjs/core.js CHANGED
@@ -1233,6 +1233,27 @@ class Attribute {
1233
1233
  }
1234
1234
  }
1235
1235
 
1236
+ function getCSSDeclarations(value) {
1237
+ return value
1238
+ .trim()
1239
+ .split(";")
1240
+ .filter(Boolean)
1241
+ .map((it) => {
1242
+ const [property, value] = it.split(":", 2);
1243
+ return [property.trim(), value ? value.trim() : ""];
1244
+ });
1245
+ }
1246
+ /**
1247
+ * @internal
1248
+ */
1249
+ function parseCssDeclaration(value) {
1250
+ if (!value || value instanceof DynamicValue) {
1251
+ return {};
1252
+ }
1253
+ const pairs = getCSSDeclarations(value);
1254
+ return Object.fromEntries(pairs);
1255
+ }
1256
+
1236
1257
  function sliceSize(size, begin, end) {
1237
1258
  if (typeof size !== "number") {
1238
1259
  return size;
@@ -2181,6 +2202,10 @@ class HtmlElement extends DOMNode {
2181
2202
  get id() {
2182
2203
  return this.getAttributeValue("id");
2183
2204
  }
2205
+ get style() {
2206
+ const attr = this.getAttribute("style");
2207
+ return parseCssDeclaration(attr === null || attr === void 0 ? void 0 : attr.value);
2208
+ }
2184
2209
  /**
2185
2210
  * Returns the first child element or null if there are no child elements.
2186
2211
  */
@@ -2986,7 +3011,7 @@ var TRANSFORMER_API;
2986
3011
  /** @public */
2987
3012
  const name = "html-validate";
2988
3013
  /** @public */
2989
- const version = "6.7.1";
3014
+ const version = "6.8.0";
2990
3015
  /** @public */
2991
3016
  const homepage = "https://html-validate.org";
2992
3017
  /** @public */
@@ -3720,7 +3745,7 @@ class AttrCase extends Rule {
3720
3745
  }
3721
3746
  }
3722
3747
 
3723
- exports.TokenType = void 0;
3748
+ var TokenType;
3724
3749
  (function (TokenType) {
3725
3750
  TokenType[TokenType["UNICODE_BOM"] = 1] = "UNICODE_BOM";
3726
3751
  TokenType[TokenType["WHITESPACE"] = 2] = "WHITESPACE";
@@ -3739,7 +3764,7 @@ exports.TokenType = void 0;
3739
3764
  TokenType[TokenType["CONDITIONAL"] = 15] = "CONDITIONAL";
3740
3765
  TokenType[TokenType["DIRECTIVE"] = 16] = "DIRECTIVE";
3741
3766
  TokenType[TokenType["EOF"] = 17] = "EOF";
3742
- })(exports.TokenType || (exports.TokenType = {}));
3767
+ })(TokenType || (TokenType = {}));
3743
3768
 
3744
3769
  /* eslint-disable no-useless-escape */
3745
3770
  const MATCH_UNICODE_BOM = /^\uFEFF/;
@@ -3818,7 +3843,7 @@ class Lexer {
3818
3843
  previousState = context.state;
3819
3844
  previousLength = context.string.length;
3820
3845
  }
3821
- yield this.token(context, exports.TokenType.EOF, []);
3846
+ yield this.token(context, TokenType.EOF, []);
3822
3847
  }
3823
3848
  token(context, type, data) {
3824
3849
  const size = data.length > 0 ? data[0].length : 0;
@@ -3889,21 +3914,21 @@ class Lexer {
3889
3914
  }
3890
3915
  *tokenizeInitial(context) {
3891
3916
  yield* this.match(context, [
3892
- [MATCH_UNICODE_BOM, State.INITIAL, exports.TokenType.UNICODE_BOM],
3917
+ [MATCH_UNICODE_BOM, State.INITIAL, TokenType.UNICODE_BOM],
3893
3918
  [MATCH_XML_TAG, State.INITIAL, false],
3894
- [MATCH_DOCTYPE_OPEN, State.DOCTYPE, exports.TokenType.DOCTYPE_OPEN],
3895
- [MATCH_WHITESPACE, State.INITIAL, exports.TokenType.WHITESPACE],
3896
- [MATCH_DIRECTIVE, State.INITIAL, exports.TokenType.DIRECTIVE],
3897
- [MATCH_CONDITIONAL, State.INITIAL, exports.TokenType.CONDITIONAL],
3898
- [MATCH_COMMENT, State.INITIAL, exports.TokenType.COMMENT],
3919
+ [MATCH_DOCTYPE_OPEN, State.DOCTYPE, TokenType.DOCTYPE_OPEN],
3920
+ [MATCH_WHITESPACE, State.INITIAL, TokenType.WHITESPACE],
3921
+ [MATCH_DIRECTIVE, State.INITIAL, TokenType.DIRECTIVE],
3922
+ [MATCH_CONDITIONAL, State.INITIAL, TokenType.CONDITIONAL],
3923
+ [MATCH_COMMENT, State.INITIAL, TokenType.COMMENT],
3899
3924
  [false, State.TEXT, false],
3900
3925
  ], "expected doctype");
3901
3926
  }
3902
3927
  *tokenizeDoctype(context) {
3903
3928
  yield* this.match(context, [
3904
- [MATCH_WHITESPACE, State.DOCTYPE, exports.TokenType.WHITESPACE],
3905
- [MATCH_DOCTYPE_VALUE, State.DOCTYPE, exports.TokenType.DOCTYPE_VALUE],
3906
- [MATCH_DOCTYPE_CLOSE, State.TEXT, exports.TokenType.DOCTYPE_CLOSE],
3929
+ [MATCH_WHITESPACE, State.DOCTYPE, TokenType.WHITESPACE],
3930
+ [MATCH_DOCTYPE_VALUE, State.DOCTYPE, TokenType.DOCTYPE_VALUE],
3931
+ [MATCH_DOCTYPE_CLOSE, State.TEXT, TokenType.DOCTYPE_CLOSE],
3907
3932
  ], "expected doctype name");
3908
3933
  }
3909
3934
  *tokenizeTag(context) {
@@ -3930,30 +3955,30 @@ class Lexer {
3930
3955
  }
3931
3956
  }
3932
3957
  yield* this.match(context, [
3933
- [MATCH_TAG_CLOSE, nextState, exports.TokenType.TAG_CLOSE],
3934
- [MATCH_ATTR_START, State.ATTR, exports.TokenType.ATTR_NAME],
3935
- [MATCH_WHITESPACE, State.TAG, exports.TokenType.WHITESPACE],
3958
+ [MATCH_TAG_CLOSE, nextState, TokenType.TAG_CLOSE],
3959
+ [MATCH_ATTR_START, State.ATTR, TokenType.ATTR_NAME],
3960
+ [MATCH_WHITESPACE, State.TAG, TokenType.WHITESPACE],
3936
3961
  ], 'expected attribute, ">" or "/>"');
3937
3962
  }
3938
3963
  *tokenizeAttr(context) {
3939
3964
  yield* this.match(context, [
3940
- [MATCH_ATTR_SINGLE, State.TAG, exports.TokenType.ATTR_VALUE],
3941
- [MATCH_ATTR_DOUBLE, State.TAG, exports.TokenType.ATTR_VALUE],
3942
- [MATCH_ATTR_UNQUOTED, State.TAG, exports.TokenType.ATTR_VALUE],
3965
+ [MATCH_ATTR_SINGLE, State.TAG, TokenType.ATTR_VALUE],
3966
+ [MATCH_ATTR_DOUBLE, State.TAG, TokenType.ATTR_VALUE],
3967
+ [MATCH_ATTR_UNQUOTED, State.TAG, TokenType.ATTR_VALUE],
3943
3968
  [false, State.TAG, false],
3944
3969
  ], 'expected attribute, ">" or "/>"');
3945
3970
  }
3946
3971
  *tokenizeText(context) {
3947
3972
  yield* this.match(context, [
3948
- [MATCH_WHITESPACE, State.TEXT, exports.TokenType.WHITESPACE],
3973
+ [MATCH_WHITESPACE, State.TEXT, TokenType.WHITESPACE],
3949
3974
  [MATCH_CDATA_BEGIN, State.CDATA, false],
3950
- [MATCH_DIRECTIVE, State.TEXT, exports.TokenType.DIRECTIVE],
3951
- [MATCH_CONDITIONAL, State.TEXT, exports.TokenType.CONDITIONAL],
3952
- [MATCH_COMMENT, State.TEXT, exports.TokenType.COMMENT],
3953
- [MATCH_TEMPLATING, State.TEXT, exports.TokenType.TEMPLATING],
3954
- [MATCH_TAG_OPEN, State.TAG, exports.TokenType.TAG_OPEN],
3955
- [MATCH_TEXT, State.TEXT, exports.TokenType.TEXT],
3956
- [MATCH_TAG_LOOKAHEAD, State.TEXT, exports.TokenType.TEXT],
3975
+ [MATCH_DIRECTIVE, State.TEXT, TokenType.DIRECTIVE],
3976
+ [MATCH_CONDITIONAL, State.TEXT, TokenType.CONDITIONAL],
3977
+ [MATCH_COMMENT, State.TEXT, TokenType.COMMENT],
3978
+ [MATCH_TEMPLATING, State.TEXT, TokenType.TEMPLATING],
3979
+ [MATCH_TAG_OPEN, State.TAG, TokenType.TAG_OPEN],
3980
+ [MATCH_TEXT, State.TEXT, TokenType.TEXT],
3981
+ [MATCH_TAG_LOOKAHEAD, State.TEXT, TokenType.TEXT],
3957
3982
  ], 'expected text or "<"');
3958
3983
  }
3959
3984
  *tokenizeCDATA(context) {
@@ -3961,21 +3986,21 @@ class Lexer {
3961
3986
  }
3962
3987
  *tokenizeScript(context) {
3963
3988
  yield* this.match(context, [
3964
- [MATCH_SCRIPT_END, State.TAG, exports.TokenType.TAG_OPEN],
3965
- [MATCH_SCRIPT_DATA, State.SCRIPT, exports.TokenType.SCRIPT],
3989
+ [MATCH_SCRIPT_END, State.TAG, TokenType.TAG_OPEN],
3990
+ [MATCH_SCRIPT_DATA, State.SCRIPT, TokenType.SCRIPT],
3966
3991
  ], "expected </script>");
3967
3992
  }
3968
3993
  *tokenizeStyle(context) {
3969
3994
  yield* this.match(context, [
3970
- [MATCH_STYLE_END, State.TAG, exports.TokenType.TAG_OPEN],
3971
- [MATCH_STYLE_DATA, State.STYLE, exports.TokenType.STYLE],
3995
+ [MATCH_STYLE_END, State.TAG, TokenType.TAG_OPEN],
3996
+ [MATCH_STYLE_DATA, State.STYLE, TokenType.STYLE],
3972
3997
  ], "expected </style>");
3973
3998
  }
3974
3999
  }
3975
4000
 
3976
4001
  const whitespace = /(\s+)/;
3977
4002
  function isRelevant$3(event) {
3978
- return event.type === exports.TokenType.ATTR_VALUE;
4003
+ return event.type === TokenType.ATTR_VALUE;
3979
4004
  }
3980
4005
  class AttrDelimiter extends Rule {
3981
4006
  documentation() {
@@ -4179,7 +4204,7 @@ class AttrSpacing extends Rule {
4179
4204
  setup() {
4180
4205
  let previousToken;
4181
4206
  this.on("token", (event) => {
4182
- if (event.type === exports.TokenType.ATTR_NAME && previousToken !== exports.TokenType.WHITESPACE) {
4207
+ if (event.type === TokenType.ATTR_NAME && previousToken !== TokenType.WHITESPACE) {
4183
4208
  this.report(null, "No space between attributes", event.location);
4184
4209
  }
4185
4210
  previousToken = event.type;
@@ -6249,16 +6274,6 @@ const defaults$b = {
6249
6274
  exclude: null,
6250
6275
  allowedProperties: ["display"],
6251
6276
  };
6252
- function getCSSDeclarations(value) {
6253
- return value
6254
- .trim()
6255
- .split(";")
6256
- .filter(Boolean)
6257
- .map((it) => {
6258
- const [property, value] = it.split(":", 2);
6259
- return { property: property.trim(), value: value ? value.trim() : undefined };
6260
- });
6261
- }
6262
6277
  class NoInlineStyle extends Rule {
6263
6278
  constructor(options) {
6264
6279
  super({ ...defaults$b, ...options });
@@ -6339,18 +6354,15 @@ class NoInlineStyle extends Rule {
6339
6354
  return true;
6340
6355
  }
6341
6356
  allPropertiesAllowed(value) {
6342
- if (typeof value !== "string") {
6343
- return false;
6344
- }
6345
6357
  const allowProperties = this.options.allowedProperties;
6346
6358
  /* quick path: no properties are allowed, no need to check each one individually */
6347
6359
  if (allowProperties.length === 0) {
6348
6360
  return false;
6349
6361
  }
6350
- const declarations = getCSSDeclarations(value);
6362
+ const declarations = Object.keys(parseCssDeclaration(value));
6351
6363
  return (declarations.length > 0 &&
6352
6364
  declarations.every((it) => {
6353
- return allowProperties.includes(it.property);
6365
+ return allowProperties.includes(it);
6354
6366
  }));
6355
6367
  }
6356
6368
  }
@@ -6783,7 +6795,7 @@ class NoUtf8Bom extends Rule {
6783
6795
  }
6784
6796
  setup() {
6785
6797
  const unregister = this.on("token", (event) => {
6786
- if (event.type === exports.TokenType.UNICODE_BOM) {
6798
+ if (event.type === TokenType.UNICODE_BOM) {
6787
6799
  this.report(null, "File should be saved without UTF-8 BOM", event.location);
6788
6800
  }
6789
6801
  /* since the BOM must be the very first thing the rule can now be disabled for the rest of the run */
@@ -7175,6 +7187,7 @@ const defaults$5 = {
7175
7187
  { pattern: "-", replacement: "&#8209;", description: "non-breaking hyphen" },
7176
7188
  ],
7177
7189
  ignoreClasses: [],
7190
+ ignoreStyle: true,
7178
7191
  };
7179
7192
  function constructRegex(characters) {
7180
7193
  const disallowed = characters
@@ -7240,6 +7253,9 @@ class TelNonBreaking extends Rule {
7240
7253
  type: "string",
7241
7254
  },
7242
7255
  },
7256
+ ignoreStyle: {
7257
+ type: "boolean",
7258
+ },
7243
7259
  };
7244
7260
  }
7245
7261
  documentation(context) {
@@ -7266,10 +7282,7 @@ class TelNonBreaking extends Rule {
7266
7282
  setup() {
7267
7283
  this.on("element:ready", this.isRelevant, (event) => {
7268
7284
  const { target } = event;
7269
- const { ignoreClasses } = this.options;
7270
- /* skip if element has a class in the ignore list */
7271
- const isIgnored = ignoreClasses.some((it) => target.classList.contains(it));
7272
- if (isIgnored) {
7285
+ if (this.isIgnored(target)) {
7273
7286
  return;
7274
7287
  }
7275
7288
  this.walk(target, target);
@@ -7288,6 +7301,25 @@ class TelNonBreaking extends Rule {
7288
7301
  }
7289
7302
  return true;
7290
7303
  }
7304
+ isIgnoredClass(node) {
7305
+ const { ignoreClasses } = this.options;
7306
+ const { classList } = node;
7307
+ return ignoreClasses.some((it) => classList.contains(it));
7308
+ }
7309
+ isIgnoredStyle(node) {
7310
+ const { ignoreStyle } = this.options;
7311
+ const { style } = node;
7312
+ if (!ignoreStyle) {
7313
+ return false;
7314
+ }
7315
+ if (style["white-space"] === "nowrap" || style["white-space"] === "pre") {
7316
+ return true;
7317
+ }
7318
+ return false;
7319
+ }
7320
+ isIgnored(node) {
7321
+ return this.isIgnoredClass(node) || this.isIgnoredStyle(node);
7322
+ }
7291
7323
  walk(anchor, node) {
7292
7324
  for (const child of node.childNodes) {
7293
7325
  if (isTextNode(child)) {
@@ -10243,7 +10275,7 @@ class Config {
10243
10275
  }
10244
10276
  let filename;
10245
10277
  /* try searching builtin metadata */
10246
- filename = path__default["default"].join(projectRoot, "elements", `${entry}.json`);
10278
+ filename = path__default["default"].join(projectRoot, "elements", `${entry}.js`);
10247
10279
  if (fs__default["default"].existsSync(filename)) {
10248
10280
  metaTable.loadFromFile(filename);
10249
10281
  continue;
@@ -10657,7 +10689,7 @@ class ParserError extends Error {
10657
10689
  }
10658
10690
 
10659
10691
  function isAttrValueToken(token) {
10660
- return Boolean(token && token.type === exports.TokenType.ATTR_VALUE);
10692
+ return Boolean(token && token.type === TokenType.ATTR_VALUE);
10661
10693
  }
10662
10694
  function svgShouldRetainTag(foreignTagName, tagName) {
10663
10695
  return foreignTagName === "svg" && ["title", "desc"].includes(tagName);
@@ -10765,43 +10797,43 @@ class Parser {
10765
10797
  /* eslint-disable-next-line complexity */
10766
10798
  consume(source, token, tokenStream) {
10767
10799
  switch (token.type) {
10768
- case exports.TokenType.UNICODE_BOM:
10800
+ case TokenType.UNICODE_BOM:
10769
10801
  /* ignore */
10770
10802
  break;
10771
- case exports.TokenType.TAG_OPEN:
10803
+ case TokenType.TAG_OPEN:
10772
10804
  this.consumeTag(source, token, tokenStream);
10773
10805
  break;
10774
- case exports.TokenType.WHITESPACE:
10806
+ case TokenType.WHITESPACE:
10775
10807
  this.trigger("whitespace", {
10776
10808
  text: token.data[0],
10777
10809
  location: token.location,
10778
10810
  });
10779
10811
  this.appendText(token.data[0], token.location);
10780
10812
  break;
10781
- case exports.TokenType.DIRECTIVE:
10813
+ case TokenType.DIRECTIVE:
10782
10814
  this.consumeDirective(token);
10783
10815
  break;
10784
- case exports.TokenType.CONDITIONAL:
10816
+ case TokenType.CONDITIONAL:
10785
10817
  this.consumeConditional(token);
10786
10818
  break;
10787
- case exports.TokenType.COMMENT:
10819
+ case TokenType.COMMENT:
10788
10820
  this.consumeComment(token);
10789
10821
  break;
10790
- case exports.TokenType.DOCTYPE_OPEN:
10822
+ case TokenType.DOCTYPE_OPEN:
10791
10823
  this.consumeDoctype(token, tokenStream);
10792
10824
  break;
10793
- case exports.TokenType.TEXT:
10794
- case exports.TokenType.TEMPLATING:
10825
+ case TokenType.TEXT:
10826
+ case TokenType.TEMPLATING:
10795
10827
  this.appendText(token.data[0], token.location);
10796
10828
  break;
10797
- case exports.TokenType.EOF:
10829
+ case TokenType.EOF:
10798
10830
  this.closeTree(source, token.location);
10799
10831
  break;
10800
10832
  }
10801
10833
  }
10802
10834
  /* eslint-disable-next-line complexity, sonarjs/cognitive-complexity */
10803
10835
  consumeTag(source, startToken, tokenStream) {
10804
- const tokens = Array.from(this.consumeUntil(tokenStream, exports.TokenType.TAG_CLOSE, startToken.location));
10836
+ const tokens = Array.from(this.consumeUntil(tokenStream, TokenType.TAG_CLOSE, startToken.location));
10805
10837
  const endToken = tokens.slice(-1)[0];
10806
10838
  const closeOptional = this.closeOptional(startToken);
10807
10839
  const parent = closeOptional ? this.dom.getActive().parent : this.dom.getActive();
@@ -10827,9 +10859,9 @@ class Parser {
10827
10859
  for (let i = 0; i < tokens.length; i++) {
10828
10860
  const token = tokens[i];
10829
10861
  switch (token.type) {
10830
- case exports.TokenType.WHITESPACE:
10862
+ case TokenType.WHITESPACE:
10831
10863
  break;
10832
- case exports.TokenType.ATTR_NAME:
10864
+ case TokenType.ATTR_NAME:
10833
10865
  this.consumeAttribute(source, node, token, tokens[i + 1]);
10834
10866
  break;
10835
10867
  }
@@ -10907,7 +10939,7 @@ class Parser {
10907
10939
  let endToken;
10908
10940
  do {
10909
10941
  /* search for tags */
10910
- const tokens = Array.from(this.consumeUntil(tokenStream, exports.TokenType.TAG_OPEN, errorLocation));
10942
+ const tokens = Array.from(this.consumeUntil(tokenStream, TokenType.TAG_OPEN, errorLocation));
10911
10943
  const [last] = tokens.slice(-1);
10912
10944
  const [, tagClosed, tagName] = last.data;
10913
10945
  /* special case: svg <title> and <desc> should be intact as it affects accessibility */
@@ -10924,7 +10956,7 @@ class Parser {
10924
10956
  continue;
10925
10957
  }
10926
10958
  /* locate end token and determine if this is a self-closed tag */
10927
- const endTokens = Array.from(this.consumeUntil(tokenStream, exports.TokenType.TAG_CLOSE, last.location));
10959
+ const endTokens = Array.from(this.consumeUntil(tokenStream, TokenType.TAG_CLOSE, last.location));
10928
10960
  endToken = endTokens.slice(-1)[0];
10929
10961
  const selfClosed = endToken.data[0] === "/>";
10930
10962
  /* since foreign element may be nested keep a count for the number of
@@ -11010,7 +11042,7 @@ class Parser {
11010
11042
  * ^^^ ^^^ ^^^ (null) (null)
11011
11043
  */
11012
11044
  getAttributeValueLocation(token) {
11013
- if (!token || token.type !== exports.TokenType.ATTR_VALUE || token.data[2] === "") {
11045
+ if (!token || token.type !== TokenType.ATTR_VALUE || token.data[2] === "") {
11014
11046
  return null;
11015
11047
  }
11016
11048
  const quote = token.data[3];
@@ -11028,7 +11060,7 @@ class Parser {
11028
11060
  getAttributeLocation(key, value) {
11029
11061
  var _a;
11030
11062
  const begin = key.location;
11031
- const end = value && value.type === exports.TokenType.ATTR_VALUE ? value.location : undefined;
11063
+ const end = value && value.type === TokenType.ATTR_VALUE ? value.location : undefined;
11032
11064
  return {
11033
11065
  filename: begin.filename,
11034
11066
  line: begin.line,
@@ -11089,7 +11121,7 @@ class Parser {
11089
11121
  * Consumes doctype tokens. Emits doctype event.
11090
11122
  */
11091
11123
  consumeDoctype(startToken, tokenStream) {
11092
- const tokens = Array.from(this.consumeUntil(tokenStream, exports.TokenType.DOCTYPE_CLOSE, startToken.location));
11124
+ const tokens = Array.from(this.consumeUntil(tokenStream, TokenType.DOCTYPE_CLOSE, startToken.location));
11093
11125
  /* first token is the doctype, second is the closing ">" */
11094
11126
  const doctype = tokens[0];
11095
11127
  const value = doctype.data[0];
@@ -11115,7 +11147,7 @@ class Parser {
11115
11147
  return;
11116
11148
  it = this.next(tokenStream);
11117
11149
  }
11118
- throw new ParserError(errorLocation, `stream ended before ${exports.TokenType[search]} token was found`);
11150
+ throw new ParserError(errorLocation, `stream ended before ${TokenType[search]} token was found`);
11119
11151
  }
11120
11152
  /**
11121
11153
  * Consumes tokens until a matching close-tag is found. Tags are appended to
@@ -11129,7 +11161,7 @@ class Parser {
11129
11161
  while (!it.done) {
11130
11162
  const token = it.value;
11131
11163
  this.consume(source, token, tokenStream);
11132
- if (token.type === exports.TokenType.TAG_OPEN) {
11164
+ if (token.type === TokenType.TAG_OPEN) {
11133
11165
  const [, close, tagName] = token.data;
11134
11166
  if (tagName === searchTag) {
11135
11167
  if (close) {
@@ -11202,6 +11234,12 @@ class Parser {
11202
11234
  }
11203
11235
  }
11204
11236
 
11237
+ function freeze(src) {
11238
+ return {
11239
+ ...src,
11240
+ selector: src.selector(),
11241
+ };
11242
+ }
11205
11243
  /**
11206
11244
  * @internal
11207
11245
  */
@@ -11253,7 +11291,9 @@ class Reporter {
11253
11291
  line: location.line,
11254
11292
  column: location.column,
11255
11293
  size: location.size || 0,
11256
- selector: node ? node.generateSelector() : null,
11294
+ selector() {
11295
+ return node ? node.generateSelector() : null;
11296
+ },
11257
11297
  context,
11258
11298
  });
11259
11299
  }
@@ -11267,7 +11307,7 @@ class Reporter {
11267
11307
  const report = {
11268
11308
  valid: this.isValid(),
11269
11309
  results: Object.keys(this.result).map((filePath) => {
11270
- const messages = Array.from(this.result[filePath]).sort(messageSort);
11310
+ const messages = Array.from(this.result[filePath], freeze).sort(messageSort);
11271
11311
  const source = (sources || []).find((source) => { var _a; return filePath === ((_a = source.filename) !== null && _a !== void 0 ? _a : ""); });
11272
11312
  return {
11273
11313
  filePath,
@@ -11420,7 +11460,7 @@ class Engine {
11420
11460
  for (const token of lexer.tokenize(src)) {
11421
11461
  const data = (_a = token.data[0]) !== null && _a !== void 0 ? _a : "";
11422
11462
  lines.push({
11423
- token: exports.TokenType[token.type],
11463
+ token: TokenType[token.type],
11424
11464
  data,
11425
11465
  location: `${token.location.filename}:${token.location.line}:${token.location.column}`,
11426
11466
  });
@@ -11669,7 +11709,7 @@ class Engine {
11669
11709
  line: location.line,
11670
11710
  column: location.column,
11671
11711
  size: location.size || 0,
11672
- selector: null,
11712
+ selector: () => null,
11673
11713
  });
11674
11714
  }
11675
11715
  }
@@ -12192,6 +12232,7 @@ const formatter$4 = checkstyleFormatter;
12192
12232
  const defaults = {
12193
12233
  showLink: true,
12194
12234
  showSummary: true,
12235
+ showSelector: false,
12195
12236
  };
12196
12237
  /**
12197
12238
  * Codeframe formatter based on ESLint codeframe.
@@ -12247,6 +12288,7 @@ function getEndLocation(message, source) {
12247
12288
  * @returns The formatted output.
12248
12289
  */
12249
12290
  function formatMessage(message, parentResult, options) {
12291
+ var _a;
12250
12292
  const type = message.severity === 2 ? kleur__default["default"].red("error") : kleur__default["default"].yellow("warning");
12251
12293
  const msg = `${kleur__default["default"].bold(message.message.replace(/([^ ])\.$/, "$1"))}`;
12252
12294
  const ruleId = kleur__default["default"].dim(`(${message.ruleId})`);
@@ -12269,6 +12311,9 @@ function formatMessage(message, parentResult, options) {
12269
12311
  end: getEndLocation(message, sourceCode),
12270
12312
  }, { highlightCode: false }));
12271
12313
  }
12314
+ if (options.showSelector) {
12315
+ result.push(`${kleur__default["default"].bold("Selector:")} ${(_a = message.selector) !== null && _a !== void 0 ? _a : "-"}`);
12316
+ }
12272
12317
  if (options.showLink && message.ruleUrl) {
12273
12318
  result.push(`${kleur__default["default"].bold("Details:")} ${message.ruleUrl}`);
12274
12319
  }
@@ -12410,6 +12455,7 @@ exports.TemplateExtractor = TemplateExtractor;
12410
12455
  exports.TextNode = TextNode;
12411
12456
  exports.UserError = UserError;
12412
12457
  exports.bugs = bugs;
12458
+ exports.codeframe = codeframe;
12413
12459
  exports.compatibilityCheck = compatibilityCheck;
12414
12460
  exports.getFormatter = getFormatter;
12415
12461
  exports.legacyRequire = legacyRequire;