@reteps/tree-sitter-htmlmustache 0.9.0 → 0.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/browser/out/browser/index.mjs +201 -67
- package/browser/out/browser/index.mjs.map +3 -3
- package/browser/out/core/selectorMatcher.d.ts +19 -6
- package/browser/out/core/selectorMatcher.d.ts.map +1 -1
- package/cli/out/main.js +200 -66
- package/package.json +1 -1
- package/src/core/selectorMatcher.ts +272 -72
|
@@ -10,14 +10,21 @@
|
|
|
10
10
|
* Supported user-facing syntax:
|
|
11
11
|
* - Tag names (`div`), universal (`*`), classes (`.foo`), ids (`#foo`)
|
|
12
12
|
* - Attributes: `[attr]`, `[attr=v]`, `[attr^=v]`, `[attr*=v]`, `[attr$=v]`, `[attr~=v]`
|
|
13
|
-
* - Descendant (space)
|
|
13
|
+
* - Descendant (space), child (`>`), adjacent-sibling (`+`), and
|
|
14
|
+
* general-sibling (`~`) combinators. Sibling combinators skip over text /
|
|
15
|
+
* whitespace nodes (CSS semantics) and work across HTML and Mustache
|
|
16
|
+
* constructs: e.g. `label + input`, `{{foo}} + p`, `h2 ~ {{#items}}`.
|
|
14
17
|
* - Mustache variables: `{{path}}` and `{{{path}}}` (raw)
|
|
15
18
|
* - Mustache sections: `{{#name}}` and `{{^name}}` (inverted)
|
|
16
19
|
* - Mustache comments: `{{!content}}`
|
|
17
20
|
* - Mustache partials: `{{>name}}`
|
|
18
21
|
* - Glob wildcard `*` inside the argument: `{{options.*}}`, `{{*.deprecated}}`, `{{*}}`
|
|
19
22
|
* - `:has(selector)` — element has a matching descendant
|
|
20
|
-
* - `:not(...)`
|
|
23
|
+
* - `:not(...)` — negation. Accepts attributes/class/id/`:has` (folded into
|
|
24
|
+
* the outer compound), plus any other selector (including Mustache
|
|
25
|
+
* literals and type selectors) as a whole-selector check against the
|
|
26
|
+
* node itself. Example: `{{*}}:not({{internal.*}})` matches any
|
|
27
|
+
* interpolation whose path does not start with `internal.`.
|
|
21
28
|
* - `:root` — the tree-sitter fragment root (the whole document). Unlike
|
|
22
29
|
* browser CSS where `:root` matches `<html>`, this matches the parse-tree
|
|
23
30
|
* root so it works on partials/fragments too. Useful as a document-scoped
|
|
@@ -26,15 +33,19 @@
|
|
|
26
33
|
* `pl-answer-panel` is. Cannot combine with tag/class/id/attribute in the
|
|
27
34
|
* same compound (only with `:has` / `:not(:has(...))`). Inside `:has(...)`,
|
|
28
35
|
* `:root` refers to the element being checked, not the document.
|
|
36
|
+
* - `:is(a, b, ...)` — matches if any alternative matches. Expanded at parse
|
|
37
|
+
* time into the Cartesian product of alternatives, so `:is(a, b) :is(c, d)`
|
|
38
|
+
* is equivalent to `a c, a d, b c, b d`. Alternatives inside `:is` that
|
|
39
|
+
* contain combinators are only allowed when the `:is(...)` stands alone in
|
|
40
|
+
* its compound (e.g. `:is(div > span, p)` works; `x:is(div > span, p)`
|
|
41
|
+
* does not, since a combinator can't be merged into another compound).
|
|
29
42
|
* - Comma-separated alternatives
|
|
30
43
|
*
|
|
31
44
|
* Unsupported (parseSelector returns null, rule is skipped):
|
|
32
|
-
* - Sibling combinators (`+`, `~`)
|
|
33
45
|
* - `[attr|=v]`, case-insensitive `i` flag
|
|
34
46
|
* - Mixed HTML + Mustache kinds in one compound (e.g. `img{{foo}}`)
|
|
35
47
|
* - `{{/end}}` (end tags aren't standalone nodes)
|
|
36
48
|
* - `{{=<% %>=}}` (delimiter changes aren't grammar-tracked)
|
|
37
|
-
* - Mustache literals inside `:not(...)` (only attribute/class/id/:has)
|
|
38
49
|
*/
|
|
39
50
|
import type { BalanceNode } from './htmlBalanceChecker.js';
|
|
40
51
|
export type AttributeOperator = '=' | '^=' | '*=' | '$=' | '~=';
|
|
@@ -49,6 +60,7 @@ export interface DescendantCheck {
|
|
|
49
60
|
selector: ParsedSelector;
|
|
50
61
|
negated: boolean;
|
|
51
62
|
}
|
|
63
|
+
export type Combinator = 'descendant' | 'child' | 'adjacent-sibling' | 'general-sibling';
|
|
52
64
|
export interface Segment {
|
|
53
65
|
kind: SegmentKind;
|
|
54
66
|
rootOnly: boolean;
|
|
@@ -56,7 +68,8 @@ export interface Segment {
|
|
|
56
68
|
pathRegex?: RegExp;
|
|
57
69
|
attributes: AttributeConstraint[];
|
|
58
70
|
descendantChecks: DescendantCheck[];
|
|
59
|
-
|
|
71
|
+
selfNegations: ParsedSelector[];
|
|
72
|
+
combinator: Combinator;
|
|
60
73
|
}
|
|
61
74
|
/** A parsed selector is a list of alternatives (from comma-separated parts). */
|
|
62
75
|
export type ParsedSelector = Segment[][];
|
|
@@ -70,5 +83,5 @@ export type ParsedSelector = Segment[][];
|
|
|
70
83
|
*/
|
|
71
84
|
export declare function preprocessMustacheLiterals(raw: string): string | null;
|
|
72
85
|
export declare function parseSelector(raw: string): ParsedSelector | null;
|
|
73
|
-
export declare function matchSelector(rootNode: BalanceNode, selector: ParsedSelector): BalanceNode[];
|
|
86
|
+
export declare function matchSelector(rootNode: BalanceNode, selector: ParsedSelector, siblings?: BalanceNode[], indexInSiblings?: number): BalanceNode[];
|
|
74
87
|
//# sourceMappingURL=selectorMatcher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selectorMatcher.d.ts","sourceRoot":"","sources":["../../../src/core/selectorMatcher.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"selectorMatcher.d.ts","sourceRoot":"","sources":["../../../src/core/selectorMatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAY3D,MAAM,MAAM,iBAAiB,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhE,MAAM,MAAM,WAAW,GACnB,MAAM,GACN,SAAS,GACT,UAAU,GACV,UAAU,GACV,KAAK,GACL,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,iBAAiB,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,OAAO,GAAG,kBAAkB,GAAG,iBAAiB,CAAC;AAEzF,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,aAAa,EAAE,cAAc,EAAE,CAAC;IAChC,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,gFAAgF;AAChF,MAAM,MAAM,cAAc,GAAG,OAAO,EAAE,EAAE,CAAC;AAQzC;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuFrE;AAID,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CA2BhE;AA2pBD,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,WAAW,EACrB,QAAQ,EAAE,cAAc,EACxB,QAAQ,GAAE,WAAW,EAAO,EAC5B,eAAe,SAAI,GAClB,WAAW,EAAE,CAYf"}
|
package/cli/out/main.js
CHANGED
|
@@ -1939,13 +1939,85 @@ function parseSelector(raw) {
|
|
|
1939
1939
|
const tops = ast.type === "list" ? ast.list : [ast];
|
|
1940
1940
|
const alts = [];
|
|
1941
1941
|
for (const top of tops) {
|
|
1942
|
-
const
|
|
1943
|
-
if (
|
|
1944
|
-
|
|
1945
|
-
|
|
1942
|
+
const expanded = expandIs(top);
|
|
1943
|
+
if (expanded === null) return null;
|
|
1944
|
+
for (const exp of expanded) {
|
|
1945
|
+
const segments = [];
|
|
1946
|
+
if (!collectSegments(exp, "descendant", segments)) return null;
|
|
1947
|
+
if (segments.length === 0) return null;
|
|
1948
|
+
alts.push(segments);
|
|
1949
|
+
}
|
|
1946
1950
|
}
|
|
1947
1951
|
return alts.length > 0 ? alts : null;
|
|
1948
1952
|
}
|
|
1953
|
+
function expandIs(ast) {
|
|
1954
|
+
switch (ast.type) {
|
|
1955
|
+
case "list": {
|
|
1956
|
+
const out = [];
|
|
1957
|
+
for (const alt of ast.list) {
|
|
1958
|
+
const expanded = expandIs(alt);
|
|
1959
|
+
if (expanded === null) return null;
|
|
1960
|
+
out.push(...expanded);
|
|
1961
|
+
}
|
|
1962
|
+
return out;
|
|
1963
|
+
}
|
|
1964
|
+
case "complex": {
|
|
1965
|
+
const lefts = expandIs(ast.left);
|
|
1966
|
+
if (lefts === null) return null;
|
|
1967
|
+
const rights = expandIs(ast.right);
|
|
1968
|
+
if (rights === null) return null;
|
|
1969
|
+
const out = [];
|
|
1970
|
+
for (const l2 of lefts) for (const r2 of rights) {
|
|
1971
|
+
out.push({ ...ast, left: l2, right: r2 });
|
|
1972
|
+
}
|
|
1973
|
+
return out;
|
|
1974
|
+
}
|
|
1975
|
+
case "compound": {
|
|
1976
|
+
if (ast.list.length === 1) {
|
|
1977
|
+
const tok = ast.list[0];
|
|
1978
|
+
if (tok.type === "pseudo-class" && tok.name === "is") {
|
|
1979
|
+
if (!tok.subtree) return null;
|
|
1980
|
+
return expandIs(tok.subtree);
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
return expandCompoundWithIs(ast.list);
|
|
1984
|
+
}
|
|
1985
|
+
default:
|
|
1986
|
+
if (ast.type === "pseudo-class" && ast.name === "is") {
|
|
1987
|
+
if (!ast.subtree) return null;
|
|
1988
|
+
return expandIs(ast.subtree);
|
|
1989
|
+
}
|
|
1990
|
+
return [ast];
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
function expandCompoundWithIs(tokens) {
|
|
1994
|
+
let variants = [[]];
|
|
1995
|
+
for (const tok of tokens) {
|
|
1996
|
+
if (tok.type === "pseudo-class" && tok.name === "is") {
|
|
1997
|
+
if (!tok.subtree) return null;
|
|
1998
|
+
const alts = expandIs(tok.subtree);
|
|
1999
|
+
if (alts === null) return null;
|
|
2000
|
+
const next = [];
|
|
2001
|
+
for (const base of variants) {
|
|
2002
|
+
for (const alt of alts) {
|
|
2003
|
+
if (alt.type === "compound") {
|
|
2004
|
+
next.push([...base, ...alt.list]);
|
|
2005
|
+
} else if (alt.type === "complex" || alt.type === "list" || alt.type === "relative") {
|
|
2006
|
+
return null;
|
|
2007
|
+
} else {
|
|
2008
|
+
next.push([...base, alt]);
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
variants = next;
|
|
2013
|
+
} else {
|
|
2014
|
+
variants = variants.map((v) => [...v, tok]);
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
return variants.map(
|
|
2018
|
+
(list) => list.length === 1 ? list[0] : { type: "compound", list }
|
|
2019
|
+
);
|
|
2020
|
+
}
|
|
1949
2021
|
function collectSegments(ast, combinator, out) {
|
|
1950
2022
|
if (ast.type === "complex") {
|
|
1951
2023
|
const mapped = mapCombinator(ast.combinator);
|
|
@@ -1963,6 +2035,8 @@ function mapCombinator(c2) {
|
|
|
1963
2035
|
const trimmed = c2.trim();
|
|
1964
2036
|
if (trimmed === "") return "descendant";
|
|
1965
2037
|
if (trimmed === ">") return "child";
|
|
2038
|
+
if (trimmed === "+") return "adjacent-sibling";
|
|
2039
|
+
if (trimmed === "~") return "general-sibling";
|
|
1966
2040
|
return null;
|
|
1967
2041
|
}
|
|
1968
2042
|
function segmentFromCompound(ast) {
|
|
@@ -1973,6 +2047,7 @@ function segmentFromCompound(ast) {
|
|
|
1973
2047
|
let rootOnly = false;
|
|
1974
2048
|
const attributes = [];
|
|
1975
2049
|
const descendantChecks = [];
|
|
2050
|
+
const selfNegations = [];
|
|
1976
2051
|
const forbidChange = (requested) => {
|
|
1977
2052
|
if (kind === void 0) return false;
|
|
1978
2053
|
if (kind === requested) return false;
|
|
@@ -2026,7 +2101,7 @@ function segmentFromCompound(ast) {
|
|
|
2026
2101
|
break;
|
|
2027
2102
|
}
|
|
2028
2103
|
if (token.name === "not") {
|
|
2029
|
-
if (!applyNegatedSubtree(token.subtree, attributes, descendantChecks)) return null;
|
|
2104
|
+
if (!applyNegatedSubtree(token.subtree, attributes, descendantChecks, selfNegations)) return null;
|
|
2030
2105
|
break;
|
|
2031
2106
|
}
|
|
2032
2107
|
if (token.name === "root") {
|
|
@@ -2048,7 +2123,7 @@ function segmentFromCompound(ast) {
|
|
|
2048
2123
|
}
|
|
2049
2124
|
const isHtml = kind === "html";
|
|
2050
2125
|
const finalAttrs = isHtml ? attributes : [];
|
|
2051
|
-
return { kind, rootOnly, name, pathRegex, attributes: finalAttrs, descendantChecks, combinator: "descendant" };
|
|
2126
|
+
return { kind, rootOnly, name, pathRegex, attributes: finalAttrs, descendantChecks, selfNegations, combinator: "descendant" };
|
|
2052
2127
|
}
|
|
2053
2128
|
function mustacheKindFromMarker(name) {
|
|
2054
2129
|
switch (name) {
|
|
@@ -2113,7 +2188,7 @@ function classConstraint(token, negated) {
|
|
|
2113
2188
|
function idConstraint(token, negated) {
|
|
2114
2189
|
return { name: "id", op: "=", value: token.name, negated };
|
|
2115
2190
|
}
|
|
2116
|
-
function applyNegatedSubtree(subtree, attributes, descendantChecks) {
|
|
2191
|
+
function applyNegatedSubtree(subtree, attributes, descendantChecks, selfNegations) {
|
|
2117
2192
|
if (!subtree) return false;
|
|
2118
2193
|
if (subtree.type === "attribute") {
|
|
2119
2194
|
const c2 = attributeConstraint(subtree, true);
|
|
@@ -2130,9 +2205,14 @@ function applyNegatedSubtree(subtree, attributes, descendantChecks) {
|
|
|
2130
2205
|
return true;
|
|
2131
2206
|
}
|
|
2132
2207
|
if (subtree.type === "pseudo-class" && subtree.name === "has") {
|
|
2133
|
-
const
|
|
2134
|
-
if (!
|
|
2135
|
-
descendantChecks.push({ selector:
|
|
2208
|
+
const sel2 = subtreeToSelector(subtree.subtree);
|
|
2209
|
+
if (!sel2) return false;
|
|
2210
|
+
descendantChecks.push({ selector: sel2, negated: true });
|
|
2211
|
+
return true;
|
|
2212
|
+
}
|
|
2213
|
+
const sel = subtreeToSelector(subtree);
|
|
2214
|
+
if (sel) {
|
|
2215
|
+
selfNegations.push(sel);
|
|
2136
2216
|
return true;
|
|
2137
2217
|
}
|
|
2138
2218
|
return false;
|
|
@@ -2232,11 +2312,20 @@ function checkDescendants(node, checks) {
|
|
|
2232
2312
|
return true;
|
|
2233
2313
|
}
|
|
2234
2314
|
function hasDescendantMatch(node, selector) {
|
|
2235
|
-
for (
|
|
2236
|
-
if (matchSelector(
|
|
2315
|
+
for (let i2 = 0; i2 < node.children.length; i2++) {
|
|
2316
|
+
if (matchSelector(node.children[i2], selector, node.children, i2).length > 0) return true;
|
|
2237
2317
|
}
|
|
2238
2318
|
return false;
|
|
2239
2319
|
}
|
|
2320
|
+
function checkSelfNegations(node, negations, rootNode) {
|
|
2321
|
+
for (const sel of negations) {
|
|
2322
|
+
for (const alt of sel) {
|
|
2323
|
+
if (alt.length !== 1) continue;
|
|
2324
|
+
if (nodeMatchesSegment(node, alt[0], rootNode)) return false;
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
return true;
|
|
2328
|
+
}
|
|
2240
2329
|
function matchesName(actual, segment) {
|
|
2241
2330
|
if (segment.name === null) return true;
|
|
2242
2331
|
if (actual === null) return false;
|
|
@@ -2246,51 +2335,73 @@ function matchesName(actual, segment) {
|
|
|
2246
2335
|
function nodeMatchesSegment(node, segment, rootNode) {
|
|
2247
2336
|
if (segment.rootOnly) {
|
|
2248
2337
|
if (node !== rootNode) return false;
|
|
2249
|
-
return checkDescendants(node, segment.descendantChecks);
|
|
2250
|
-
}
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2338
|
+
return checkDescendants(node, segment.descendantChecks) && checkSelfNegations(node, segment.selfNegations, rootNode);
|
|
2339
|
+
}
|
|
2340
|
+
const baseMatches = (() => {
|
|
2341
|
+
switch (segment.kind) {
|
|
2342
|
+
case "html": {
|
|
2343
|
+
if (!HTML_ELEMENT_TYPES.has(node.type)) return false;
|
|
2344
|
+
if (segment.name !== null) {
|
|
2345
|
+
const tagName = getTagName(node)?.toLowerCase();
|
|
2346
|
+
if (tagName !== segment.name) return false;
|
|
2347
|
+
}
|
|
2348
|
+
return checkAttributes(node, segment.attributes) && checkDescendants(node, segment.descendantChecks);
|
|
2257
2349
|
}
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2350
|
+
case "section":
|
|
2351
|
+
if (node.type !== "mustache_section") return false;
|
|
2352
|
+
if (!matchesName(getSectionName(node)?.toLowerCase() ?? null, segment)) return false;
|
|
2353
|
+
return checkDescendants(node, segment.descendantChecks);
|
|
2354
|
+
case "inverted":
|
|
2355
|
+
if (node.type !== "mustache_inverted_section") return false;
|
|
2356
|
+
if (!matchesName(getSectionName(node)?.toLowerCase() ?? null, segment)) return false;
|
|
2357
|
+
return checkDescendants(node, segment.descendantChecks);
|
|
2358
|
+
case "variable":
|
|
2359
|
+
if (node.type !== "mustache_interpolation") return false;
|
|
2360
|
+
if (!matchesName(getInterpolationPath(node)?.toLowerCase() ?? null, segment)) return false;
|
|
2361
|
+
return checkDescendants(node, segment.descendantChecks);
|
|
2362
|
+
case "raw":
|
|
2363
|
+
if (node.type !== "mustache_triple") return false;
|
|
2364
|
+
if (!matchesName(getInterpolationPath(node)?.toLowerCase() ?? null, segment)) return false;
|
|
2365
|
+
return checkDescendants(node, segment.descendantChecks);
|
|
2366
|
+
case "comment":
|
|
2367
|
+
if (node.type !== "mustache_comment") return false;
|
|
2368
|
+
if (!matchesName(getCommentContent(node)?.toLowerCase() ?? null, segment)) return false;
|
|
2369
|
+
return checkDescendants(node, segment.descendantChecks);
|
|
2370
|
+
case "partial":
|
|
2371
|
+
if (node.type !== "mustache_partial") return false;
|
|
2372
|
+
if (!matchesName(getPartialName(node)?.toLowerCase() ?? null, segment)) return false;
|
|
2373
|
+
return checkDescendants(node, segment.descendantChecks);
|
|
2374
|
+
}
|
|
2375
|
+
})();
|
|
2376
|
+
if (!baseMatches) return false;
|
|
2377
|
+
return checkSelfNegations(node, segment.selfNegations, rootNode);
|
|
2378
|
+
}
|
|
2379
|
+
function checkPrefix(cursor, segments, segIdx, stepCombinator, rootNode) {
|
|
2287
2380
|
if (segIdx < 0) return true;
|
|
2288
2381
|
const segment = segments[segIdx];
|
|
2382
|
+
if (stepCombinator === "adjacent-sibling" || stepCombinator === "general-sibling") {
|
|
2383
|
+
for (let i2 = cursor.indexInSiblings - 1; i2 >= 0; i2--) {
|
|
2384
|
+
const sib = cursor.siblings[i2];
|
|
2385
|
+
if (!isMatchableNode(sib)) continue;
|
|
2386
|
+
if (!nodeMatchesSegment(sib, segment, rootNode)) {
|
|
2387
|
+
if (stepCombinator === "adjacent-sibling") return false;
|
|
2388
|
+
continue;
|
|
2389
|
+
}
|
|
2390
|
+
const newCursor = {
|
|
2391
|
+
ancestors: cursor.ancestors,
|
|
2392
|
+
siblings: cursor.siblings,
|
|
2393
|
+
indexInSiblings: i2
|
|
2394
|
+
};
|
|
2395
|
+
if (checkPrefix(newCursor, segments, segIdx - 1, segment.combinator, rootNode)) return true;
|
|
2396
|
+
if (stepCombinator === "adjacent-sibling") return false;
|
|
2397
|
+
}
|
|
2398
|
+
return false;
|
|
2399
|
+
}
|
|
2289
2400
|
const ancestorKind = ancestorKindForSegment(segment);
|
|
2290
2401
|
if (ancestorKind === null) return false;
|
|
2291
|
-
if (
|
|
2292
|
-
for (let a2 = ancestors.length - 1; a2 >= 0; a2--) {
|
|
2293
|
-
const entry = ancestors[a2];
|
|
2402
|
+
if (stepCombinator === "child") {
|
|
2403
|
+
for (let a2 = cursor.ancestors.length - 1; a2 >= 0; a2--) {
|
|
2404
|
+
const entry = cursor.ancestors[a2];
|
|
2294
2405
|
if (entry.kind !== ancestorKind) {
|
|
2295
2406
|
if (ancestorKind === "root" && entry.kind === "html") return false;
|
|
2296
2407
|
continue;
|
|
@@ -2298,22 +2409,35 @@ function checkAncestors(ancestors, segments, segIdx, childCombinator) {
|
|
|
2298
2409
|
if (!matchesName(entry.name, segment)) return false;
|
|
2299
2410
|
if (segment.kind === "html" && !checkAttributes(entry.node, segment.attributes)) return false;
|
|
2300
2411
|
if (!checkDescendants(entry.node, segment.descendantChecks)) return false;
|
|
2301
|
-
|
|
2412
|
+
if (!checkSelfNegations(entry.node, segment.selfNegations, rootNode)) return false;
|
|
2413
|
+
const newCursor = {
|
|
2414
|
+
ancestors: cursor.ancestors.slice(0, a2),
|
|
2415
|
+
siblings: entry.siblings,
|
|
2416
|
+
indexInSiblings: entry.indexInSiblings
|
|
2417
|
+
};
|
|
2418
|
+
return checkPrefix(newCursor, segments, segIdx - 1, segment.combinator, rootNode);
|
|
2302
2419
|
}
|
|
2303
2420
|
return false;
|
|
2304
2421
|
}
|
|
2305
|
-
for (let a2 = ancestors.length - 1; a2 >= 0; a2--) {
|
|
2306
|
-
const entry = ancestors[a2];
|
|
2422
|
+
for (let a2 = cursor.ancestors.length - 1; a2 >= 0; a2--) {
|
|
2423
|
+
const entry = cursor.ancestors[a2];
|
|
2307
2424
|
if (entry.kind !== ancestorKind) continue;
|
|
2308
2425
|
if (!matchesName(entry.name, segment)) continue;
|
|
2309
2426
|
if (segment.kind === "html" && !checkAttributes(entry.node, segment.attributes)) continue;
|
|
2310
2427
|
if (!checkDescendants(entry.node, segment.descendantChecks)) continue;
|
|
2311
|
-
if (
|
|
2312
|
-
|
|
2313
|
-
|
|
2428
|
+
if (!checkSelfNegations(entry.node, segment.selfNegations, rootNode)) continue;
|
|
2429
|
+
const newCursor = {
|
|
2430
|
+
ancestors: cursor.ancestors.slice(0, a2),
|
|
2431
|
+
siblings: entry.siblings,
|
|
2432
|
+
indexInSiblings: entry.indexInSiblings
|
|
2433
|
+
};
|
|
2434
|
+
if (checkPrefix(newCursor, segments, segIdx - 1, segment.combinator, rootNode)) return true;
|
|
2314
2435
|
}
|
|
2315
2436
|
return false;
|
|
2316
2437
|
}
|
|
2438
|
+
function isMatchableNode(node) {
|
|
2439
|
+
return HTML_ELEMENT_TYPES.has(node.type) || node.type === "mustache_section" || node.type === "mustache_inverted_section" || node.type === "mustache_interpolation" || node.type === "mustache_triple" || node.type === "mustache_comment" || node.type === "mustache_partial";
|
|
2440
|
+
}
|
|
2317
2441
|
function ancestorKindForSegment(segment) {
|
|
2318
2442
|
if (segment.rootOnly) return "root";
|
|
2319
2443
|
if (segment.kind === "html") return "html";
|
|
@@ -2347,12 +2471,13 @@ function getReportNode(node, rootNode) {
|
|
|
2347
2471
|
}
|
|
2348
2472
|
return node;
|
|
2349
2473
|
}
|
|
2350
|
-
function matchAlternative(rootNode, segments) {
|
|
2474
|
+
function matchAlternative(rootNode, segments, rootSiblings, rootIndexInSiblings) {
|
|
2351
2475
|
const results = [];
|
|
2352
2476
|
const lastSegment = segments[segments.length - 1];
|
|
2353
|
-
function walk(node, ancestors) {
|
|
2477
|
+
function walk(node, ancestors, siblings, indexInSiblings) {
|
|
2354
2478
|
if (nodeMatchesSegment(node, lastSegment, rootNode)) {
|
|
2355
|
-
|
|
2479
|
+
const cursor = { ancestors, siblings, indexInSiblings };
|
|
2480
|
+
if (segments.length === 1 || checkPrefix(cursor, segments, segments.length - 2, lastSegment.combinator, rootNode)) {
|
|
2356
2481
|
results.push(getReportNode(node, rootNode));
|
|
2357
2482
|
}
|
|
2358
2483
|
}
|
|
@@ -2361,19 +2486,28 @@ function matchAlternative(rootNode, segments) {
|
|
|
2361
2486
|
if (ancestorKind !== null) {
|
|
2362
2487
|
const name = ancestorKind === "html" ? getTagName(node)?.toLowerCase() : getSectionName(node)?.toLowerCase();
|
|
2363
2488
|
if (name) {
|
|
2364
|
-
newAncestors = [...ancestors, { kind: ancestorKind, name, node }];
|
|
2489
|
+
newAncestors = [...ancestors, { kind: ancestorKind, name, node, siblings, indexInSiblings }];
|
|
2365
2490
|
}
|
|
2366
2491
|
}
|
|
2367
|
-
for (
|
|
2492
|
+
for (let i2 = 0; i2 < node.children.length; i2++) {
|
|
2493
|
+
walk(node.children[i2], newAncestors, node.children, i2);
|
|
2494
|
+
}
|
|
2368
2495
|
}
|
|
2369
|
-
|
|
2496
|
+
const rootEntry = {
|
|
2497
|
+
kind: "root",
|
|
2498
|
+
name: "",
|
|
2499
|
+
node: rootNode,
|
|
2500
|
+
siblings: rootSiblings,
|
|
2501
|
+
indexInSiblings: rootIndexInSiblings
|
|
2502
|
+
};
|
|
2503
|
+
walk(rootNode, [rootEntry], rootSiblings, rootIndexInSiblings);
|
|
2370
2504
|
return results;
|
|
2371
2505
|
}
|
|
2372
|
-
function matchSelector(rootNode, selector) {
|
|
2506
|
+
function matchSelector(rootNode, selector, siblings = [], indexInSiblings = 0) {
|
|
2373
2507
|
const allResults = [];
|
|
2374
2508
|
const seen = /* @__PURE__ */ new Set();
|
|
2375
2509
|
for (const alt of selector) {
|
|
2376
|
-
for (const node of matchAlternative(rootNode, alt)) {
|
|
2510
|
+
for (const node of matchAlternative(rootNode, alt, siblings, indexInSiblings)) {
|
|
2377
2511
|
if (!seen.has(node)) {
|
|
2378
2512
|
seen.add(node);
|
|
2379
2513
|
allResults.push(node);
|