astro-eslint-parser 0.7.3 → 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.js CHANGED
@@ -122,6 +122,19 @@ function isBasicParserObject(value) {
122
122
  function maybeTSESLintParserObject(value) {
123
123
  return isEnhancedParserObject(value) && isBasicParserObject(value) && typeof value.createProgram === "function" && typeof value.clearCaches === "function" && typeof value.version === "string";
124
124
  }
125
+ function isTSESLintParserObject(value) {
126
+ if (!isEnhancedParserObject(value))
127
+ return false;
128
+ try {
129
+ const result = value.parseForESLint("", {});
130
+ const services = result.services;
131
+ return Boolean(
132
+ services && services.esTreeNodeToTSNodeMap && services.tsNodeToESTreeNodeMap && services.program
133
+ );
134
+ } catch {
135
+ return false;
136
+ }
137
+ }
125
138
 
126
139
  // src/parser/script.ts
127
140
  function parseScript(code, _ctx, parserOptions) {
@@ -554,51 +567,41 @@ function traverseNodes(node, visitor) {
554
567
  traverse(node, null, visitor);
555
568
  }
556
569
 
557
- // src/context/script.ts
570
+ // src/context/restore.ts
558
571
  var RestoreNodeProcessContext = class {
559
- constructor(result, parentMap) {
572
+ constructor(result, nodeMap) {
560
573
  this.removeTokens = /* @__PURE__ */ new Set();
561
574
  this.result = result;
562
- this.parentMap = parentMap;
575
+ this.nodeMap = nodeMap;
563
576
  }
564
577
  addRemoveToken(test) {
565
578
  this.removeTokens.add(test);
566
579
  }
567
580
  getParent(node) {
568
- return this.parentMap.get(node) || null;
581
+ return this.nodeMap.get(node) || null;
569
582
  }
570
583
  };
571
- var ScriptContext = class {
584
+ var RestoreContext = class {
572
585
  constructor(ctx) {
573
- this.script = "";
574
- this.consumedIndex = 0;
575
586
  this.offsets = [];
576
- this.fragments = [];
577
- this.tokens = [];
587
+ this.virtualFragments = [];
578
588
  this.restoreNodeProcesses = [];
589
+ this.tokens = [];
579
590
  this.ctx = ctx;
580
591
  }
581
- get originalCode() {
582
- return this.ctx.code;
592
+ addRestoreNodeProcess(process2) {
593
+ this.restoreNodeProcesses.push(process2);
583
594
  }
584
- skipOriginalOffset(offset) {
585
- this.consumedIndex += offset;
595
+ addOffset(offset) {
596
+ this.offsets.push(offset);
586
597
  }
587
- appendOriginal(index) {
588
- if (this.consumedIndex >= index) {
598
+ addVirtualFragmentRange(start, end) {
599
+ const peek = this.virtualFragments[this.virtualFragments.length - 1];
600
+ if (peek && peek.end === start) {
601
+ peek.end = end;
589
602
  return;
590
603
  }
591
- this.offsets.push({
592
- original: this.consumedIndex,
593
- script: this.script.length
594
- });
595
- this.script += this.ctx.code.slice(this.consumedIndex, index);
596
- this.consumedIndex = index;
597
- }
598
- appendScript(fragment) {
599
- const start = this.script.length;
600
- this.script += fragment;
601
- this.fragments.push({ start, end: this.script.length });
604
+ this.virtualFragments.push({ start, end });
602
605
  }
603
606
  addToken(type, range) {
604
607
  if (range[0] >= range[1]) {
@@ -606,63 +609,17 @@ var ScriptContext = class {
606
609
  }
607
610
  this.tokens.push(this.ctx.buildToken(type, range));
608
611
  }
609
- addRestoreNodeProcess(process2) {
610
- this.restoreNodeProcesses.push(process2);
611
- }
612
612
  restore(result) {
613
613
  var _a, _b;
614
- const traversed = /* @__PURE__ */ new Map();
615
- traverseNodes(result.ast, {
616
- visitorKeys: result.visitorKeys,
617
- enterNode: (node, p) => {
618
- if (!traversed.has(node)) {
619
- traversed.set(node, p);
620
- this.remapLocation(node);
621
- }
622
- },
623
- leaveNode: (_node) => {
624
- }
625
- });
626
- const tokens = [...this.tokens];
627
- for (const token of result.ast.tokens || []) {
628
- if (this.fragments.some(
614
+ const nodeMap = remapLocationsAndGetNodeMap(result, this.tokens, {
615
+ remapLocation: (n) => this.remapLocation(n),
616
+ removeToken: (token) => this.virtualFragments.some(
629
617
  (f) => f.start <= token.range[0] && token.range[1] <= f.end
630
- )) {
631
- continue;
632
- }
633
- this.remapLocation(token);
634
- tokens.push(token);
635
- }
636
- result.ast.tokens = tokens;
637
- for (const token of result.ast.comments || []) {
638
- this.remapLocation(token);
639
- }
640
- const context = new RestoreNodeProcessContext(result, traversed);
641
- let restoreNodeProcesses = this.restoreNodeProcesses;
642
- for (const [node, parent] of traversed) {
643
- if (!parent)
644
- continue;
645
- restoreNodeProcesses = restoreNodeProcesses.filter(
646
- (proc) => !proc(node, context)
647
- );
648
- }
649
- if (context.removeTokens.size) {
650
- const tokens2 = result.ast.tokens || [];
651
- for (let index = tokens2.length - 1; index >= 0; index--) {
652
- const token = tokens2[index];
653
- for (const rt of context.removeTokens) {
654
- if (rt(token)) {
655
- tokens2.splice(index, 1);
656
- context.removeTokens.delete(rt);
657
- if (!context.removeTokens.size) {
658
- break;
659
- }
660
- }
661
- }
662
- }
663
- }
618
+ )
619
+ });
620
+ restoreNodes(result, nodeMap, this.restoreNodeProcesses);
664
621
  const firstOffset = Math.min(
665
- ...[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])
622
+ ...[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])
666
623
  );
667
624
  if (firstOffset < result.ast.range[0]) {
668
625
  result.ast.range[0] = firstOffset;
@@ -671,17 +628,20 @@ var ScriptContext = class {
671
628
  }
672
629
  remapLocation(node) {
673
630
  let [start, end] = node.range;
674
- const startFragment = this.fragments.find(
631
+ const startFragment = this.virtualFragments.find(
675
632
  (f) => f.start <= start && start < f.end
676
633
  );
677
634
  if (startFragment) {
678
635
  start = startFragment.end;
679
636
  }
680
- const endFragment = this.fragments.find(
637
+ const endFragment = this.virtualFragments.find(
681
638
  (f) => f.start < end && end <= f.end
682
639
  );
683
640
  if (endFragment) {
684
641
  end = endFragment.start;
642
+ if (startFragment === endFragment) {
643
+ start = startFragment.start;
644
+ }
685
645
  }
686
646
  if (end < start) {
687
647
  const w = start;
@@ -705,39 +665,128 @@ var ScriptContext = class {
705
665
  let lastStart = this.offsets[0];
706
666
  let lastEnd = this.offsets[0];
707
667
  for (const offset of this.offsets) {
708
- if (offset.script <= start) {
668
+ if (offset.dist <= start) {
709
669
  lastStart = offset;
710
670
  }
711
- if (offset.script < end) {
671
+ if (offset.dist < end) {
712
672
  lastEnd = offset;
713
673
  } else {
714
- if (offset.script === end) {
715
- const remapStart2 = lastStart.original + (start - lastStart.script);
716
- if (this.tokens.some(
717
- (t) => t.range[0] <= remapStart2 && offset.original <= t.range[1]
718
- )) {
719
- lastEnd = offset;
720
- }
674
+ if (offset.dist === end && start === end) {
675
+ lastEnd = offset;
721
676
  }
722
677
  break;
723
678
  }
724
679
  }
725
- const remapStart = lastStart.original + (start - lastStart.script);
726
- const remapEnd = lastEnd.original + (end - lastEnd.script);
680
+ const remapStart = lastStart.original + (start - lastStart.dist);
681
+ const remapEnd = lastEnd.original + (end - lastEnd.dist);
682
+ if (remapEnd < remapStart) {
683
+ return [remapEnd, remapStart];
684
+ }
727
685
  return [remapStart, remapEnd];
728
686
  }
729
687
  };
688
+ function remapLocationsAndGetNodeMap(result, restoreTokens, {
689
+ remapLocation,
690
+ removeToken
691
+ }) {
692
+ const traversed = /* @__PURE__ */ new Map();
693
+ traverseNodes(result.ast, {
694
+ visitorKeys: result.visitorKeys,
695
+ enterNode: (node, p) => {
696
+ if (!traversed.has(node)) {
697
+ traversed.set(node, p);
698
+ remapLocation(node);
699
+ }
700
+ },
701
+ leaveNode: (_node) => {
702
+ }
703
+ });
704
+ const tokens = [...restoreTokens];
705
+ for (const token of result.ast.tokens || []) {
706
+ if (removeToken(token)) {
707
+ continue;
708
+ }
709
+ remapLocation(token);
710
+ tokens.push(token);
711
+ }
712
+ result.ast.tokens = tokens;
713
+ for (const token of result.ast.comments || []) {
714
+ remapLocation(token);
715
+ }
716
+ return traversed;
717
+ }
718
+ function restoreNodes(result, nodeMap, restoreNodeProcesses) {
719
+ const context = new RestoreNodeProcessContext(result, nodeMap);
720
+ const restoreNodeProcessesSet = new Set(restoreNodeProcesses);
721
+ for (const [node] of nodeMap) {
722
+ if (!restoreNodeProcessesSet.size) {
723
+ break;
724
+ }
725
+ for (const proc of [...restoreNodeProcessesSet]) {
726
+ if (proc(node, context)) {
727
+ restoreNodeProcessesSet.delete(proc);
728
+ }
729
+ }
730
+ }
731
+ if (context.removeTokens.size) {
732
+ const tokens = result.ast.tokens || [];
733
+ for (let index = tokens.length - 1; index >= 0; index--) {
734
+ const token = tokens[index];
735
+ for (const rt of context.removeTokens) {
736
+ if (rt(token)) {
737
+ tokens.splice(index, 1);
738
+ context.removeTokens.delete(rt);
739
+ if (!context.removeTokens.size) {
740
+ break;
741
+ }
742
+ }
743
+ }
744
+ }
745
+ }
746
+ }
747
+
748
+ // src/context/script.ts
749
+ var VirtualScriptContext = class {
750
+ constructor(ctx) {
751
+ this.script = "";
752
+ this.consumedIndex = 0;
753
+ this.originalCode = ctx.code;
754
+ this.restoreContext = new RestoreContext(ctx);
755
+ }
756
+ skipOriginalOffset(offset) {
757
+ this.consumedIndex += offset;
758
+ }
759
+ skipUntilOriginalOffset(offset) {
760
+ this.consumedIndex = Math.max(offset, this.consumedIndex);
761
+ }
762
+ appendOriginal(index) {
763
+ if (this.consumedIndex >= index) {
764
+ return;
765
+ }
766
+ this.restoreContext.addOffset({
767
+ original: this.consumedIndex,
768
+ dist: this.script.length
769
+ });
770
+ this.script += this.originalCode.slice(this.consumedIndex, index);
771
+ this.consumedIndex = index;
772
+ }
773
+ appendVirtualScript(virtualFragment) {
774
+ const start = this.script.length;
775
+ this.script += virtualFragment;
776
+ this.restoreContext.addVirtualFragmentRange(start, this.script.length);
777
+ }
778
+ };
730
779
 
731
780
  // src/parser/process-template.ts
732
781
  function processTemplate(ctx, resultTemplate) {
733
782
  let uniqueIdSeq = 0;
734
783
  const usedUniqueIds = /* @__PURE__ */ new Set();
735
- const script = new ScriptContext(ctx);
784
+ const script = new VirtualScriptContext(ctx);
736
785
  let fragmentOpened = false;
737
786
  function openRootFragment(startOffset) {
738
- script.appendScript("<>");
787
+ script.appendVirtualScript("<>");
739
788
  fragmentOpened = true;
740
- script.addRestoreNodeProcess((scriptNode, { result }) => {
789
+ script.restoreContext.addRestoreNodeProcess((scriptNode, { result }) => {
741
790
  if (scriptNode.type === import_types.AST_NODE_TYPES.ExpressionStatement && scriptNode.expression.type === import_types.AST_NODE_TYPES.JSXFragment && scriptNode.range[0] === startOffset && result.ast.body.includes(scriptNode)) {
742
791
  const index = result.ast.body.indexOf(scriptNode);
743
792
  const rootFragment = result.ast.body[index] = scriptNode.expression;
@@ -756,7 +805,7 @@ function processTemplate(ctx, resultTemplate) {
756
805
  if (node.type === "frontmatter") {
757
806
  const start = node.position.start.offset;
758
807
  if (fragmentOpened) {
759
- script.appendScript("</>;");
808
+ script.appendVirtualScript("</>;");
760
809
  fragmentOpened = false;
761
810
  }
762
811
  script.appendOriginal(start);
@@ -765,29 +814,34 @@ function processTemplate(ctx, resultTemplate) {
765
814
  const scriptStart = start + 3;
766
815
  let scriptEnd = end - 3;
767
816
  let endChar;
768
- while (scriptStart < scriptEnd - 1 && (endChar = script.originalCode[scriptEnd - 1]) && !endChar.trim()) {
817
+ while (scriptStart < scriptEnd - 1 && (endChar = ctx.code[scriptEnd - 1]) && !endChar.trim()) {
769
818
  scriptEnd--;
770
819
  }
771
820
  script.appendOriginal(scriptEnd);
772
- script.appendScript("\n;");
821
+ script.appendVirtualScript("\n;");
773
822
  script.skipOriginalOffset(end - scriptEnd);
774
- script.addRestoreNodeProcess((_scriptNode, { result }) => {
775
- for (let index = 0; index < result.ast.body.length; index++) {
776
- const st = result.ast.body[index];
777
- if (st.type === import_types.AST_NODE_TYPES.EmptyStatement) {
778
- if (st.range[0] === scriptEnd && st.range[1] <= end) {
779
- result.ast.body.splice(index, 1);
780
- break;
823
+ script.restoreContext.addRestoreNodeProcess(
824
+ (_scriptNode, { result }) => {
825
+ for (let index = 0; index < result.ast.body.length; index++) {
826
+ const st = result.ast.body[index];
827
+ if (st.type === import_types.AST_NODE_TYPES.EmptyStatement) {
828
+ if (st.range[0] === scriptEnd && st.range[1] === scriptEnd) {
829
+ result.ast.body.splice(index, 1);
830
+ break;
831
+ }
781
832
  }
782
833
  }
834
+ return true;
783
835
  }
784
- return true;
785
- });
786
- script.addToken(import_types.AST_TOKEN_TYPES.Punctuator, [
836
+ );
837
+ script.restoreContext.addToken(import_types.AST_TOKEN_TYPES.Punctuator, [
787
838
  node.position.start.offset,
788
839
  node.position.start.offset + 3
789
840
  ]);
790
- script.addToken(import_types.AST_TOKEN_TYPES.Punctuator, [end - 3, end]);
841
+ script.restoreContext.addToken(import_types.AST_TOKEN_TYPES.Punctuator, [
842
+ end - 3,
843
+ end
844
+ ]);
791
845
  } else if (isTag(node)) {
792
846
  if (parent.type === "expression") {
793
847
  const index = parent.children.indexOf(node);
@@ -797,8 +851,8 @@ function processTemplate(ctx, resultTemplate) {
797
851
  if (after && (isTag(after) || after.type === "comment")) {
798
852
  const start2 = node.position.start.offset;
799
853
  script.appendOriginal(start2);
800
- script.appendScript("<>");
801
- script.addRestoreNodeProcess((scriptNode) => {
854
+ script.appendVirtualScript("<>");
855
+ script.restoreContext.addRestoreNodeProcess((scriptNode) => {
802
856
  if (scriptNode.range[0] === start2 && scriptNode.type === import_types.AST_NODE_TYPES.JSXFragment) {
803
857
  delete scriptNode.openingFragment;
804
858
  delete scriptNode.closingFragment;
@@ -830,60 +884,62 @@ function processTemplate(ctx, resultTemplate) {
830
884
  const start2 = attr.position.start.offset;
831
885
  script.appendOriginal(start2 + colonIndex);
832
886
  script.skipOriginalOffset(1);
833
- script.appendScript(`_`);
834
- script.addToken(import_types.AST_TOKEN_TYPES.JSXIdentifier, [
887
+ script.appendVirtualScript(`_`);
888
+ script.restoreContext.addToken(import_types.AST_TOKEN_TYPES.JSXIdentifier, [
835
889
  start2,
836
890
  start2 + colonIndex
837
891
  ]);
838
- script.addToken(import_types.AST_TOKEN_TYPES.Punctuator, [
892
+ script.restoreContext.addToken(import_types.AST_TOKEN_TYPES.Punctuator, [
839
893
  start2 + colonIndex,
840
894
  start2 + colonIndex + 1
841
895
  ]);
842
- script.addToken(import_types.AST_TOKEN_TYPES.JSXIdentifier, [
896
+ script.restoreContext.addToken(import_types.AST_TOKEN_TYPES.JSXIdentifier, [
843
897
  start2 + colonIndex + 1,
844
898
  start2 + attr.name.length
845
899
  ]);
846
- script.addRestoreNodeProcess((scriptNode, context) => {
847
- if (scriptNode.type === import_types.AST_NODE_TYPES.JSXAttribute && scriptNode.range[0] === start2) {
848
- const baseNameNode = scriptNode.name;
849
- const nsn = {
850
- ...baseNameNode,
851
- type: import_types.AST_NODE_TYPES.JSXNamespacedName,
852
- namespace: {
853
- type: import_types.AST_NODE_TYPES.JSXIdentifier,
854
- name: attr.name.slice(0, colonIndex),
855
- ...ctx.getLocations(
856
- baseNameNode.range[0],
857
- baseNameNode.range[0] + colonIndex
858
- )
859
- },
860
- name: {
861
- type: import_types.AST_NODE_TYPES.JSXIdentifier,
862
- name: attr.name.slice(colonIndex + 1),
863
- ...ctx.getLocations(
864
- baseNameNode.range[0] + colonIndex + 1,
865
- baseNameNode.range[1]
866
- )
867
- }
868
- };
869
- scriptNode.name = nsn;
870
- nsn.namespace.parent = nsn;
871
- nsn.name.parent = nsn;
872
- context.addRemoveToken(
873
- (token) => token.range[0] === baseNameNode.range[0] && token.range[1] === baseNameNode.range[1]
874
- );
875
- return true;
900
+ script.restoreContext.addRestoreNodeProcess(
901
+ (scriptNode, context) => {
902
+ if (scriptNode.type === import_types.AST_NODE_TYPES.JSXAttribute && scriptNode.range[0] === start2) {
903
+ const baseNameNode = scriptNode.name;
904
+ const nsn = {
905
+ ...baseNameNode,
906
+ type: import_types.AST_NODE_TYPES.JSXNamespacedName,
907
+ namespace: {
908
+ type: import_types.AST_NODE_TYPES.JSXIdentifier,
909
+ name: attr.name.slice(0, colonIndex),
910
+ ...ctx.getLocations(
911
+ baseNameNode.range[0],
912
+ baseNameNode.range[0] + colonIndex
913
+ )
914
+ },
915
+ name: {
916
+ type: import_types.AST_NODE_TYPES.JSXIdentifier,
917
+ name: attr.name.slice(colonIndex + 1),
918
+ ...ctx.getLocations(
919
+ baseNameNode.range[0] + colonIndex + 1,
920
+ baseNameNode.range[1]
921
+ )
922
+ }
923
+ };
924
+ scriptNode.name = nsn;
925
+ nsn.namespace.parent = nsn;
926
+ nsn.name.parent = nsn;
927
+ context.addRemoveToken(
928
+ (token) => token.range[0] === baseNameNode.range[0] && token.range[1] === baseNameNode.range[1]
929
+ );
930
+ return true;
931
+ }
932
+ return false;
876
933
  }
877
- return false;
878
- });
934
+ );
879
935
  }
880
936
  }
881
937
  if (attr.kind === "shorthand") {
882
938
  const start2 = attr.position.start.offset;
883
939
  script.appendOriginal(start2);
884
940
  const jsxName = /[\s"'[\]{}]/u.test(attr.name) ? generateUniqueId(attr.name) : attr.name;
885
- script.appendScript(`${jsxName}=`);
886
- script.addRestoreNodeProcess((scriptNode) => {
941
+ script.appendVirtualScript(`${jsxName}=`);
942
+ script.restoreContext.addRestoreNodeProcess((scriptNode) => {
887
943
  if (scriptNode.type === import_types.AST_NODE_TYPES.JSXAttribute && scriptNode.range[0] === start2) {
888
944
  const attrNode = scriptNode;
889
945
  attrNode.type = "AstroShorthandAttribute";
@@ -904,10 +960,10 @@ function processTemplate(ctx, resultTemplate) {
904
960
  const start2 = calcAttributeValueStartOffset(attr, ctx);
905
961
  const end = calcAttributeEndOffset(attr, ctx);
906
962
  script.appendOriginal(start2);
907
- script.appendScript("{");
963
+ script.appendVirtualScript("{");
908
964
  script.appendOriginal(end);
909
- script.appendScript("}");
910
- script.addRestoreNodeProcess((scriptNode) => {
965
+ script.appendVirtualScript("}");
966
+ script.restoreContext.addRestoreNodeProcess((scriptNode) => {
911
967
  if (scriptNode.type === import_types.AST_NODE_TYPES.JSXAttribute && scriptNode.range[0] === attrStart) {
912
968
  const attrNode = scriptNode;
913
969
  attrNode.type = "AstroTemplateLiteralAttribute";
@@ -920,7 +976,7 @@ function processTemplate(ctx, resultTemplate) {
920
976
  const closing = getSelfClosingTag(node, ctx);
921
977
  if (closing && closing.end === ">") {
922
978
  script.appendOriginal(closing.offset - 1);
923
- script.appendScript("/");
979
+ script.appendVirtualScript("/");
924
980
  }
925
981
  if (node.name === "script" || node.name === "style") {
926
982
  const text = node.children[0];
@@ -929,7 +985,7 @@ function processTemplate(ctx, resultTemplate) {
929
985
  const start2 = text.position.start.offset;
930
986
  script.appendOriginal(start2);
931
987
  script.skipOriginalOffset(text.value.length);
932
- script.addRestoreNodeProcess((scriptNode) => {
988
+ script.restoreContext.addRestoreNodeProcess((scriptNode) => {
933
989
  if (scriptNode.type === import_types.AST_NODE_TYPES.JSXElement && scriptNode.range[0] === styleNodeStart) {
934
990
  const textNode = {
935
991
  type: "AstroRawText",
@@ -943,7 +999,7 @@ function processTemplate(ctx, resultTemplate) {
943
999
  }
944
1000
  return false;
945
1001
  });
946
- script.addToken(import_types.AST_TOKEN_TYPES.JSXText, [
1002
+ script.restoreContext.addToken(import_types.AST_TOKEN_TYPES.JSXText, [
947
1003
  start2,
948
1004
  start2 + text.value.length
949
1005
  ]);
@@ -958,10 +1014,10 @@ function processTemplate(ctx, resultTemplate) {
958
1014
  openRootFragment(start);
959
1015
  }
960
1016
  script.appendOriginal(start + 1);
961
- script.appendScript(`></`);
1017
+ script.appendVirtualScript(`></`);
962
1018
  script.skipOriginalOffset(length - 2);
963
1019
  script.appendOriginal(end);
964
- script.addRestoreNodeProcess((scriptNode, context) => {
1020
+ script.restoreContext.addRestoreNodeProcess((scriptNode, context) => {
965
1021
  if (scriptNode.range[0] === start && scriptNode.type === import_types.AST_NODE_TYPES.JSXFragment) {
966
1022
  delete scriptNode.children;
967
1023
  delete scriptNode.openingFragment;
@@ -980,7 +1036,7 @@ function processTemplate(ctx, resultTemplate) {
980
1036
  }
981
1037
  return false;
982
1038
  });
983
- script.addToken("HTMLComment", [
1039
+ script.restoreContext.addToken("HTMLComment", [
984
1040
  start,
985
1041
  start + length
986
1042
  ]);
@@ -993,10 +1049,10 @@ function processTemplate(ctx, resultTemplate) {
993
1049
  openRootFragment(start);
994
1050
  }
995
1051
  script.appendOriginal(start + 1);
996
- script.appendScript(`></`);
1052
+ script.appendVirtualScript(`></`);
997
1053
  script.skipOriginalOffset(length - 2);
998
1054
  script.appendOriginal(end);
999
- script.addRestoreNodeProcess((scriptNode, context) => {
1055
+ script.restoreContext.addRestoreNodeProcess((scriptNode, context) => {
1000
1056
  if (scriptNode.range[0] === start && scriptNode.type === import_types.AST_NODE_TYPES.JSXFragment) {
1001
1057
  delete scriptNode.children;
1002
1058
  delete scriptNode.openingFragment;
@@ -1014,7 +1070,10 @@ function processTemplate(ctx, resultTemplate) {
1014
1070
  }
1015
1071
  return false;
1016
1072
  });
1017
- script.addToken("HTMLDocType", [start, end]);
1073
+ script.restoreContext.addToken("HTMLDocType", [
1074
+ start,
1075
+ end
1076
+ ]);
1018
1077
  } else {
1019
1078
  const start = node.position.start.offset;
1020
1079
  script.appendOriginal(start);
@@ -1031,15 +1090,17 @@ function processTemplate(ctx, resultTemplate) {
1031
1090
  if (!end) {
1032
1091
  const offset = calcContentEndOffset(node, ctx);
1033
1092
  script.appendOriginal(offset);
1034
- script.appendScript(`</${node.name}>`);
1035
- script.addRestoreNodeProcess((scriptNode, context) => {
1036
- const parent2 = context.getParent(scriptNode);
1037
- if (scriptNode.range[0] === offset && scriptNode.type === import_types.AST_NODE_TYPES.JSXClosingElement && parent2.type === import_types.AST_NODE_TYPES.JSXElement) {
1038
- parent2.closingElement = null;
1039
- return true;
1093
+ script.appendVirtualScript(`</${node.name}>`);
1094
+ script.restoreContext.addRestoreNodeProcess(
1095
+ (scriptNode, context) => {
1096
+ const parent2 = context.getParent(scriptNode);
1097
+ if (scriptNode.range[0] === offset && scriptNode.type === import_types.AST_NODE_TYPES.JSXClosingElement && parent2.type === import_types.AST_NODE_TYPES.JSXElement) {
1098
+ parent2.closingElement = null;
1099
+ return true;
1100
+ }
1101
+ return false;
1040
1102
  }
1041
- return false;
1042
- });
1103
+ );
1043
1104
  }
1044
1105
  }
1045
1106
  }
@@ -1051,7 +1112,7 @@ function processTemplate(ctx, resultTemplate) {
1051
1112
  if (before && (isTag(before) || before.type === "comment")) {
1052
1113
  const end = getEndOffset(node, ctx);
1053
1114
  script.appendOriginal(end);
1054
- script.appendScript("</>");
1115
+ script.appendVirtualScript("</>");
1055
1116
  }
1056
1117
  }
1057
1118
  }
@@ -1061,7 +1122,7 @@ function processTemplate(ctx, resultTemplate) {
1061
1122
  const last = resultTemplate.ast.children[resultTemplate.ast.children.length - 1];
1062
1123
  const end = getEndOffset(last, ctx);
1063
1124
  script.appendOriginal(end);
1064
- script.appendScript("</>");
1125
+ script.appendVirtualScript("</>;");
1065
1126
  }
1066
1127
  script.appendOriginal(ctx.code.length);
1067
1128
  return script;
@@ -1075,13 +1136,54 @@ function processTemplate(ctx, resultTemplate) {
1075
1136
  }
1076
1137
  }
1077
1138
 
1139
+ // src/util/index.ts
1140
+ function sortedLastIndex(array, compare) {
1141
+ let lower = 0;
1142
+ let upper = array.length;
1143
+ while (lower < upper) {
1144
+ const mid = Math.floor(lower + (upper - lower) / 2);
1145
+ const target = compare(array[mid]);
1146
+ if (target < 0) {
1147
+ lower = mid + 1;
1148
+ } else if (target > 0) {
1149
+ upper = mid;
1150
+ } else {
1151
+ return mid + 1;
1152
+ }
1153
+ }
1154
+ return upper;
1155
+ }
1156
+ function addElementToSortedArray(array, element, compare) {
1157
+ const index = sortedLastIndex(array, (target) => compare(target, element));
1158
+ array.splice(index, 0, element);
1159
+ }
1160
+ function addElementsToSortedArray(array, elements, compare) {
1161
+ if (!elements.length) {
1162
+ return;
1163
+ }
1164
+ let last = elements[0];
1165
+ let index = sortedLastIndex(array, (target) => compare(target, last));
1166
+ for (const element of elements) {
1167
+ if (compare(last, element) > 0) {
1168
+ index = sortedLastIndex(array, (target) => compare(target, element));
1169
+ }
1170
+ let e = array[index];
1171
+ while (e && compare(e, element) <= 0) {
1172
+ e = array[++index];
1173
+ }
1174
+ array.splice(index, 0, element);
1175
+ last = element;
1176
+ }
1177
+ }
1178
+
1078
1179
  // src/context/index.ts
1079
1180
  var Context = class {
1080
- constructor(code) {
1181
+ constructor(code, filePath) {
1081
1182
  this.locsMap = /* @__PURE__ */ new Map();
1082
1183
  this.state = {};
1083
1184
  this.locs = new LinesAndColumns(code);
1084
1185
  this.code = code;
1186
+ this.filePath = filePath;
1085
1187
  }
1086
1188
  getLocFromIndex(index) {
1087
1189
  let loc = this.locsMap.get(index);
@@ -1153,7 +1255,10 @@ ${next}`;
1153
1255
  this.normalizedLineFeed = new NormalizedLineFeed(normalizedCode, crs);
1154
1256
  }
1155
1257
  getLocFromIndex(index) {
1156
- const lineNumber = sortedLastIndex(this.lineStartIndices, index);
1258
+ const lineNumber = sortedLastIndex(
1259
+ this.lineStartIndices,
1260
+ (target) => target - index
1261
+ );
1157
1262
  return {
1158
1263
  line: lineNumber,
1159
1264
  column: index - this.lineStartIndices[lineNumber - 1]
@@ -1197,22 +1302,6 @@ var NormalizedLineFeed = class {
1197
1302
  }
1198
1303
  }
1199
1304
  };
1200
- function sortedLastIndex(array, value) {
1201
- let lower = 0;
1202
- let upper = array.length;
1203
- while (lower < upper) {
1204
- const mid = Math.floor(lower + (upper - lower) / 2);
1205
- const target = array[mid];
1206
- if (target < value) {
1207
- lower = mid + 1;
1208
- } else if (target > value) {
1209
- upper = mid;
1210
- } else {
1211
- return mid + 1;
1212
- }
1213
- }
1214
- return upper;
1215
- }
1216
1305
 
1217
1306
  // src/parser/astro-parser/parse.ts
1218
1307
  var service = __toESM(require("astrojs-compiler-sync"));
@@ -1466,14 +1555,14 @@ var LruCache = class extends Map {
1466
1555
 
1467
1556
  // src/parser/template.ts
1468
1557
  var lruCache = new LruCache(5);
1469
- function parseTemplate(code) {
1558
+ function parseTemplate(code, filePath) {
1470
1559
  const cache = lruCache.get(code);
1471
1560
  if (cache) {
1472
1561
  return cache;
1473
1562
  }
1474
- const ctx = new Context(code);
1563
+ const ctx = new Context(code, filePath);
1475
1564
  const normalized = ctx.locs.getNormalizedLineFeed();
1476
- const ctxForAstro = normalized.needRemap ? new Context(normalized.code) : ctx;
1565
+ const ctxForAstro = normalized.needRemap ? new Context(normalized.code, filePath) : ctx;
1477
1566
  try {
1478
1567
  const result = parse2((normalized == null ? void 0 : normalized.code) ?? code, ctxForAstro);
1479
1568
  if (normalized.needRemap) {
@@ -1608,6 +1697,10 @@ function getParser(attrs, parser) {
1608
1697
  }
1609
1698
 
1610
1699
  // src/context/parser-options.ts
1700
+ var TS_PARSER_NAMES = [
1701
+ "@typescript-eslint/parser",
1702
+ "typescript-eslint-parser-for-extra-files"
1703
+ ];
1611
1704
  var ParserOptionsContext = class {
1612
1705
  constructor(options) {
1613
1706
  this.state = {};
@@ -1642,20 +1735,22 @@ var ParserOptionsContext = class {
1642
1735
  return this.state.isTypeScript;
1643
1736
  }
1644
1737
  const parserValue = getParserForLang({}, (_a = this.parserOptions) == null ? void 0 : _a.parser);
1645
- if (maybeTSESLintParserObject(parserValue) || parserValue === "@typescript-eslint/parser") {
1646
- return this.state.isTypeScript = true;
1647
- }
1648
1738
  if (typeof parserValue !== "string") {
1649
- return this.state.isTypeScript = false;
1739
+ return this.state.isTypeScript = maybeTSESLintParserObject(parserValue) || isTSESLintParserObject(parserValue);
1650
1740
  }
1651
1741
  const parserName = parserValue;
1652
- if (parserName.includes("@typescript-eslint/parser")) {
1742
+ if (TS_PARSER_NAMES.includes(parserName)) {
1743
+ return this.state.isTypeScript = true;
1744
+ }
1745
+ if (TS_PARSER_NAMES.some((nm) => parserName.includes(nm))) {
1653
1746
  let targetPath = parserName;
1654
1747
  while (targetPath) {
1655
1748
  const pkgPath = import_path3.default.join(targetPath, "package.json");
1656
1749
  if (import_fs2.default.existsSync(pkgPath)) {
1657
1750
  try {
1658
- return this.state.isTypeScript = ((_b = JSON.parse(import_fs2.default.readFileSync(pkgPath, "utf-8"))) == null ? void 0 : _b.name) === "@typescript-eslint/parser";
1751
+ return this.state.isTypeScript = TS_PARSER_NAMES.includes(
1752
+ (_b = JSON.parse(import_fs2.default.readFileSync(pkgPath, "utf-8"))) == null ? void 0 : _b.name
1753
+ );
1659
1754
  } catch {
1660
1755
  return this.state.isTypeScript = false;
1661
1756
  }
@@ -1671,13 +1766,292 @@ var ParserOptionsContext = class {
1671
1766
  }
1672
1767
  };
1673
1768
 
1769
+ // src/parser/scope/index.ts
1770
+ var import_eslint_scope = require("eslint-scope");
1771
+ function getProgramScope(scopeManager) {
1772
+ const globalScope = scopeManager.globalScope;
1773
+ return globalScope.childScopes.find((s) => s.type === "module") || globalScope;
1774
+ }
1775
+ function removeAllScopeAndVariableAndReference(target, info) {
1776
+ const targetScopes = /* @__PURE__ */ new Set();
1777
+ traverseNodes(target, {
1778
+ visitorKeys: info.visitorKeys,
1779
+ enterNode(node) {
1780
+ const scope = info.scopeManager.acquire(node);
1781
+ if (scope) {
1782
+ targetScopes.add(scope);
1783
+ return;
1784
+ }
1785
+ if (node.type === "Identifier") {
1786
+ let scope2 = getInnermostScopeFromNode(info.scopeManager, node);
1787
+ while (scope2 && scope2.block.type !== "Program" && target.range[0] <= scope2.block.range[0] && scope2.block.range[1] <= target.range[1]) {
1788
+ scope2 = scope2.upper;
1789
+ }
1790
+ if (targetScopes.has(scope2)) {
1791
+ return;
1792
+ }
1793
+ removeIdentifierVariable(node, scope2);
1794
+ removeIdentifierReference(node, scope2);
1795
+ }
1796
+ },
1797
+ leaveNode() {
1798
+ }
1799
+ });
1800
+ for (const scope of targetScopes) {
1801
+ removeScope(info.scopeManager, scope);
1802
+ }
1803
+ }
1804
+ function addVirtualReference(node, variable, scope, readWrite) {
1805
+ const reference = new import_eslint_scope.Reference();
1806
+ reference.astroVirtualReference = true;
1807
+ reference.from = scope;
1808
+ reference.identifier = node;
1809
+ reference.isWrite = () => Boolean(readWrite.write);
1810
+ reference.isWriteOnly = () => Boolean(readWrite.write) && !readWrite.read;
1811
+ reference.isRead = () => Boolean(readWrite.read);
1812
+ reference.isReadOnly = () => Boolean(readWrite.read) && !readWrite.write;
1813
+ reference.isReadWrite = () => Boolean(readWrite.read && readWrite.write);
1814
+ addReference(variable.references, reference);
1815
+ reference.resolved = variable;
1816
+ return reference;
1817
+ }
1818
+ function addGlobalVariable(reference, scopeManager) {
1819
+ const globalScope = scopeManager.globalScope;
1820
+ const name = reference.identifier.name;
1821
+ let variable = globalScope.set.get(name);
1822
+ if (!variable) {
1823
+ variable = new import_eslint_scope.Variable();
1824
+ variable.name = name;
1825
+ variable.scope = globalScope;
1826
+ globalScope.variables.push(variable);
1827
+ globalScope.set.set(name, variable);
1828
+ }
1829
+ reference.resolved = variable;
1830
+ variable.references.push(reference);
1831
+ return variable;
1832
+ }
1833
+ function removeReferenceFromThrough(reference, baseScope) {
1834
+ const variable = reference.resolved;
1835
+ const name = reference.identifier.name;
1836
+ let scope = baseScope;
1837
+ while (scope) {
1838
+ for (const ref of [...scope.through]) {
1839
+ if (reference === ref) {
1840
+ scope.through.splice(scope.through.indexOf(ref), 1);
1841
+ } else if (ref.identifier.name === name) {
1842
+ ref.resolved = variable;
1843
+ if (!variable.references.includes(ref)) {
1844
+ addReference(variable.references, ref);
1845
+ }
1846
+ scope.through.splice(scope.through.indexOf(ref), 1);
1847
+ }
1848
+ }
1849
+ scope = scope.upper;
1850
+ }
1851
+ }
1852
+ function removeScope(scopeManager, scope) {
1853
+ for (const childScope of scope.childScopes) {
1854
+ removeScope(scopeManager, childScope);
1855
+ }
1856
+ while (scope.references[0]) {
1857
+ removeReference(scope.references[0], scope);
1858
+ }
1859
+ const upper = scope.upper;
1860
+ if (upper) {
1861
+ const index2 = upper.childScopes.indexOf(scope);
1862
+ if (index2 >= 0) {
1863
+ upper.childScopes.splice(index2, 1);
1864
+ }
1865
+ }
1866
+ const index = scopeManager.scopes.indexOf(scope);
1867
+ if (index >= 0) {
1868
+ scopeManager.scopes.splice(index, 1);
1869
+ }
1870
+ }
1871
+ function removeReference(reference, baseScope) {
1872
+ if (reference.resolved) {
1873
+ if (reference.resolved.defs.some((d) => d.name === reference.identifier)) {
1874
+ const varIndex = baseScope.variables.indexOf(reference.resolved);
1875
+ if (varIndex >= 0) {
1876
+ baseScope.variables.splice(varIndex, 1);
1877
+ }
1878
+ const name = reference.identifier.name;
1879
+ if (reference.resolved === baseScope.set.get(name)) {
1880
+ baseScope.set.delete(name);
1881
+ }
1882
+ } else {
1883
+ const refIndex = reference.resolved.references.indexOf(reference);
1884
+ if (refIndex >= 0) {
1885
+ reference.resolved.references.splice(refIndex, 1);
1886
+ }
1887
+ }
1888
+ }
1889
+ let scope = baseScope;
1890
+ while (scope) {
1891
+ const refIndex = scope.references.indexOf(reference);
1892
+ if (refIndex >= 0) {
1893
+ scope.references.splice(refIndex, 1);
1894
+ }
1895
+ const throughIndex = scope.through.indexOf(reference);
1896
+ if (throughIndex >= 0) {
1897
+ scope.through.splice(throughIndex, 1);
1898
+ }
1899
+ scope = scope.upper;
1900
+ }
1901
+ }
1902
+ function removeIdentifierVariable(node, scope) {
1903
+ for (let varIndex = 0; varIndex < scope.variables.length; varIndex++) {
1904
+ const variable = scope.variables[varIndex];
1905
+ const defIndex = variable.defs.findIndex((def) => def.name === node);
1906
+ if (defIndex < 0) {
1907
+ continue;
1908
+ }
1909
+ variable.defs.splice(defIndex, 1);
1910
+ if (variable.defs.length === 0) {
1911
+ referencesToThrough(variable.references, scope);
1912
+ variable.references.forEach((r) => {
1913
+ if (r.init)
1914
+ r.init = false;
1915
+ r.resolved = null;
1916
+ });
1917
+ scope.variables.splice(varIndex, 1);
1918
+ const name = node.name;
1919
+ if (variable === scope.set.get(name)) {
1920
+ scope.set.delete(name);
1921
+ }
1922
+ } else {
1923
+ const idIndex = variable.identifiers.indexOf(node);
1924
+ if (idIndex >= 0) {
1925
+ variable.identifiers.splice(idIndex, 1);
1926
+ }
1927
+ }
1928
+ return;
1929
+ }
1930
+ }
1931
+ function removeIdentifierReference(node, scope) {
1932
+ const reference = scope.references.find((ref) => ref.identifier === node);
1933
+ if (reference) {
1934
+ removeReference(reference, scope);
1935
+ return true;
1936
+ }
1937
+ const location = node.range[0];
1938
+ const pendingScopes = [];
1939
+ for (const childScope of scope.childScopes) {
1940
+ const range = childScope.block.range;
1941
+ if (range[0] <= location && location < range[1]) {
1942
+ if (removeIdentifierReference(node, childScope)) {
1943
+ return true;
1944
+ }
1945
+ } else {
1946
+ pendingScopes.push(childScope);
1947
+ }
1948
+ }
1949
+ for (const childScope of pendingScopes) {
1950
+ if (removeIdentifierReference(node, childScope)) {
1951
+ return true;
1952
+ }
1953
+ }
1954
+ return false;
1955
+ }
1956
+ function getInnermostScopeFromNode(scopeManager, currentNode) {
1957
+ return getInnermostScope(
1958
+ getScopeFromNode(scopeManager, currentNode),
1959
+ currentNode
1960
+ );
1961
+ }
1962
+ function getScopeFromNode(scopeManager, currentNode) {
1963
+ let node = currentNode;
1964
+ for (; node; node = node.parent || null) {
1965
+ const scope = scopeManager.acquire(node, false);
1966
+ if (scope) {
1967
+ if (scope.type === "function-expression-name") {
1968
+ return scope.childScopes[0];
1969
+ }
1970
+ if (scope.type === "global" && node.type === "Program" && node.sourceType === "module") {
1971
+ return scope.childScopes.find((s) => s.type === "module") || scope;
1972
+ }
1973
+ return scope;
1974
+ }
1975
+ }
1976
+ const global = scopeManager.globalScope;
1977
+ return global;
1978
+ }
1979
+ function getInnermostScope(initialScope, node) {
1980
+ for (const childScope of initialScope.childScopes) {
1981
+ const range = childScope.block.range;
1982
+ if (range[0] <= node.range[0] && node.range[1] <= range[1]) {
1983
+ return getInnermostScope(childScope, node);
1984
+ }
1985
+ }
1986
+ return initialScope;
1987
+ }
1988
+ function referencesToThrough(references, baseScope) {
1989
+ let scope = baseScope;
1990
+ while (scope) {
1991
+ addAllReferences(scope.through, references);
1992
+ scope = scope.upper;
1993
+ }
1994
+ }
1995
+ function addAllReferences(list, elements) {
1996
+ addElementsToSortedArray(
1997
+ list,
1998
+ elements,
1999
+ (a, b) => a.identifier.range[0] - b.identifier.range[0]
2000
+ );
2001
+ }
2002
+ function addReference(list, reference) {
2003
+ addElementToSortedArray(
2004
+ list,
2005
+ reference,
2006
+ (a, b) => a.identifier.range[0] - b.identifier.range[0]
2007
+ );
2008
+ }
2009
+
1674
2010
  // src/parser/index.ts
1675
2011
  function parseForESLint(code, options) {
1676
- const { result: resultTemplate, context: ctx } = parseTemplate(code);
2012
+ const { result: resultTemplate, context: ctx } = parseTemplate(
2013
+ code,
2014
+ (options == null ? void 0 : options.filePath) ?? "<input>"
2015
+ );
1677
2016
  const scriptContext = processTemplate(ctx, resultTemplate);
1678
2017
  const parserOptions = new ParserOptionsContext(options);
2018
+ if (parserOptions.isTypeScript() && /\bAstro\b/u.test(code)) {
2019
+ scriptContext.appendVirtualScript(
2020
+ `declare const Astro: Readonly<import('astro').AstroGlobal<Props>>;`
2021
+ );
2022
+ scriptContext.restoreContext.addRestoreNodeProcess(
2023
+ (_scriptNode, { result }) => {
2024
+ const declareNode = result.ast.body.pop();
2025
+ const scopeManager = result.scopeManager;
2026
+ if (scopeManager) {
2027
+ removeAllScopeAndVariableAndReference(declareNode, {
2028
+ visitorKeys: result.visitorKeys,
2029
+ scopeManager
2030
+ });
2031
+ const scope = getProgramScope(scopeManager);
2032
+ const propsVariable = scope.set.get("Props");
2033
+ if (propsVariable) {
2034
+ addVirtualReference(
2035
+ propsVariable.identifiers[0],
2036
+ propsVariable,
2037
+ scope,
2038
+ {}
2039
+ );
2040
+ }
2041
+ const astroGlobalReferences = scope.through.filter(
2042
+ (ref) => ref.identifier.name === "Astro" || ref.identifier.name === "Fragment"
2043
+ );
2044
+ for (const astroGlobalReference of astroGlobalReferences) {
2045
+ addGlobalVariable(astroGlobalReference, scopeManager);
2046
+ removeReferenceFromThrough(astroGlobalReference, scope);
2047
+ }
2048
+ }
2049
+ return true;
2050
+ }
2051
+ );
2052
+ }
1679
2053
  const resultScript = parseScript(scriptContext.script, ctx, parserOptions);
1680
- scriptContext.restore(resultScript);
2054
+ scriptContext.restoreContext.restore(resultScript);
1681
2055
  sort(resultScript.ast.comments);
1682
2056
  sort(resultScript.ast.tokens);
1683
2057
  extractTokens(resultScript, ctx);