html-validate 9.4.1 → 9.4.2

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
@@ -1944,15 +1944,15 @@ function nthChild(node, args) {
1944
1944
  return cur === n;
1945
1945
  }
1946
1946
 
1947
- function scope(node) {
1948
- return node.isSameNode(this.scope);
1947
+ function scope$1(node) {
1948
+ return Boolean(this.scope && node.isSameNode(this.scope));
1949
1949
  }
1950
1950
 
1951
1951
  const table = {
1952
1952
  "first-child": firstChild,
1953
1953
  "last-child": lastChild,
1954
1954
  "nth-child": nthChild,
1955
- scope
1955
+ scope: scope$1
1956
1956
  };
1957
1957
  function factory(name, context) {
1958
1958
  const fn = table[name];
@@ -1963,139 +1963,12 @@ function factory(name, context) {
1963
1963
  }
1964
1964
  }
1965
1965
 
1966
- const escapedCodepoints = ["9", "a", "d"];
1967
- function* splitSelectorElements(selector) {
1968
- let begin = 0;
1969
- let end = 0;
1970
- function initialState(ch, p) {
1971
- if (ch === "\\") {
1972
- return 1 /* ESCAPED */;
1973
- }
1974
- if (ch === " ") {
1975
- end = p;
1976
- return 2 /* WHITESPACE */;
1977
- }
1978
- return 0 /* INITIAL */;
1979
- }
1980
- function escapedState(ch) {
1981
- if (escapedCodepoints.includes(ch)) {
1982
- return 1 /* ESCAPED */;
1983
- }
1984
- return 0 /* INITIAL */;
1985
- }
1986
- function* whitespaceState(ch, p) {
1987
- if (ch === " ") {
1988
- return 2 /* WHITESPACE */;
1989
- }
1990
- yield selector.slice(begin, end);
1991
- begin = p;
1992
- end = p;
1993
- return 0 /* INITIAL */;
1994
- }
1995
- let state = 0 /* INITIAL */;
1996
- for (let p = 0; p < selector.length; p++) {
1997
- const ch = selector[p];
1998
- switch (state) {
1999
- case 0 /* INITIAL */:
2000
- state = initialState(ch, p);
2001
- break;
2002
- case 1 /* ESCAPED */:
2003
- state = escapedState(ch);
2004
- break;
2005
- case 2 /* WHITESPACE */:
2006
- state = yield* whitespaceState(ch, p);
2007
- break;
2008
- }
2009
- }
2010
- if (begin !== selector.length) {
2011
- yield selector.slice(begin);
2012
- }
2013
- }
2014
-
2015
1966
  function stripslashes(value) {
2016
1967
  return value.replace(/\\(.)/g, "$1");
2017
1968
  }
2018
- function unescapeCodepoint(value) {
2019
- const replacement = {
2020
- "\\9 ": " ",
2021
- "\\a ": "\n",
2022
- "\\d ": "\r"
2023
- };
2024
- return value.replace(
2025
- /(\\[\u0039\u0061\u0064] )/g,
2026
- (_, codepoint) => replacement[codepoint]
2027
- );
1969
+ class Condition {
2028
1970
  }
2029
- function escapeSelectorComponent(text) {
2030
- const codepoints = {
2031
- " ": "\\9 ",
2032
- "\n": "\\a ",
2033
- "\r": "\\d "
2034
- };
2035
- return text.toString().replace(/([\t\n\r]|[^a-z0-9_-])/gi, (_, ch) => {
2036
- if (codepoints[ch]) {
2037
- return codepoints[ch];
2038
- } else {
2039
- return `\\${ch}`;
2040
- }
2041
- });
2042
- }
2043
- function generateIdSelector(id) {
2044
- const escaped = escapeSelectorComponent(id);
2045
- return escaped.match(/^\d/) ? `[id="${escaped}"]` : `#${escaped}`;
2046
- }
2047
- function isDelimiter(ch) {
2048
- return /[.#[:]/.test(ch);
2049
- }
2050
- function isQuotationMark(ch) {
2051
- return /['"]/.test(ch);
2052
- }
2053
- function isPseudoElement(ch, buffer) {
2054
- return ch === ":" && buffer === ":";
2055
- }
2056
- function* splitPattern(pattern) {
2057
- if (pattern === "") {
2058
- return;
2059
- }
2060
- const end = pattern.length;
2061
- let begin = 0;
2062
- let cur = 1;
2063
- let quoted = false;
2064
- while (cur < end) {
2065
- const ch = pattern[cur];
2066
- const buffer = pattern.slice(begin, cur);
2067
- if (ch === "\\") {
2068
- cur += 2;
2069
- continue;
2070
- }
2071
- if (quoted) {
2072
- if (ch === quoted) {
2073
- quoted = false;
2074
- }
2075
- cur += 1;
2076
- continue;
2077
- }
2078
- if (isQuotationMark(ch)) {
2079
- quoted = ch;
2080
- cur += 1;
2081
- continue;
2082
- }
2083
- if (isPseudoElement(ch, buffer)) {
2084
- cur += 1;
2085
- continue;
2086
- }
2087
- if (isDelimiter(ch)) {
2088
- begin = cur;
2089
- yield buffer;
2090
- }
2091
- cur += 1;
2092
- }
2093
- const tail = pattern.slice(begin, cur);
2094
- yield tail;
2095
- }
2096
- class Matcher {
2097
- }
2098
- class ClassMatcher extends Matcher {
1971
+ class ClassCondition extends Condition {
2099
1972
  classname;
2100
1973
  constructor(classname) {
2101
1974
  super();
@@ -2105,7 +1978,7 @@ class ClassMatcher extends Matcher {
2105
1978
  return node.classList.contains(this.classname);
2106
1979
  }
2107
1980
  }
2108
- class IdMatcher extends Matcher {
1981
+ class IdCondition extends Condition {
2109
1982
  id;
2110
1983
  constructor(id) {
2111
1984
  super();
@@ -2115,7 +1988,7 @@ class IdMatcher extends Matcher {
2115
1988
  return node.id === this.id;
2116
1989
  }
2117
1990
  }
2118
- class AttrMatcher extends Matcher {
1991
+ class AttributeCondition extends Condition {
2119
1992
  key;
2120
1993
  op;
2121
1994
  value;
@@ -2141,7 +2014,7 @@ class AttrMatcher extends Matcher {
2141
2014
  });
2142
2015
  }
2143
2016
  }
2144
- class PseudoClassMatcher extends Matcher {
2017
+ class PseudoClassCondition extends Condition {
2145
2018
  name;
2146
2019
  args;
2147
2020
  constructor(pseudoclass, context) {
@@ -2159,11 +2032,62 @@ class PseudoClassMatcher extends Matcher {
2159
2032
  return fn(node, this.args);
2160
2033
  }
2161
2034
  }
2162
- class Pattern {
2035
+
2036
+ function isDelimiter(ch) {
2037
+ return /[.#[:]/.test(ch);
2038
+ }
2039
+ function isQuotationMark(ch) {
2040
+ return /['"]/.test(ch);
2041
+ }
2042
+ function isPseudoElement(ch, buffer) {
2043
+ return ch === ":" && buffer === ":";
2044
+ }
2045
+ function* splitCompound(pattern) {
2046
+ if (pattern === "") {
2047
+ return;
2048
+ }
2049
+ const end = pattern.length;
2050
+ let begin = 0;
2051
+ let cur = 1;
2052
+ let quoted = false;
2053
+ while (cur < end) {
2054
+ const ch = pattern[cur];
2055
+ const buffer = pattern.slice(begin, cur);
2056
+ if (ch === "\\") {
2057
+ cur += 2;
2058
+ continue;
2059
+ }
2060
+ if (quoted) {
2061
+ if (ch === quoted) {
2062
+ quoted = false;
2063
+ }
2064
+ cur += 1;
2065
+ continue;
2066
+ }
2067
+ if (isQuotationMark(ch)) {
2068
+ quoted = ch;
2069
+ cur += 1;
2070
+ continue;
2071
+ }
2072
+ if (isPseudoElement(ch, buffer)) {
2073
+ cur += 1;
2074
+ continue;
2075
+ }
2076
+ if (isDelimiter(ch)) {
2077
+ begin = cur;
2078
+ yield buffer;
2079
+ }
2080
+ cur += 1;
2081
+ }
2082
+ const tail = pattern.slice(begin, cur);
2083
+ yield tail;
2084
+ }
2085
+
2086
+ class Compound {
2163
2087
  combinator;
2164
2088
  tagName;
2165
2089
  selector;
2166
- pattern;
2090
+ conditions;
2167
2091
  constructor(pattern) {
2168
2092
  const match = pattern.match(/^([~+\->]?)((?:[*]|[^.#[:]+)?)([^]*)$/);
2169
2093
  if (!match) {
@@ -2173,25 +2097,166 @@ class Pattern {
2173
2097
  this.selector = pattern;
2174
2098
  this.combinator = parseCombinator(match.shift(), pattern);
2175
2099
  this.tagName = match.shift() || "*";
2176
- this.pattern = Array.from(splitPattern(match[0]), (it) => this.createMatcher(it));
2100
+ this.conditions = Array.from(splitCompound(match[0]), (it) => this.createCondition(it));
2177
2101
  }
2178
2102
  match(node, context) {
2179
- return node.is(this.tagName) && this.pattern.every((cur) => cur.match(node, context));
2103
+ return node.is(this.tagName) && this.conditions.every((cur) => cur.match(node, context));
2180
2104
  }
2181
- createMatcher(pattern) {
2105
+ createCondition(pattern) {
2182
2106
  switch (pattern[0]) {
2183
2107
  case ".":
2184
- return new ClassMatcher(pattern.slice(1));
2108
+ return new ClassCondition(pattern.slice(1));
2185
2109
  case "#":
2186
- return new IdMatcher(pattern.slice(1));
2110
+ return new IdCondition(pattern.slice(1));
2187
2111
  case "[":
2188
- return new AttrMatcher(pattern.slice(1, -1));
2112
+ return new AttributeCondition(pattern.slice(1, -1));
2189
2113
  case ":":
2190
- return new PseudoClassMatcher(pattern.slice(1), this.selector);
2114
+ return new PseudoClassCondition(pattern.slice(1), this.selector);
2191
2115
  default:
2192
- throw new Error(`Failed to create matcher for "${pattern}"`);
2116
+ throw new Error(`Failed to create selector condition for "${pattern}"`);
2117
+ }
2118
+ }
2119
+ }
2120
+
2121
+ function* ancestors$1(element) {
2122
+ let current = element.parent;
2123
+ while (current && !current.isRootElement()) {
2124
+ yield current;
2125
+ current = current.parent;
2126
+ }
2127
+ }
2128
+ function* parent(element) {
2129
+ const parent2 = element.parent;
2130
+ if (parent2 && !parent2.isRootElement()) {
2131
+ yield parent2;
2132
+ }
2133
+ }
2134
+ function* adjacentSibling(element) {
2135
+ const sibling = element.previousSibling;
2136
+ if (sibling) {
2137
+ yield sibling;
2138
+ }
2139
+ }
2140
+ function* generalSibling(element) {
2141
+ const siblings = element.siblings;
2142
+ const index = siblings.findIndex((it) => it.isSameNode(element));
2143
+ for (let i = 0; i < index; i++) {
2144
+ yield siblings[i];
2145
+ }
2146
+ }
2147
+ function* scope(element) {
2148
+ yield element;
2149
+ }
2150
+ function candidatesFromCombinator(element, combinator) {
2151
+ switch (combinator) {
2152
+ case Combinator.DESCENDANT:
2153
+ return ancestors$1(element);
2154
+ case Combinator.CHILD:
2155
+ return parent(element);
2156
+ case Combinator.ADJACENT_SIBLING:
2157
+ return adjacentSibling(element);
2158
+ case Combinator.GENERAL_SIBLING:
2159
+ return generalSibling(element);
2160
+ /* istanbul ignore next -- cannot really happen, the selector would be malformed */
2161
+ case Combinator.SCOPE:
2162
+ return scope(element);
2163
+ }
2164
+ }
2165
+ function matchElement(element, compounds, context) {
2166
+ const last = compounds[compounds.length - 1];
2167
+ if (!last.match(element, context)) {
2168
+ return false;
2169
+ }
2170
+ const remainder = compounds.slice(0, -1);
2171
+ if (remainder.length === 0) {
2172
+ return true;
2173
+ }
2174
+ const candidates = candidatesFromCombinator(element, last.combinator);
2175
+ for (const candidate of candidates) {
2176
+ if (matchElement(candidate, remainder, context)) {
2177
+ return true;
2178
+ }
2179
+ }
2180
+ return false;
2181
+ }
2182
+
2183
+ const escapedCodepoints = ["9", "a", "d"];
2184
+ function* splitSelectorElements(selector) {
2185
+ let begin = 0;
2186
+ let end = 0;
2187
+ function initialState(ch, p) {
2188
+ if (ch === "\\") {
2189
+ return 1 /* ESCAPED */;
2190
+ }
2191
+ if (ch === " ") {
2192
+ end = p;
2193
+ return 2 /* WHITESPACE */;
2194
+ }
2195
+ return 0 /* INITIAL */;
2196
+ }
2197
+ function escapedState(ch) {
2198
+ if (escapedCodepoints.includes(ch)) {
2199
+ return 1 /* ESCAPED */;
2200
+ }
2201
+ return 0 /* INITIAL */;
2202
+ }
2203
+ function* whitespaceState(ch, p) {
2204
+ if (ch === " ") {
2205
+ return 2 /* WHITESPACE */;
2206
+ }
2207
+ yield selector.slice(begin, end);
2208
+ begin = p;
2209
+ end = p;
2210
+ return 0 /* INITIAL */;
2211
+ }
2212
+ let state = 0 /* INITIAL */;
2213
+ for (let p = 0; p < selector.length; p++) {
2214
+ const ch = selector[p];
2215
+ switch (state) {
2216
+ case 0 /* INITIAL */:
2217
+ state = initialState(ch, p);
2218
+ break;
2219
+ case 1 /* ESCAPED */:
2220
+ state = escapedState(ch);
2221
+ break;
2222
+ case 2 /* WHITESPACE */:
2223
+ state = yield* whitespaceState(ch, p);
2224
+ break;
2193
2225
  }
2194
2226
  }
2227
+ if (begin !== selector.length) {
2228
+ yield selector.slice(begin);
2229
+ }
2230
+ }
2231
+
2232
+ function unescapeCodepoint(value) {
2233
+ const replacement = {
2234
+ "\\9 ": " ",
2235
+ "\\a ": "\n",
2236
+ "\\d ": "\r"
2237
+ };
2238
+ return value.replace(
2239
+ /(\\[\u0039\u0061\u0064] )/g,
2240
+ (_, codepoint) => replacement[codepoint]
2241
+ );
2242
+ }
2243
+ function escapeSelectorComponent(text) {
2244
+ const codepoints = {
2245
+ " ": "\\9 ",
2246
+ "\n": "\\a ",
2247
+ "\r": "\\d "
2248
+ };
2249
+ return text.toString().replace(/([\t\n\r]|[^a-z0-9_-])/gi, (_, ch) => {
2250
+ if (codepoints[ch]) {
2251
+ return codepoints[ch];
2252
+ } else {
2253
+ return `\\${ch}`;
2254
+ }
2255
+ });
2256
+ }
2257
+ function generateIdSelector(id) {
2258
+ const escaped = escapeSelectorComponent(id);
2259
+ return escaped.match(/^\d/) ? `[id="${escaped}"]` : `#${escaped}`;
2195
2260
  }
2196
2261
  class Selector {
2197
2262
  pattern;
@@ -2208,6 +2273,13 @@ class Selector {
2208
2273
  const context = { scope: root };
2209
2274
  yield* this.matchInternal(root, 0, context);
2210
2275
  }
2276
+ /**
2277
+ * Returns `true` if the element matches this selector.
2278
+ */
2279
+ matchElement(element) {
2280
+ const context = { scope: null };
2281
+ return matchElement(element, this.pattern, context);
2282
+ }
2211
2283
  *matchInternal(root, level, context) {
2212
2284
  if (level >= this.pattern.length) {
2213
2285
  yield root;
@@ -2225,7 +2297,7 @@ class Selector {
2225
2297
  static parse(selector) {
2226
2298
  selector = selector.replace(/([+~>]) /g, "$1");
2227
2299
  return Array.from(splitSelectorElements(selector), (element) => {
2228
- return new Pattern(unescapeCodepoint(element));
2300
+ return new Compound(unescapeCodepoint(element));
2229
2301
  });
2230
2302
  }
2231
2303
  static findCandidates(root, pattern) {
@@ -2241,7 +2313,6 @@ class Selector {
2241
2313
  case Combinator.SCOPE:
2242
2314
  return [root];
2243
2315
  }
2244
- return [];
2245
2316
  }
2246
2317
  static findAdjacentSibling(node) {
2247
2318
  let adjacent = false;
@@ -2577,17 +2648,11 @@ class HtmlElement extends DOMNode {
2577
2648
  *
2578
2649
  * Implementation of DOM specification of Element.matches(selectors).
2579
2650
  */
2580
- matches(selector) {
2581
- let root = this;
2582
- while (root.parent) {
2583
- root = root.parent;
2584
- }
2585
- for (const match of root.querySelectorAll(selector)) {
2586
- if (match.unique === this.unique) {
2587
- return true;
2588
- }
2589
- }
2590
- return false;
2651
+ matches(selectorList) {
2652
+ return selectorList.split(",").some((it) => {
2653
+ const selector = new Selector(it.trim());
2654
+ return selector.matchElement(this);
2655
+ });
2591
2656
  }
2592
2657
  get meta() {
2593
2658
  return this.metaElement;
@@ -6027,7 +6092,7 @@ class ElementPermittedContent extends Rule {
6027
6092
  }
6028
6093
  validatePermittedDescendant(node, parent) {
6029
6094
  for (let cur = parent; cur && !cur.isRootElement(); cur = /* istanbul ignore next */
6030
- cur?.parent ?? null) {
6095
+ cur.parent ?? null) {
6031
6096
  const meta = cur.meta;
6032
6097
  if (!meta) {
6033
6098
  continue;
@@ -6635,7 +6700,7 @@ class HeadingLevel extends Rule {
6635
6700
  constructor(options) {
6636
6701
  super({ ...defaults$j, ...options });
6637
6702
  this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
6638
- this.sectionRoots = this.options.sectioningRoots.map((it) => new Pattern(it));
6703
+ this.sectionRoots = this.options.sectioningRoots.map((it) => new Compound(it));
6639
6704
  this.stack.push({
6640
6705
  node: null,
6641
6706
  current: 0,
@@ -11652,7 +11717,7 @@ class EventHandler {
11652
11717
  }
11653
11718
 
11654
11719
  const name = "html-validate";
11655
- const version = "9.4.1";
11720
+ const version = "9.4.2";
11656
11721
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
11657
11722
 
11658
11723
  function freeze(src) {