astro-eslint-parser 0.7.4 → 0.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.
package/lib/index.mjs CHANGED
@@ -93,6 +93,19 @@ function isBasicParserObject(value) {
93
93
  function maybeTSESLintParserObject(value) {
94
94
  return isEnhancedParserObject(value) && isBasicParserObject(value) && typeof value.createProgram === "function" && typeof value.clearCaches === "function" && typeof value.version === "string";
95
95
  }
96
+ function isTSESLintParserObject(value) {
97
+ if (!isEnhancedParserObject(value))
98
+ return false;
99
+ try {
100
+ const result = value.parseForESLint("", {});
101
+ const services = result.services;
102
+ return Boolean(
103
+ services && services.esTreeNodeToTSNodeMap && services.tsNodeToESTreeNodeMap && services.program
104
+ );
105
+ } catch {
106
+ return false;
107
+ }
108
+ }
96
109
 
97
110
  // src/parser/script.ts
98
111
  function parseScript(code, _ctx, parserOptions) {
@@ -525,51 +538,41 @@ function traverseNodes(node, visitor) {
525
538
  traverse(node, null, visitor);
526
539
  }
527
540
 
528
- // src/context/script.ts
541
+ // src/context/restore.ts
529
542
  var RestoreNodeProcessContext = class {
530
- constructor(result, parentMap) {
543
+ constructor(result, nodeMap) {
531
544
  this.removeTokens = /* @__PURE__ */ new Set();
532
545
  this.result = result;
533
- this.parentMap = parentMap;
546
+ this.nodeMap = nodeMap;
534
547
  }
535
548
  addRemoveToken(test) {
536
549
  this.removeTokens.add(test);
537
550
  }
538
551
  getParent(node) {
539
- return this.parentMap.get(node) || null;
552
+ return this.nodeMap.get(node) || null;
540
553
  }
541
554
  };
542
- var ScriptContext = class {
555
+ var RestoreContext = class {
543
556
  constructor(ctx) {
544
- this.script = "";
545
- this.consumedIndex = 0;
546
557
  this.offsets = [];
547
- this.fragments = [];
548
- this.tokens = [];
558
+ this.virtualFragments = [];
549
559
  this.restoreNodeProcesses = [];
560
+ this.tokens = [];
550
561
  this.ctx = ctx;
551
562
  }
552
- get originalCode() {
553
- return this.ctx.code;
563
+ addRestoreNodeProcess(process2) {
564
+ this.restoreNodeProcesses.push(process2);
554
565
  }
555
- skipOriginalOffset(offset) {
556
- this.consumedIndex += offset;
566
+ addOffset(offset) {
567
+ this.offsets.push(offset);
557
568
  }
558
- appendOriginal(index) {
559
- if (this.consumedIndex >= index) {
569
+ addVirtualFragmentRange(start, end) {
570
+ const peek = this.virtualFragments[this.virtualFragments.length - 1];
571
+ if (peek && peek.end === start) {
572
+ peek.end = end;
560
573
  return;
561
574
  }
562
- this.offsets.push({
563
- original: this.consumedIndex,
564
- script: this.script.length
565
- });
566
- this.script += this.ctx.code.slice(this.consumedIndex, index);
567
- this.consumedIndex = index;
568
- }
569
- appendScript(fragment) {
570
- const start = this.script.length;
571
- this.script += fragment;
572
- this.fragments.push({ start, end: this.script.length });
575
+ this.virtualFragments.push({ start, end });
573
576
  }
574
577
  addToken(type, range) {
575
578
  if (range[0] >= range[1]) {
@@ -577,63 +580,17 @@ var ScriptContext = class {
577
580
  }
578
581
  this.tokens.push(this.ctx.buildToken(type, range));
579
582
  }
580
- addRestoreNodeProcess(process2) {
581
- this.restoreNodeProcesses.push(process2);
582
- }
583
583
  restore(result) {
584
584
  var _a, _b;
585
- const traversed = /* @__PURE__ */ new Map();
586
- traverseNodes(result.ast, {
587
- visitorKeys: result.visitorKeys,
588
- enterNode: (node, p) => {
589
- if (!traversed.has(node)) {
590
- traversed.set(node, p);
591
- this.remapLocation(node);
592
- }
593
- },
594
- leaveNode: (_node) => {
595
- }
596
- });
597
- const tokens = [...this.tokens];
598
- for (const token of result.ast.tokens || []) {
599
- if (this.fragments.some(
585
+ const nodeMap = remapLocationsAndGetNodeMap(result, this.tokens, {
586
+ remapLocation: (n) => this.remapLocation(n),
587
+ removeToken: (token) => this.virtualFragments.some(
600
588
  (f) => f.start <= token.range[0] && token.range[1] <= f.end
601
- )) {
602
- continue;
603
- }
604
- this.remapLocation(token);
605
- tokens.push(token);
606
- }
607
- result.ast.tokens = tokens;
608
- for (const token of result.ast.comments || []) {
609
- this.remapLocation(token);
610
- }
611
- const context = new RestoreNodeProcessContext(result, traversed);
612
- let restoreNodeProcesses = this.restoreNodeProcesses;
613
- for (const [node, parent] of traversed) {
614
- if (!parent)
615
- continue;
616
- restoreNodeProcesses = restoreNodeProcesses.filter(
617
- (proc) => !proc(node, context)
618
- );
619
- }
620
- if (context.removeTokens.size) {
621
- const tokens2 = result.ast.tokens || [];
622
- for (let index = tokens2.length - 1; index >= 0; index--) {
623
- const token = tokens2[index];
624
- for (const rt of context.removeTokens) {
625
- if (rt(token)) {
626
- tokens2.splice(index, 1);
627
- context.removeTokens.delete(rt);
628
- if (!context.removeTokens.size) {
629
- break;
630
- }
631
- }
632
- }
633
- }
634
- }
589
+ )
590
+ });
591
+ restoreNodes(result, nodeMap, this.restoreNodeProcesses);
635
592
  const firstOffset = Math.min(
636
- ...[result.ast.body[0], (_a = result.ast.tokens) == null ? void 0 : _a[0], (_b = result.ast.comments) == null ? void 0 : _b[0]].filter(Boolean).map((t) => t.range[0])
593
+ ...[result.ast.body[0], (_a = result.ast.tokens) == null ? void 0 : _a[0], (_b = result.ast.comments) == null ? void 0 : _b[0]].filter((t) => Boolean(t)).map((t) => t.range[0])
637
594
  );
638
595
  if (firstOffset < result.ast.range[0]) {
639
596
  result.ast.range[0] = firstOffset;
@@ -642,17 +599,20 @@ var ScriptContext = class {
642
599
  }
643
600
  remapLocation(node) {
644
601
  let [start, end] = node.range;
645
- const startFragment = this.fragments.find(
602
+ const startFragment = this.virtualFragments.find(
646
603
  (f) => f.start <= start && start < f.end
647
604
  );
648
605
  if (startFragment) {
649
606
  start = startFragment.end;
650
607
  }
651
- const endFragment = this.fragments.find(
608
+ const endFragment = this.virtualFragments.find(
652
609
  (f) => f.start < end && end <= f.end
653
610
  );
654
611
  if (endFragment) {
655
612
  end = endFragment.start;
613
+ if (startFragment === endFragment) {
614
+ start = startFragment.start;
615
+ }
656
616
  }
657
617
  if (end < start) {
658
618
  const w = start;
@@ -676,39 +636,128 @@ var ScriptContext = class {
676
636
  let lastStart = this.offsets[0];
677
637
  let lastEnd = this.offsets[0];
678
638
  for (const offset of this.offsets) {
679
- if (offset.script <= start) {
639
+ if (offset.dist <= start) {
680
640
  lastStart = offset;
681
641
  }
682
- if (offset.script < end) {
642
+ if (offset.dist < end) {
683
643
  lastEnd = offset;
684
644
  } else {
685
- if (offset.script === end) {
686
- const remapStart2 = lastStart.original + (start - lastStart.script);
687
- if (this.tokens.some(
688
- (t) => t.range[0] <= remapStart2 && offset.original <= t.range[1]
689
- )) {
690
- lastEnd = offset;
691
- }
645
+ if (offset.dist === end && start === end) {
646
+ lastEnd = offset;
692
647
  }
693
648
  break;
694
649
  }
695
650
  }
696
- const remapStart = lastStart.original + (start - lastStart.script);
697
- const remapEnd = lastEnd.original + (end - lastEnd.script);
651
+ const remapStart = lastStart.original + (start - lastStart.dist);
652
+ const remapEnd = lastEnd.original + (end - lastEnd.dist);
653
+ if (remapEnd < remapStart) {
654
+ return [remapEnd, remapStart];
655
+ }
698
656
  return [remapStart, remapEnd];
699
657
  }
700
658
  };
659
+ function remapLocationsAndGetNodeMap(result, restoreTokens, {
660
+ remapLocation,
661
+ removeToken
662
+ }) {
663
+ const traversed = /* @__PURE__ */ new Map();
664
+ traverseNodes(result.ast, {
665
+ visitorKeys: result.visitorKeys,
666
+ enterNode: (node, p) => {
667
+ if (!traversed.has(node)) {
668
+ traversed.set(node, p);
669
+ remapLocation(node);
670
+ }
671
+ },
672
+ leaveNode: (_node) => {
673
+ }
674
+ });
675
+ const tokens = [...restoreTokens];
676
+ for (const token of result.ast.tokens || []) {
677
+ if (removeToken(token)) {
678
+ continue;
679
+ }
680
+ remapLocation(token);
681
+ tokens.push(token);
682
+ }
683
+ result.ast.tokens = tokens;
684
+ for (const token of result.ast.comments || []) {
685
+ remapLocation(token);
686
+ }
687
+ return traversed;
688
+ }
689
+ function restoreNodes(result, nodeMap, restoreNodeProcesses) {
690
+ const context = new RestoreNodeProcessContext(result, nodeMap);
691
+ const restoreNodeProcessesSet = new Set(restoreNodeProcesses);
692
+ for (const [node] of nodeMap) {
693
+ if (!restoreNodeProcessesSet.size) {
694
+ break;
695
+ }
696
+ for (const proc of [...restoreNodeProcessesSet]) {
697
+ if (proc(node, context)) {
698
+ restoreNodeProcessesSet.delete(proc);
699
+ }
700
+ }
701
+ }
702
+ if (context.removeTokens.size) {
703
+ const tokens = result.ast.tokens || [];
704
+ for (let index = tokens.length - 1; index >= 0; index--) {
705
+ const token = tokens[index];
706
+ for (const rt of context.removeTokens) {
707
+ if (rt(token)) {
708
+ tokens.splice(index, 1);
709
+ context.removeTokens.delete(rt);
710
+ if (!context.removeTokens.size) {
711
+ break;
712
+ }
713
+ }
714
+ }
715
+ }
716
+ }
717
+ }
718
+
719
+ // src/context/script.ts
720
+ var VirtualScriptContext = class {
721
+ constructor(ctx) {
722
+ this.script = "";
723
+ this.consumedIndex = 0;
724
+ this.originalCode = ctx.code;
725
+ this.restoreContext = new RestoreContext(ctx);
726
+ }
727
+ skipOriginalOffset(offset) {
728
+ this.consumedIndex += offset;
729
+ }
730
+ skipUntilOriginalOffset(offset) {
731
+ this.consumedIndex = Math.max(offset, this.consumedIndex);
732
+ }
733
+ appendOriginal(index) {
734
+ if (this.consumedIndex >= index) {
735
+ return;
736
+ }
737
+ this.restoreContext.addOffset({
738
+ original: this.consumedIndex,
739
+ dist: this.script.length
740
+ });
741
+ this.script += this.originalCode.slice(this.consumedIndex, index);
742
+ this.consumedIndex = index;
743
+ }
744
+ appendVirtualScript(virtualFragment) {
745
+ const start = this.script.length;
746
+ this.script += virtualFragment;
747
+ this.restoreContext.addVirtualFragmentRange(start, this.script.length);
748
+ }
749
+ };
701
750
 
702
751
  // src/parser/process-template.ts
703
752
  function processTemplate(ctx, resultTemplate) {
704
753
  let uniqueIdSeq = 0;
705
754
  const usedUniqueIds = /* @__PURE__ */ new Set();
706
- const script = new ScriptContext(ctx);
755
+ const script = new VirtualScriptContext(ctx);
707
756
  let fragmentOpened = false;
708
757
  function openRootFragment(startOffset) {
709
- script.appendScript("<>");
758
+ script.appendVirtualScript("<>");
710
759
  fragmentOpened = true;
711
- script.addRestoreNodeProcess((scriptNode, { result }) => {
760
+ script.restoreContext.addRestoreNodeProcess((scriptNode, { result }) => {
712
761
  if (scriptNode.type === AST_NODE_TYPES.ExpressionStatement && scriptNode.expression.type === AST_NODE_TYPES.JSXFragment && scriptNode.range[0] === startOffset && result.ast.body.includes(scriptNode)) {
713
762
  const index = result.ast.body.indexOf(scriptNode);
714
763
  const rootFragment = result.ast.body[index] = scriptNode.expression;
@@ -727,7 +776,7 @@ function processTemplate(ctx, resultTemplate) {
727
776
  if (node.type === "frontmatter") {
728
777
  const start = node.position.start.offset;
729
778
  if (fragmentOpened) {
730
- script.appendScript("</>;");
779
+ script.appendVirtualScript("</>;");
731
780
  fragmentOpened = false;
732
781
  }
733
782
  script.appendOriginal(start);
@@ -736,29 +785,34 @@ function processTemplate(ctx, resultTemplate) {
736
785
  const scriptStart = start + 3;
737
786
  let scriptEnd = end - 3;
738
787
  let endChar;
739
- while (scriptStart < scriptEnd - 1 && (endChar = script.originalCode[scriptEnd - 1]) && !endChar.trim()) {
788
+ while (scriptStart < scriptEnd - 1 && (endChar = ctx.code[scriptEnd - 1]) && !endChar.trim()) {
740
789
  scriptEnd--;
741
790
  }
742
791
  script.appendOriginal(scriptEnd);
743
- script.appendScript("\n;");
792
+ script.appendVirtualScript("\n;");
744
793
  script.skipOriginalOffset(end - scriptEnd);
745
- script.addRestoreNodeProcess((_scriptNode, { result }) => {
746
- for (let index = 0; index < result.ast.body.length; index++) {
747
- const st = result.ast.body[index];
748
- if (st.type === AST_NODE_TYPES.EmptyStatement) {
749
- if (st.range[0] === scriptEnd && st.range[1] <= end) {
750
- result.ast.body.splice(index, 1);
751
- break;
794
+ script.restoreContext.addRestoreNodeProcess(
795
+ (_scriptNode, { result }) => {
796
+ for (let index = 0; index < result.ast.body.length; index++) {
797
+ const st = result.ast.body[index];
798
+ if (st.type === AST_NODE_TYPES.EmptyStatement) {
799
+ if (st.range[0] === scriptEnd && st.range[1] === scriptEnd) {
800
+ result.ast.body.splice(index, 1);
801
+ break;
802
+ }
752
803
  }
753
804
  }
805
+ return true;
754
806
  }
755
- return true;
756
- });
757
- script.addToken(AST_TOKEN_TYPES.Punctuator, [
807
+ );
808
+ script.restoreContext.addToken(AST_TOKEN_TYPES.Punctuator, [
758
809
  node.position.start.offset,
759
810
  node.position.start.offset + 3
760
811
  ]);
761
- script.addToken(AST_TOKEN_TYPES.Punctuator, [end - 3, end]);
812
+ script.restoreContext.addToken(AST_TOKEN_TYPES.Punctuator, [
813
+ end - 3,
814
+ end
815
+ ]);
762
816
  } else if (isTag(node)) {
763
817
  if (parent.type === "expression") {
764
818
  const index = parent.children.indexOf(node);
@@ -768,8 +822,8 @@ function processTemplate(ctx, resultTemplate) {
768
822
  if (after && (isTag(after) || after.type === "comment")) {
769
823
  const start2 = node.position.start.offset;
770
824
  script.appendOriginal(start2);
771
- script.appendScript("<>");
772
- script.addRestoreNodeProcess((scriptNode) => {
825
+ script.appendVirtualScript("<>");
826
+ script.restoreContext.addRestoreNodeProcess((scriptNode) => {
773
827
  if (scriptNode.range[0] === start2 && scriptNode.type === AST_NODE_TYPES.JSXFragment) {
774
828
  delete scriptNode.openingFragment;
775
829
  delete scriptNode.closingFragment;
@@ -801,60 +855,62 @@ function processTemplate(ctx, resultTemplate) {
801
855
  const start2 = attr.position.start.offset;
802
856
  script.appendOriginal(start2 + colonIndex);
803
857
  script.skipOriginalOffset(1);
804
- script.appendScript(`_`);
805
- script.addToken(AST_TOKEN_TYPES.JSXIdentifier, [
858
+ script.appendVirtualScript(`_`);
859
+ script.restoreContext.addToken(AST_TOKEN_TYPES.JSXIdentifier, [
806
860
  start2,
807
861
  start2 + colonIndex
808
862
  ]);
809
- script.addToken(AST_TOKEN_TYPES.Punctuator, [
863
+ script.restoreContext.addToken(AST_TOKEN_TYPES.Punctuator, [
810
864
  start2 + colonIndex,
811
865
  start2 + colonIndex + 1
812
866
  ]);
813
- script.addToken(AST_TOKEN_TYPES.JSXIdentifier, [
867
+ script.restoreContext.addToken(AST_TOKEN_TYPES.JSXIdentifier, [
814
868
  start2 + colonIndex + 1,
815
869
  start2 + attr.name.length
816
870
  ]);
817
- script.addRestoreNodeProcess((scriptNode, context) => {
818
- if (scriptNode.type === AST_NODE_TYPES.JSXAttribute && scriptNode.range[0] === start2) {
819
- const baseNameNode = scriptNode.name;
820
- const nsn = {
821
- ...baseNameNode,
822
- type: AST_NODE_TYPES.JSXNamespacedName,
823
- namespace: {
824
- type: AST_NODE_TYPES.JSXIdentifier,
825
- name: attr.name.slice(0, colonIndex),
826
- ...ctx.getLocations(
827
- baseNameNode.range[0],
828
- baseNameNode.range[0] + colonIndex
829
- )
830
- },
831
- name: {
832
- type: AST_NODE_TYPES.JSXIdentifier,
833
- name: attr.name.slice(colonIndex + 1),
834
- ...ctx.getLocations(
835
- baseNameNode.range[0] + colonIndex + 1,
836
- baseNameNode.range[1]
837
- )
838
- }
839
- };
840
- scriptNode.name = nsn;
841
- nsn.namespace.parent = nsn;
842
- nsn.name.parent = nsn;
843
- context.addRemoveToken(
844
- (token) => token.range[0] === baseNameNode.range[0] && token.range[1] === baseNameNode.range[1]
845
- );
846
- return true;
871
+ script.restoreContext.addRestoreNodeProcess(
872
+ (scriptNode, context) => {
873
+ if (scriptNode.type === AST_NODE_TYPES.JSXAttribute && scriptNode.range[0] === start2) {
874
+ const baseNameNode = scriptNode.name;
875
+ const nsn = {
876
+ ...baseNameNode,
877
+ type: AST_NODE_TYPES.JSXNamespacedName,
878
+ namespace: {
879
+ type: AST_NODE_TYPES.JSXIdentifier,
880
+ name: attr.name.slice(0, colonIndex),
881
+ ...ctx.getLocations(
882
+ baseNameNode.range[0],
883
+ baseNameNode.range[0] + colonIndex
884
+ )
885
+ },
886
+ name: {
887
+ type: AST_NODE_TYPES.JSXIdentifier,
888
+ name: attr.name.slice(colonIndex + 1),
889
+ ...ctx.getLocations(
890
+ baseNameNode.range[0] + colonIndex + 1,
891
+ baseNameNode.range[1]
892
+ )
893
+ }
894
+ };
895
+ scriptNode.name = nsn;
896
+ nsn.namespace.parent = nsn;
897
+ nsn.name.parent = nsn;
898
+ context.addRemoveToken(
899
+ (token) => token.range[0] === baseNameNode.range[0] && token.range[1] === baseNameNode.range[1]
900
+ );
901
+ return true;
902
+ }
903
+ return false;
847
904
  }
848
- return false;
849
- });
905
+ );
850
906
  }
851
907
  }
852
908
  if (attr.kind === "shorthand") {
853
909
  const start2 = attr.position.start.offset;
854
910
  script.appendOriginal(start2);
855
911
  const jsxName = /[\s"'[\]{}]/u.test(attr.name) ? generateUniqueId(attr.name) : attr.name;
856
- script.appendScript(`${jsxName}=`);
857
- script.addRestoreNodeProcess((scriptNode) => {
912
+ script.appendVirtualScript(`${jsxName}=`);
913
+ script.restoreContext.addRestoreNodeProcess((scriptNode) => {
858
914
  if (scriptNode.type === AST_NODE_TYPES.JSXAttribute && scriptNode.range[0] === start2) {
859
915
  const attrNode = scriptNode;
860
916
  attrNode.type = "AstroShorthandAttribute";
@@ -875,10 +931,10 @@ function processTemplate(ctx, resultTemplate) {
875
931
  const start2 = calcAttributeValueStartOffset(attr, ctx);
876
932
  const end = calcAttributeEndOffset(attr, ctx);
877
933
  script.appendOriginal(start2);
878
- script.appendScript("{");
934
+ script.appendVirtualScript("{");
879
935
  script.appendOriginal(end);
880
- script.appendScript("}");
881
- script.addRestoreNodeProcess((scriptNode) => {
936
+ script.appendVirtualScript("}");
937
+ script.restoreContext.addRestoreNodeProcess((scriptNode) => {
882
938
  if (scriptNode.type === AST_NODE_TYPES.JSXAttribute && scriptNode.range[0] === attrStart) {
883
939
  const attrNode = scriptNode;
884
940
  attrNode.type = "AstroTemplateLiteralAttribute";
@@ -891,7 +947,7 @@ function processTemplate(ctx, resultTemplate) {
891
947
  const closing = getSelfClosingTag(node, ctx);
892
948
  if (closing && closing.end === ">") {
893
949
  script.appendOriginal(closing.offset - 1);
894
- script.appendScript("/");
950
+ script.appendVirtualScript("/");
895
951
  }
896
952
  if (node.name === "script" || node.name === "style") {
897
953
  const text = node.children[0];
@@ -900,7 +956,7 @@ function processTemplate(ctx, resultTemplate) {
900
956
  const start2 = text.position.start.offset;
901
957
  script.appendOriginal(start2);
902
958
  script.skipOriginalOffset(text.value.length);
903
- script.addRestoreNodeProcess((scriptNode) => {
959
+ script.restoreContext.addRestoreNodeProcess((scriptNode) => {
904
960
  if (scriptNode.type === AST_NODE_TYPES.JSXElement && scriptNode.range[0] === styleNodeStart) {
905
961
  const textNode = {
906
962
  type: "AstroRawText",
@@ -914,7 +970,7 @@ function processTemplate(ctx, resultTemplate) {
914
970
  }
915
971
  return false;
916
972
  });
917
- script.addToken(AST_TOKEN_TYPES.JSXText, [
973
+ script.restoreContext.addToken(AST_TOKEN_TYPES.JSXText, [
918
974
  start2,
919
975
  start2 + text.value.length
920
976
  ]);
@@ -929,10 +985,10 @@ function processTemplate(ctx, resultTemplate) {
929
985
  openRootFragment(start);
930
986
  }
931
987
  script.appendOriginal(start + 1);
932
- script.appendScript(`></`);
988
+ script.appendVirtualScript(`></`);
933
989
  script.skipOriginalOffset(length - 2);
934
990
  script.appendOriginal(end);
935
- script.addRestoreNodeProcess((scriptNode, context) => {
991
+ script.restoreContext.addRestoreNodeProcess((scriptNode, context) => {
936
992
  if (scriptNode.range[0] === start && scriptNode.type === AST_NODE_TYPES.JSXFragment) {
937
993
  delete scriptNode.children;
938
994
  delete scriptNode.openingFragment;
@@ -951,7 +1007,7 @@ function processTemplate(ctx, resultTemplate) {
951
1007
  }
952
1008
  return false;
953
1009
  });
954
- script.addToken("HTMLComment", [
1010
+ script.restoreContext.addToken("HTMLComment", [
955
1011
  start,
956
1012
  start + length
957
1013
  ]);
@@ -964,10 +1020,10 @@ function processTemplate(ctx, resultTemplate) {
964
1020
  openRootFragment(start);
965
1021
  }
966
1022
  script.appendOriginal(start + 1);
967
- script.appendScript(`></`);
1023
+ script.appendVirtualScript(`></`);
968
1024
  script.skipOriginalOffset(length - 2);
969
1025
  script.appendOriginal(end);
970
- script.addRestoreNodeProcess((scriptNode, context) => {
1026
+ script.restoreContext.addRestoreNodeProcess((scriptNode, context) => {
971
1027
  if (scriptNode.range[0] === start && scriptNode.type === AST_NODE_TYPES.JSXFragment) {
972
1028
  delete scriptNode.children;
973
1029
  delete scriptNode.openingFragment;
@@ -985,7 +1041,10 @@ function processTemplate(ctx, resultTemplate) {
985
1041
  }
986
1042
  return false;
987
1043
  });
988
- script.addToken("HTMLDocType", [start, end]);
1044
+ script.restoreContext.addToken("HTMLDocType", [
1045
+ start,
1046
+ end
1047
+ ]);
989
1048
  } else {
990
1049
  const start = node.position.start.offset;
991
1050
  script.appendOriginal(start);
@@ -1002,15 +1061,17 @@ function processTemplate(ctx, resultTemplate) {
1002
1061
  if (!end) {
1003
1062
  const offset = calcContentEndOffset(node, ctx);
1004
1063
  script.appendOriginal(offset);
1005
- script.appendScript(`</${node.name}>`);
1006
- script.addRestoreNodeProcess((scriptNode, context) => {
1007
- const parent2 = context.getParent(scriptNode);
1008
- if (scriptNode.range[0] === offset && scriptNode.type === AST_NODE_TYPES.JSXClosingElement && parent2.type === AST_NODE_TYPES.JSXElement) {
1009
- parent2.closingElement = null;
1010
- return true;
1064
+ script.appendVirtualScript(`</${node.name}>`);
1065
+ script.restoreContext.addRestoreNodeProcess(
1066
+ (scriptNode, context) => {
1067
+ const parent2 = context.getParent(scriptNode);
1068
+ if (scriptNode.range[0] === offset && scriptNode.type === AST_NODE_TYPES.JSXClosingElement && parent2.type === AST_NODE_TYPES.JSXElement) {
1069
+ parent2.closingElement = null;
1070
+ return true;
1071
+ }
1072
+ return false;
1011
1073
  }
1012
- return false;
1013
- });
1074
+ );
1014
1075
  }
1015
1076
  }
1016
1077
  }
@@ -1022,7 +1083,7 @@ function processTemplate(ctx, resultTemplate) {
1022
1083
  if (before && (isTag(before) || before.type === "comment")) {
1023
1084
  const end = getEndOffset(node, ctx);
1024
1085
  script.appendOriginal(end);
1025
- script.appendScript("</>");
1086
+ script.appendVirtualScript("</>");
1026
1087
  }
1027
1088
  }
1028
1089
  }
@@ -1032,7 +1093,7 @@ function processTemplate(ctx, resultTemplate) {
1032
1093
  const last = resultTemplate.ast.children[resultTemplate.ast.children.length - 1];
1033
1094
  const end = getEndOffset(last, ctx);
1034
1095
  script.appendOriginal(end);
1035
- script.appendScript("</>");
1096
+ script.appendVirtualScript("</>;");
1036
1097
  }
1037
1098
  script.appendOriginal(ctx.code.length);
1038
1099
  return script;
@@ -1046,13 +1107,54 @@ function processTemplate(ctx, resultTemplate) {
1046
1107
  }
1047
1108
  }
1048
1109
 
1110
+ // src/util/index.ts
1111
+ function sortedLastIndex(array, compare) {
1112
+ let lower = 0;
1113
+ let upper = array.length;
1114
+ while (lower < upper) {
1115
+ const mid = Math.floor(lower + (upper - lower) / 2);
1116
+ const target = compare(array[mid]);
1117
+ if (target < 0) {
1118
+ lower = mid + 1;
1119
+ } else if (target > 0) {
1120
+ upper = mid;
1121
+ } else {
1122
+ return mid + 1;
1123
+ }
1124
+ }
1125
+ return upper;
1126
+ }
1127
+ function addElementToSortedArray(array, element, compare) {
1128
+ const index = sortedLastIndex(array, (target) => compare(target, element));
1129
+ array.splice(index, 0, element);
1130
+ }
1131
+ function addElementsToSortedArray(array, elements, compare) {
1132
+ if (!elements.length) {
1133
+ return;
1134
+ }
1135
+ let last = elements[0];
1136
+ let index = sortedLastIndex(array, (target) => compare(target, last));
1137
+ for (const element of elements) {
1138
+ if (compare(last, element) > 0) {
1139
+ index = sortedLastIndex(array, (target) => compare(target, element));
1140
+ }
1141
+ let e = array[index];
1142
+ while (e && compare(e, element) <= 0) {
1143
+ e = array[++index];
1144
+ }
1145
+ array.splice(index, 0, element);
1146
+ last = element;
1147
+ }
1148
+ }
1149
+
1049
1150
  // src/context/index.ts
1050
1151
  var Context = class {
1051
- constructor(code) {
1152
+ constructor(code, filePath) {
1052
1153
  this.locsMap = /* @__PURE__ */ new Map();
1053
1154
  this.state = {};
1054
1155
  this.locs = new LinesAndColumns(code);
1055
1156
  this.code = code;
1157
+ this.filePath = filePath;
1056
1158
  }
1057
1159
  getLocFromIndex(index) {
1058
1160
  let loc = this.locsMap.get(index);
@@ -1124,7 +1226,10 @@ ${next}`;
1124
1226
  this.normalizedLineFeed = new NormalizedLineFeed(normalizedCode, crs);
1125
1227
  }
1126
1228
  getLocFromIndex(index) {
1127
- const lineNumber = sortedLastIndex(this.lineStartIndices, index);
1229
+ const lineNumber = sortedLastIndex(
1230
+ this.lineStartIndices,
1231
+ (target) => target - index
1232
+ );
1128
1233
  return {
1129
1234
  line: lineNumber,
1130
1235
  column: index - this.lineStartIndices[lineNumber - 1]
@@ -1168,22 +1273,6 @@ var NormalizedLineFeed = class {
1168
1273
  }
1169
1274
  }
1170
1275
  };
1171
- function sortedLastIndex(array, value) {
1172
- let lower = 0;
1173
- let upper = array.length;
1174
- while (lower < upper) {
1175
- const mid = Math.floor(lower + (upper - lower) / 2);
1176
- const target = array[mid];
1177
- if (target < value) {
1178
- lower = mid + 1;
1179
- } else if (target > value) {
1180
- upper = mid;
1181
- } else {
1182
- return mid + 1;
1183
- }
1184
- }
1185
- return upper;
1186
- }
1187
1276
 
1188
1277
  // src/parser/astro-parser/parse.ts
1189
1278
  import * as service from "astrojs-compiler-sync";
@@ -1437,14 +1526,14 @@ var LruCache = class extends Map {
1437
1526
 
1438
1527
  // src/parser/template.ts
1439
1528
  var lruCache = new LruCache(5);
1440
- function parseTemplate(code) {
1529
+ function parseTemplate(code, filePath) {
1441
1530
  const cache = lruCache.get(code);
1442
1531
  if (cache) {
1443
1532
  return cache;
1444
1533
  }
1445
- const ctx = new Context(code);
1534
+ const ctx = new Context(code, filePath);
1446
1535
  const normalized = ctx.locs.getNormalizedLineFeed();
1447
- const ctxForAstro = normalized.needRemap ? new Context(normalized.code) : ctx;
1536
+ const ctxForAstro = normalized.needRemap ? new Context(normalized.code, filePath) : ctx;
1448
1537
  try {
1449
1538
  const result = parse2((normalized == null ? void 0 : normalized.code) ?? code, ctxForAstro);
1450
1539
  if (normalized.needRemap) {
@@ -1579,6 +1668,10 @@ function getParser(attrs, parser) {
1579
1668
  }
1580
1669
 
1581
1670
  // src/context/parser-options.ts
1671
+ var TS_PARSER_NAMES = [
1672
+ "@typescript-eslint/parser",
1673
+ "typescript-eslint-parser-for-extra-files"
1674
+ ];
1582
1675
  var ParserOptionsContext = class {
1583
1676
  constructor(options) {
1584
1677
  this.state = {};
@@ -1613,20 +1706,22 @@ var ParserOptionsContext = class {
1613
1706
  return this.state.isTypeScript;
1614
1707
  }
1615
1708
  const parserValue = getParserForLang({}, (_a = this.parserOptions) == null ? void 0 : _a.parser);
1616
- if (maybeTSESLintParserObject(parserValue) || parserValue === "@typescript-eslint/parser") {
1617
- return this.state.isTypeScript = true;
1618
- }
1619
1709
  if (typeof parserValue !== "string") {
1620
- return this.state.isTypeScript = false;
1710
+ return this.state.isTypeScript = maybeTSESLintParserObject(parserValue) || isTSESLintParserObject(parserValue);
1621
1711
  }
1622
1712
  const parserName = parserValue;
1623
- if (parserName.includes("@typescript-eslint/parser")) {
1713
+ if (TS_PARSER_NAMES.includes(parserName)) {
1714
+ return this.state.isTypeScript = true;
1715
+ }
1716
+ if (TS_PARSER_NAMES.some((nm) => parserName.includes(nm))) {
1624
1717
  let targetPath = parserName;
1625
1718
  while (targetPath) {
1626
1719
  const pkgPath = path3.join(targetPath, "package.json");
1627
1720
  if (fs2.existsSync(pkgPath)) {
1628
1721
  try {
1629
- return this.state.isTypeScript = ((_b = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"))) == null ? void 0 : _b.name) === "@typescript-eslint/parser";
1722
+ return this.state.isTypeScript = TS_PARSER_NAMES.includes(
1723
+ (_b = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"))) == null ? void 0 : _b.name
1724
+ );
1630
1725
  } catch {
1631
1726
  return this.state.isTypeScript = false;
1632
1727
  }
@@ -1642,13 +1737,295 @@ var ParserOptionsContext = class {
1642
1737
  }
1643
1738
  };
1644
1739
 
1740
+ // src/parser/scope/index.ts
1741
+ import {
1742
+ Reference as ReferenceClass,
1743
+ Variable as VariableClass
1744
+ } from "eslint-scope";
1745
+ function getProgramScope(scopeManager) {
1746
+ const globalScope = scopeManager.globalScope;
1747
+ return globalScope.childScopes.find((s) => s.type === "module") || globalScope;
1748
+ }
1749
+ function removeAllScopeAndVariableAndReference(target, info) {
1750
+ const targetScopes = /* @__PURE__ */ new Set();
1751
+ traverseNodes(target, {
1752
+ visitorKeys: info.visitorKeys,
1753
+ enterNode(node) {
1754
+ const scope = info.scopeManager.acquire(node);
1755
+ if (scope) {
1756
+ targetScopes.add(scope);
1757
+ return;
1758
+ }
1759
+ if (node.type === "Identifier") {
1760
+ let scope2 = getInnermostScopeFromNode(info.scopeManager, node);
1761
+ while (scope2 && scope2.block.type !== "Program" && target.range[0] <= scope2.block.range[0] && scope2.block.range[1] <= target.range[1]) {
1762
+ scope2 = scope2.upper;
1763
+ }
1764
+ if (targetScopes.has(scope2)) {
1765
+ return;
1766
+ }
1767
+ removeIdentifierVariable(node, scope2);
1768
+ removeIdentifierReference(node, scope2);
1769
+ }
1770
+ },
1771
+ leaveNode() {
1772
+ }
1773
+ });
1774
+ for (const scope of targetScopes) {
1775
+ removeScope(info.scopeManager, scope);
1776
+ }
1777
+ }
1778
+ function addVirtualReference(node, variable, scope, readWrite) {
1779
+ const reference = new ReferenceClass();
1780
+ reference.astroVirtualReference = true;
1781
+ reference.from = scope;
1782
+ reference.identifier = node;
1783
+ reference.isWrite = () => Boolean(readWrite.write);
1784
+ reference.isWriteOnly = () => Boolean(readWrite.write) && !readWrite.read;
1785
+ reference.isRead = () => Boolean(readWrite.read);
1786
+ reference.isReadOnly = () => Boolean(readWrite.read) && !readWrite.write;
1787
+ reference.isReadWrite = () => Boolean(readWrite.read && readWrite.write);
1788
+ addReference(variable.references, reference);
1789
+ reference.resolved = variable;
1790
+ return reference;
1791
+ }
1792
+ function addGlobalVariable(reference, scopeManager) {
1793
+ const globalScope = scopeManager.globalScope;
1794
+ const name = reference.identifier.name;
1795
+ let variable = globalScope.set.get(name);
1796
+ if (!variable) {
1797
+ variable = new VariableClass();
1798
+ variable.name = name;
1799
+ variable.scope = globalScope;
1800
+ globalScope.variables.push(variable);
1801
+ globalScope.set.set(name, variable);
1802
+ }
1803
+ reference.resolved = variable;
1804
+ variable.references.push(reference);
1805
+ return variable;
1806
+ }
1807
+ function removeReferenceFromThrough(reference, baseScope) {
1808
+ const variable = reference.resolved;
1809
+ const name = reference.identifier.name;
1810
+ let scope = baseScope;
1811
+ while (scope) {
1812
+ for (const ref of [...scope.through]) {
1813
+ if (reference === ref) {
1814
+ scope.through.splice(scope.through.indexOf(ref), 1);
1815
+ } else if (ref.identifier.name === name) {
1816
+ ref.resolved = variable;
1817
+ if (!variable.references.includes(ref)) {
1818
+ addReference(variable.references, ref);
1819
+ }
1820
+ scope.through.splice(scope.through.indexOf(ref), 1);
1821
+ }
1822
+ }
1823
+ scope = scope.upper;
1824
+ }
1825
+ }
1826
+ function removeScope(scopeManager, scope) {
1827
+ for (const childScope of scope.childScopes) {
1828
+ removeScope(scopeManager, childScope);
1829
+ }
1830
+ while (scope.references[0]) {
1831
+ removeReference(scope.references[0], scope);
1832
+ }
1833
+ const upper = scope.upper;
1834
+ if (upper) {
1835
+ const index2 = upper.childScopes.indexOf(scope);
1836
+ if (index2 >= 0) {
1837
+ upper.childScopes.splice(index2, 1);
1838
+ }
1839
+ }
1840
+ const index = scopeManager.scopes.indexOf(scope);
1841
+ if (index >= 0) {
1842
+ scopeManager.scopes.splice(index, 1);
1843
+ }
1844
+ }
1845
+ function removeReference(reference, baseScope) {
1846
+ if (reference.resolved) {
1847
+ if (reference.resolved.defs.some((d) => d.name === reference.identifier)) {
1848
+ const varIndex = baseScope.variables.indexOf(reference.resolved);
1849
+ if (varIndex >= 0) {
1850
+ baseScope.variables.splice(varIndex, 1);
1851
+ }
1852
+ const name = reference.identifier.name;
1853
+ if (reference.resolved === baseScope.set.get(name)) {
1854
+ baseScope.set.delete(name);
1855
+ }
1856
+ } else {
1857
+ const refIndex = reference.resolved.references.indexOf(reference);
1858
+ if (refIndex >= 0) {
1859
+ reference.resolved.references.splice(refIndex, 1);
1860
+ }
1861
+ }
1862
+ }
1863
+ let scope = baseScope;
1864
+ while (scope) {
1865
+ const refIndex = scope.references.indexOf(reference);
1866
+ if (refIndex >= 0) {
1867
+ scope.references.splice(refIndex, 1);
1868
+ }
1869
+ const throughIndex = scope.through.indexOf(reference);
1870
+ if (throughIndex >= 0) {
1871
+ scope.through.splice(throughIndex, 1);
1872
+ }
1873
+ scope = scope.upper;
1874
+ }
1875
+ }
1876
+ function removeIdentifierVariable(node, scope) {
1877
+ for (let varIndex = 0; varIndex < scope.variables.length; varIndex++) {
1878
+ const variable = scope.variables[varIndex];
1879
+ const defIndex = variable.defs.findIndex((def) => def.name === node);
1880
+ if (defIndex < 0) {
1881
+ continue;
1882
+ }
1883
+ variable.defs.splice(defIndex, 1);
1884
+ if (variable.defs.length === 0) {
1885
+ referencesToThrough(variable.references, scope);
1886
+ variable.references.forEach((r) => {
1887
+ if (r.init)
1888
+ r.init = false;
1889
+ r.resolved = null;
1890
+ });
1891
+ scope.variables.splice(varIndex, 1);
1892
+ const name = node.name;
1893
+ if (variable === scope.set.get(name)) {
1894
+ scope.set.delete(name);
1895
+ }
1896
+ } else {
1897
+ const idIndex = variable.identifiers.indexOf(node);
1898
+ if (idIndex >= 0) {
1899
+ variable.identifiers.splice(idIndex, 1);
1900
+ }
1901
+ }
1902
+ return;
1903
+ }
1904
+ }
1905
+ function removeIdentifierReference(node, scope) {
1906
+ const reference = scope.references.find((ref) => ref.identifier === node);
1907
+ if (reference) {
1908
+ removeReference(reference, scope);
1909
+ return true;
1910
+ }
1911
+ const location = node.range[0];
1912
+ const pendingScopes = [];
1913
+ for (const childScope of scope.childScopes) {
1914
+ const range = childScope.block.range;
1915
+ if (range[0] <= location && location < range[1]) {
1916
+ if (removeIdentifierReference(node, childScope)) {
1917
+ return true;
1918
+ }
1919
+ } else {
1920
+ pendingScopes.push(childScope);
1921
+ }
1922
+ }
1923
+ for (const childScope of pendingScopes) {
1924
+ if (removeIdentifierReference(node, childScope)) {
1925
+ return true;
1926
+ }
1927
+ }
1928
+ return false;
1929
+ }
1930
+ function getInnermostScopeFromNode(scopeManager, currentNode) {
1931
+ return getInnermostScope(
1932
+ getScopeFromNode(scopeManager, currentNode),
1933
+ currentNode
1934
+ );
1935
+ }
1936
+ function getScopeFromNode(scopeManager, currentNode) {
1937
+ let node = currentNode;
1938
+ for (; node; node = node.parent || null) {
1939
+ const scope = scopeManager.acquire(node, false);
1940
+ if (scope) {
1941
+ if (scope.type === "function-expression-name") {
1942
+ return scope.childScopes[0];
1943
+ }
1944
+ if (scope.type === "global" && node.type === "Program" && node.sourceType === "module") {
1945
+ return scope.childScopes.find((s) => s.type === "module") || scope;
1946
+ }
1947
+ return scope;
1948
+ }
1949
+ }
1950
+ const global = scopeManager.globalScope;
1951
+ return global;
1952
+ }
1953
+ function getInnermostScope(initialScope, node) {
1954
+ for (const childScope of initialScope.childScopes) {
1955
+ const range = childScope.block.range;
1956
+ if (range[0] <= node.range[0] && node.range[1] <= range[1]) {
1957
+ return getInnermostScope(childScope, node);
1958
+ }
1959
+ }
1960
+ return initialScope;
1961
+ }
1962
+ function referencesToThrough(references, baseScope) {
1963
+ let scope = baseScope;
1964
+ while (scope) {
1965
+ addAllReferences(scope.through, references);
1966
+ scope = scope.upper;
1967
+ }
1968
+ }
1969
+ function addAllReferences(list, elements) {
1970
+ addElementsToSortedArray(
1971
+ list,
1972
+ elements,
1973
+ (a, b) => a.identifier.range[0] - b.identifier.range[0]
1974
+ );
1975
+ }
1976
+ function addReference(list, reference) {
1977
+ addElementToSortedArray(
1978
+ list,
1979
+ reference,
1980
+ (a, b) => a.identifier.range[0] - b.identifier.range[0]
1981
+ );
1982
+ }
1983
+
1645
1984
  // src/parser/index.ts
1646
1985
  function parseForESLint(code, options) {
1647
- const { result: resultTemplate, context: ctx } = parseTemplate(code);
1986
+ const { result: resultTemplate, context: ctx } = parseTemplate(
1987
+ code,
1988
+ (options == null ? void 0 : options.filePath) ?? "<input>"
1989
+ );
1648
1990
  const scriptContext = processTemplate(ctx, resultTemplate);
1649
1991
  const parserOptions = new ParserOptionsContext(options);
1992
+ if (parserOptions.isTypeScript() && /\bAstro\b/u.test(code)) {
1993
+ scriptContext.appendVirtualScript(
1994
+ `declare const Astro: Readonly<import('astro').AstroGlobal<Props>>;`
1995
+ );
1996
+ scriptContext.restoreContext.addRestoreNodeProcess(
1997
+ (_scriptNode, { result }) => {
1998
+ const declareNode = result.ast.body.pop();
1999
+ const scopeManager = result.scopeManager;
2000
+ if (scopeManager) {
2001
+ removeAllScopeAndVariableAndReference(declareNode, {
2002
+ visitorKeys: result.visitorKeys,
2003
+ scopeManager
2004
+ });
2005
+ const scope = getProgramScope(scopeManager);
2006
+ const propsVariable = scope.set.get("Props");
2007
+ if (propsVariable) {
2008
+ addVirtualReference(
2009
+ propsVariable.identifiers[0],
2010
+ propsVariable,
2011
+ scope,
2012
+ {}
2013
+ );
2014
+ }
2015
+ const astroGlobalReferences = scope.through.filter(
2016
+ (ref) => ref.identifier.name === "Astro" || ref.identifier.name === "Fragment"
2017
+ );
2018
+ for (const astroGlobalReference of astroGlobalReferences) {
2019
+ addGlobalVariable(astroGlobalReference, scopeManager);
2020
+ removeReferenceFromThrough(astroGlobalReference, scope);
2021
+ }
2022
+ }
2023
+ return true;
2024
+ }
2025
+ );
2026
+ }
1650
2027
  const resultScript = parseScript(scriptContext.script, ctx, parserOptions);
1651
- scriptContext.restore(resultScript);
2028
+ scriptContext.restoreContext.restore(resultScript);
1652
2029
  sort(resultScript.ast.comments);
1653
2030
  sort(resultScript.ast.tokens);
1654
2031
  extractTokens(resultScript, ctx);