@reteps/tree-sitter-htmlmustache 0.9.2 → 0.9.3
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 +25 -20
- package/browser/out/browser/index.mjs.map +2 -2
- package/browser/out/core/selectorMatcher.d.ts +5 -1
- package/browser/out/core/selectorMatcher.d.ts.map +1 -1
- package/cli/out/main.js +25 -20
- package/package.json +1 -1
- package/src/core/selectorMatcher.ts +44 -24
|
@@ -24,7 +24,11 @@
|
|
|
24
24
|
* the outer compound), plus any other selector (including Mustache
|
|
25
25
|
* literals and type selectors) as a whole-selector check against the
|
|
26
26
|
* node itself. Example: `{{*}}:not({{internal.*}})` matches any
|
|
27
|
-
* interpolation whose path does not start with `internal.`.
|
|
27
|
+
* interpolation whose path does not start with `internal.`. Multi-segment
|
|
28
|
+
* selectors with combinators are supported and tested against the node's
|
|
29
|
+
* ancestor/sibling context, matching `Element.matches` semantics — e.g.
|
|
30
|
+
* `img:not(pl-overlay img)` matches any `img` that is not a descendant of
|
|
31
|
+
* `pl-overlay`, and `td:not(thead td)` matches `td`s outside a `thead`.
|
|
28
32
|
* - `:root` — the tree-sitter fragment root (the whole document). Unlike
|
|
29
33
|
* browser CSS where `:root` matches `<html>`, this matches the parse-tree
|
|
30
34
|
* root so it works on partials/fragments too. Useful as a document-scoped
|
|
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;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;AA2qBD,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
|
@@ -2326,11 +2326,16 @@ function hasDescendantMatch(node, selector) {
|
|
|
2326
2326
|
}
|
|
2327
2327
|
return false;
|
|
2328
2328
|
}
|
|
2329
|
-
function checkSelfNegations(node, negations, rootNode) {
|
|
2329
|
+
function checkSelfNegations(node, negations, rootNode, cursor) {
|
|
2330
2330
|
for (const sel of negations) {
|
|
2331
2331
|
for (const alt of sel) {
|
|
2332
|
-
if (alt.length
|
|
2333
|
-
|
|
2332
|
+
if (alt.length === 0) continue;
|
|
2333
|
+
const lastSegment = alt[alt.length - 1];
|
|
2334
|
+
if (!nodeMatchesSegment(node, lastSegment, rootNode, cursor)) continue;
|
|
2335
|
+
if (alt.length === 1) return false;
|
|
2336
|
+
if (checkPrefix(cursor, alt, alt.length - 2, lastSegment.combinator, rootNode)) {
|
|
2337
|
+
return false;
|
|
2338
|
+
}
|
|
2334
2339
|
}
|
|
2335
2340
|
}
|
|
2336
2341
|
return true;
|
|
@@ -2341,10 +2346,10 @@ function matchesName(actual, segment) {
|
|
|
2341
2346
|
if (segment.pathRegex) return segment.pathRegex.test(actual);
|
|
2342
2347
|
return actual === segment.name;
|
|
2343
2348
|
}
|
|
2344
|
-
function nodeMatchesSegment(node, segment, rootNode) {
|
|
2349
|
+
function nodeMatchesSegment(node, segment, rootNode, cursor) {
|
|
2345
2350
|
if (segment.rootOnly) {
|
|
2346
2351
|
if (node !== rootNode) return false;
|
|
2347
|
-
return checkDescendants(node, segment.descendantChecks) && checkSelfNegations(node, segment.selfNegations, rootNode);
|
|
2352
|
+
return checkDescendants(node, segment.descendantChecks) && checkSelfNegations(node, segment.selfNegations, rootNode, cursor);
|
|
2348
2353
|
}
|
|
2349
2354
|
const baseMatches = (() => {
|
|
2350
2355
|
switch (segment.kind) {
|
|
@@ -2383,7 +2388,7 @@ function nodeMatchesSegment(node, segment, rootNode) {
|
|
|
2383
2388
|
}
|
|
2384
2389
|
})();
|
|
2385
2390
|
if (!baseMatches) return false;
|
|
2386
|
-
return checkSelfNegations(node, segment.selfNegations, rootNode);
|
|
2391
|
+
return checkSelfNegations(node, segment.selfNegations, rootNode, cursor);
|
|
2387
2392
|
}
|
|
2388
2393
|
function checkPrefix(cursor, segments, segIdx, stepCombinator, rootNode) {
|
|
2389
2394
|
if (segIdx < 0) return true;
|
|
@@ -2392,16 +2397,16 @@ function checkPrefix(cursor, segments, segIdx, stepCombinator, rootNode) {
|
|
|
2392
2397
|
for (let i2 = cursor.indexInSiblings - 1; i2 >= 0; i2--) {
|
|
2393
2398
|
const sib = cursor.siblings[i2];
|
|
2394
2399
|
if (!isMatchableNode(sib)) continue;
|
|
2395
|
-
|
|
2396
|
-
if (stepCombinator === "adjacent-sibling") return false;
|
|
2397
|
-
continue;
|
|
2398
|
-
}
|
|
2399
|
-
const newCursor = {
|
|
2400
|
+
const sibCursor = {
|
|
2400
2401
|
ancestors: cursor.ancestors,
|
|
2401
2402
|
siblings: cursor.siblings,
|
|
2402
2403
|
indexInSiblings: i2
|
|
2403
2404
|
};
|
|
2404
|
-
if (
|
|
2405
|
+
if (!nodeMatchesSegment(sib, segment, rootNode, sibCursor)) {
|
|
2406
|
+
if (stepCombinator === "adjacent-sibling") return false;
|
|
2407
|
+
continue;
|
|
2408
|
+
}
|
|
2409
|
+
if (checkPrefix(sibCursor, segments, segIdx - 1, segment.combinator, rootNode)) return true;
|
|
2405
2410
|
if (stepCombinator === "adjacent-sibling") return false;
|
|
2406
2411
|
}
|
|
2407
2412
|
return false;
|
|
@@ -2418,13 +2423,13 @@ function checkPrefix(cursor, segments, segIdx, stepCombinator, rootNode) {
|
|
|
2418
2423
|
if (!matchesName(entry.name, segment)) return false;
|
|
2419
2424
|
if (segment.kind === "html" && !checkAttributes(entry.node, segment.attributes)) return false;
|
|
2420
2425
|
if (!checkDescendants(entry.node, segment.descendantChecks)) return false;
|
|
2421
|
-
|
|
2422
|
-
const newCursor = {
|
|
2426
|
+
const ancestorCursor = {
|
|
2423
2427
|
ancestors: cursor.ancestors.slice(0, a2),
|
|
2424
2428
|
siblings: entry.siblings,
|
|
2425
2429
|
indexInSiblings: entry.indexInSiblings
|
|
2426
2430
|
};
|
|
2427
|
-
|
|
2431
|
+
if (!checkSelfNegations(entry.node, segment.selfNegations, rootNode, ancestorCursor)) return false;
|
|
2432
|
+
return checkPrefix(ancestorCursor, segments, segIdx - 1, segment.combinator, rootNode);
|
|
2428
2433
|
}
|
|
2429
2434
|
return false;
|
|
2430
2435
|
}
|
|
@@ -2434,13 +2439,13 @@ function checkPrefix(cursor, segments, segIdx, stepCombinator, rootNode) {
|
|
|
2434
2439
|
if (!matchesName(entry.name, segment)) continue;
|
|
2435
2440
|
if (segment.kind === "html" && !checkAttributes(entry.node, segment.attributes)) continue;
|
|
2436
2441
|
if (!checkDescendants(entry.node, segment.descendantChecks)) continue;
|
|
2437
|
-
|
|
2438
|
-
const newCursor = {
|
|
2442
|
+
const ancestorCursor = {
|
|
2439
2443
|
ancestors: cursor.ancestors.slice(0, a2),
|
|
2440
2444
|
siblings: entry.siblings,
|
|
2441
2445
|
indexInSiblings: entry.indexInSiblings
|
|
2442
2446
|
};
|
|
2443
|
-
if (
|
|
2447
|
+
if (!checkSelfNegations(entry.node, segment.selfNegations, rootNode, ancestorCursor)) continue;
|
|
2448
|
+
if (checkPrefix(ancestorCursor, segments, segIdx - 1, segment.combinator, rootNode)) return true;
|
|
2444
2449
|
}
|
|
2445
2450
|
return false;
|
|
2446
2451
|
}
|
|
@@ -2484,8 +2489,8 @@ function matchAlternative(rootNode, segments, rootSiblings, rootIndexInSiblings)
|
|
|
2484
2489
|
const results = [];
|
|
2485
2490
|
const lastSegment = segments[segments.length - 1];
|
|
2486
2491
|
function walk(node, ancestors, siblings, indexInSiblings) {
|
|
2487
|
-
|
|
2488
|
-
|
|
2492
|
+
const cursor = { ancestors, siblings, indexInSiblings };
|
|
2493
|
+
if (nodeMatchesSegment(node, lastSegment, rootNode, cursor)) {
|
|
2489
2494
|
if (segments.length === 1 || checkPrefix(cursor, segments, segments.length - 2, lastSegment.combinator, rootNode)) {
|
|
2490
2495
|
results.push(getReportNode(node, rootNode));
|
|
2491
2496
|
}
|
package/package.json
CHANGED
|
@@ -24,7 +24,11 @@
|
|
|
24
24
|
* the outer compound), plus any other selector (including Mustache
|
|
25
25
|
* literals and type selectors) as a whole-selector check against the
|
|
26
26
|
* node itself. Example: `{{*}}:not({{internal.*}})` matches any
|
|
27
|
-
* interpolation whose path does not start with `internal.`.
|
|
27
|
+
* interpolation whose path does not start with `internal.`. Multi-segment
|
|
28
|
+
* selectors with combinators are supported and tested against the node's
|
|
29
|
+
* ancestor/sibling context, matching `Element.matches` semantics — e.g.
|
|
30
|
+
* `img:not(pl-overlay img)` matches any `img` that is not a descendant of
|
|
31
|
+
* `pl-overlay`, and `td:not(thead td)` matches `td`s outside a `thead`.
|
|
28
32
|
* - `:root` — the tree-sitter fragment root (the whole document). Unlike
|
|
29
33
|
* browser CSS where `:root` matches `<html>`, this matches the parse-tree
|
|
30
34
|
* root so it works on partials/fragments too. Useful as a document-scoped
|
|
@@ -651,14 +655,25 @@ function hasDescendantMatch(node: BalanceNode, selector: ParsedSelector): boolea
|
|
|
651
655
|
return false;
|
|
652
656
|
}
|
|
653
657
|
|
|
654
|
-
function checkSelfNegations(
|
|
658
|
+
function checkSelfNegations(
|
|
659
|
+
node: BalanceNode,
|
|
660
|
+
negations: ParsedSelector[],
|
|
661
|
+
rootNode: BalanceNode,
|
|
662
|
+
cursor: Cursor,
|
|
663
|
+
): boolean {
|
|
655
664
|
for (const sel of negations) {
|
|
656
665
|
for (const alt of sel) {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
if (alt.length
|
|
661
|
-
|
|
666
|
+
if (alt.length === 0) continue;
|
|
667
|
+
const lastSegment = alt[alt.length - 1];
|
|
668
|
+
if (!nodeMatchesSegment(node, lastSegment, rootNode, cursor)) continue;
|
|
669
|
+
if (alt.length === 1) return false;
|
|
670
|
+
// Multi-segment negation (e.g. `:not(ancestor descendant)`): the last
|
|
671
|
+
// segment matched the node itself; walk back through the remaining
|
|
672
|
+
// segments against the node's ancestor/sibling cursor. If the chain
|
|
673
|
+
// also matches, the negation fires.
|
|
674
|
+
if (checkPrefix(cursor, alt, alt.length - 2, lastSegment.combinator, rootNode)) {
|
|
675
|
+
return false;
|
|
676
|
+
}
|
|
662
677
|
}
|
|
663
678
|
}
|
|
664
679
|
return true;
|
|
@@ -671,11 +686,16 @@ function matchesName(actual: string | null, segment: Segment): boolean {
|
|
|
671
686
|
return actual === segment.name;
|
|
672
687
|
}
|
|
673
688
|
|
|
674
|
-
function nodeMatchesSegment(
|
|
689
|
+
function nodeMatchesSegment(
|
|
690
|
+
node: BalanceNode,
|
|
691
|
+
segment: Segment,
|
|
692
|
+
rootNode: BalanceNode,
|
|
693
|
+
cursor: Cursor,
|
|
694
|
+
): boolean {
|
|
675
695
|
if (segment.rootOnly) {
|
|
676
696
|
if (node !== rootNode) return false;
|
|
677
697
|
return checkDescendants(node, segment.descendantChecks)
|
|
678
|
-
&& checkSelfNegations(node, segment.selfNegations, rootNode);
|
|
698
|
+
&& checkSelfNegations(node, segment.selfNegations, rootNode, cursor);
|
|
679
699
|
}
|
|
680
700
|
const baseMatches = (() => {
|
|
681
701
|
switch (segment.kind) {
|
|
@@ -714,7 +734,7 @@ function nodeMatchesSegment(node: BalanceNode, segment: Segment, rootNode: Balan
|
|
|
714
734
|
}
|
|
715
735
|
})();
|
|
716
736
|
if (!baseMatches) return false;
|
|
717
|
-
return checkSelfNegations(node, segment.selfNegations, rootNode);
|
|
737
|
+
return checkSelfNegations(node, segment.selfNegations, rootNode, cursor);
|
|
718
738
|
}
|
|
719
739
|
|
|
720
740
|
interface Cursor {
|
|
@@ -738,16 +758,16 @@ function checkPrefix(
|
|
|
738
758
|
for (let i = cursor.indexInSiblings - 1; i >= 0; i--) {
|
|
739
759
|
const sib = cursor.siblings[i];
|
|
740
760
|
if (!isMatchableNode(sib)) continue;
|
|
741
|
-
|
|
742
|
-
if (stepCombinator === 'adjacent-sibling') return false;
|
|
743
|
-
continue;
|
|
744
|
-
}
|
|
745
|
-
const newCursor: Cursor = {
|
|
761
|
+
const sibCursor: Cursor = {
|
|
746
762
|
ancestors: cursor.ancestors,
|
|
747
763
|
siblings: cursor.siblings,
|
|
748
764
|
indexInSiblings: i,
|
|
749
765
|
};
|
|
750
|
-
if (
|
|
766
|
+
if (!nodeMatchesSegment(sib, segment, rootNode, sibCursor)) {
|
|
767
|
+
if (stepCombinator === 'adjacent-sibling') return false;
|
|
768
|
+
continue;
|
|
769
|
+
}
|
|
770
|
+
if (checkPrefix(sibCursor, segments, segIdx - 1, segment.combinator, rootNode)) return true;
|
|
751
771
|
if (stepCombinator === 'adjacent-sibling') return false;
|
|
752
772
|
}
|
|
753
773
|
return false;
|
|
@@ -770,13 +790,13 @@ function checkPrefix(
|
|
|
770
790
|
if (!matchesName(entry.name, segment)) return false;
|
|
771
791
|
if (segment.kind === 'html' && !checkAttributes(entry.node, segment.attributes)) return false;
|
|
772
792
|
if (!checkDescendants(entry.node, segment.descendantChecks)) return false;
|
|
773
|
-
|
|
774
|
-
const newCursor: Cursor = {
|
|
793
|
+
const ancestorCursor: Cursor = {
|
|
775
794
|
ancestors: cursor.ancestors.slice(0, a),
|
|
776
795
|
siblings: entry.siblings,
|
|
777
796
|
indexInSiblings: entry.indexInSiblings,
|
|
778
797
|
};
|
|
779
|
-
|
|
798
|
+
if (!checkSelfNegations(entry.node, segment.selfNegations, rootNode, ancestorCursor)) return false;
|
|
799
|
+
return checkPrefix(ancestorCursor, segments, segIdx - 1, segment.combinator, rootNode);
|
|
780
800
|
}
|
|
781
801
|
return false;
|
|
782
802
|
}
|
|
@@ -787,13 +807,13 @@ function checkPrefix(
|
|
|
787
807
|
if (!matchesName(entry.name, segment)) continue;
|
|
788
808
|
if (segment.kind === 'html' && !checkAttributes(entry.node, segment.attributes)) continue;
|
|
789
809
|
if (!checkDescendants(entry.node, segment.descendantChecks)) continue;
|
|
790
|
-
|
|
791
|
-
const newCursor: Cursor = {
|
|
810
|
+
const ancestorCursor: Cursor = {
|
|
792
811
|
ancestors: cursor.ancestors.slice(0, a),
|
|
793
812
|
siblings: entry.siblings,
|
|
794
813
|
indexInSiblings: entry.indexInSiblings,
|
|
795
814
|
};
|
|
796
|
-
if (
|
|
815
|
+
if (!checkSelfNegations(entry.node, segment.selfNegations, rootNode, ancestorCursor)) continue;
|
|
816
|
+
if (checkPrefix(ancestorCursor, segments, segIdx - 1, segment.combinator, rootNode)) return true;
|
|
797
817
|
}
|
|
798
818
|
return false;
|
|
799
819
|
}
|
|
@@ -862,8 +882,8 @@ function matchAlternative(
|
|
|
862
882
|
siblings: BalanceNode[],
|
|
863
883
|
indexInSiblings: number,
|
|
864
884
|
) {
|
|
865
|
-
|
|
866
|
-
|
|
885
|
+
const cursor: Cursor = { ancestors, siblings, indexInSiblings };
|
|
886
|
+
if (nodeMatchesSegment(node, lastSegment, rootNode, cursor)) {
|
|
867
887
|
if (
|
|
868
888
|
segments.length === 1 ||
|
|
869
889
|
checkPrefix(cursor, segments, segments.length - 2, lastSegment.combinator, rootNode)
|