token-goat 2.9.30 → 2.9.31

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.
Files changed (172) hide show
  1. package/README.md +24 -7
  2. package/SECURITY.md +10 -2
  3. package/THIRD_PARTY_NOTICES.md +1 -1
  4. package/dist/native/linux-arm64/tg-hook +0 -0
  5. package/dist/native/linux-x64/tg-hook +0 -0
  6. package/dist/native/win32-arm64/tg-hook.exe +0 -0
  7. package/dist/native/win32-x64/tg-hook.exe +0 -0
  8. package/dist/{token-goat-chunk-QSBRTGM2.mjs → token-goat-chunk-25TRAWET.mjs} +17 -7
  9. package/dist/token-goat-chunk-2KXO6V2B.mjs +203 -0
  10. package/dist/{token-goat-chunk-IVKIZWAB.mjs → token-goat-chunk-2M7E4PF7.mjs} +41 -12
  11. package/dist/{token-goat-chunk-SMVRN2HU.mjs → token-goat-chunk-2UPZGKKY.mjs} +2 -2
  12. package/dist/token-goat-chunk-2WLPWKHV.mjs +135 -0
  13. package/dist/token-goat-chunk-2XBMMDBD.mjs +126 -0
  14. package/dist/token-goat-chunk-32ZOY4N5.mjs +23 -0
  15. package/dist/token-goat-chunk-3EZRNKTK.mjs +188 -0
  16. package/dist/token-goat-chunk-4ADZHI7J.mjs +63 -0
  17. package/dist/token-goat-chunk-4GBVPH3D.mjs +242 -0
  18. package/dist/{token-goat-chunk-KWPNJBDH.mjs → token-goat-chunk-4GILLLWY.mjs} +7 -4
  19. package/dist/{token-goat-chunk-67TQJ76B.mjs → token-goat-chunk-4NAPX7BA.mjs} +36 -3
  20. package/dist/{token-goat-chunk-PU7V3FD6.mjs → token-goat-chunk-4SC7UJYV.mjs} +3354 -2553
  21. package/dist/token-goat-chunk-4SMRO4TO.mjs +366 -0
  22. package/dist/{token-goat-chunk-AFLYLHDH.mjs → token-goat-chunk-4ZBFWLXF.mjs} +283 -427
  23. package/dist/{token-goat-chunk-JDWCRD6M.mjs → token-goat-chunk-57BIAXJL.mjs} +73 -40
  24. package/dist/token-goat-chunk-5AC66HNP.mjs +115 -0
  25. package/dist/token-goat-chunk-5IMLKSOP.mjs +145 -0
  26. package/dist/token-goat-chunk-646E6U44.mjs +398 -0
  27. package/dist/token-goat-chunk-65N4RHP4.mjs +33 -0
  28. package/dist/{token-goat-chunk-JN4XMLSD.mjs → token-goat-chunk-6DG6HWP3.mjs} +8 -2
  29. package/dist/token-goat-chunk-6ENQSNRZ.mjs +573 -0
  30. package/dist/token-goat-chunk-6ZY4GNF2.mjs +91 -0
  31. package/dist/{token-goat-chunk-VPBBTSJR.mjs → token-goat-chunk-76FGDLRO.mjs} +262 -255
  32. package/dist/{token-goat-chunk-7IN2MKDS.mjs → token-goat-chunk-7EZTZOMC.mjs} +121 -289
  33. package/dist/{token-goat-chunk-OJBNYTJP.mjs → token-goat-chunk-7MAOA6X4.mjs} +640 -80
  34. package/dist/token-goat-chunk-7R2ZVVAX.mjs +218 -0
  35. package/dist/{token-goat-chunk-PD5VKH46.mjs → token-goat-chunk-AUNGYYQX.mjs} +2 -2
  36. package/dist/{token-goat-chunk-HG45AF2B.mjs → token-goat-chunk-AUQYRMMH.mjs} +794 -37
  37. package/dist/token-goat-chunk-B3PEKBYG.mjs +128 -0
  38. package/dist/{token-goat-chunk-A3CK6N5Z.mjs → token-goat-chunk-BA4HI6BW.mjs} +1309 -110
  39. package/dist/{token-goat-chunk-JB6QN6VF.mjs → token-goat-chunk-BFCWY73P.mjs} +59 -23
  40. package/dist/{token-goat-chunk-B45VMIIH.mjs → token-goat-chunk-BWGFUZZE.mjs} +7 -5
  41. package/dist/{token-goat-chunk-P4QMM4WK.mjs → token-goat-chunk-C75NA7PL.mjs} +50 -23
  42. package/dist/token-goat-chunk-CBIQ7WTD.mjs +87 -0
  43. package/dist/token-goat-chunk-CETM74KC.mjs +307 -0
  44. package/dist/{token-goat-chunk-H2PHHGM5.mjs → token-goat-chunk-CIMQ2BB3.mjs} +57 -12
  45. package/dist/{token-goat-chunk-N2NMER56.mjs → token-goat-chunk-CJLS3CDL.mjs} +46 -4
  46. package/dist/{token-goat-chunk-VES7EL7O.mjs → token-goat-chunk-CO3UYX6G.mjs} +1 -1
  47. package/dist/token-goat-chunk-COPNXRJM.mjs +154 -0
  48. package/dist/token-goat-chunk-CSJ5L3NL.mjs +479 -0
  49. package/dist/{token-goat-chunk-4LCCNRTG.mjs → token-goat-chunk-CVCEVUGK.mjs} +8 -6
  50. package/dist/{token-goat-chunk-B2RZZCSS.mjs → token-goat-chunk-CXHOFN7R.mjs} +37 -20
  51. package/dist/token-goat-chunk-D735C4QM.mjs +603 -0
  52. package/dist/{token-goat-chunk-APGZXSPS.mjs → token-goat-chunk-DGS2LVNA.mjs} +47 -30
  53. package/dist/{token-goat-chunk-54K3EUV3.mjs → token-goat-chunk-DOWRSMWO.mjs} +1 -1
  54. package/dist/token-goat-chunk-E45INMY3.mjs +71 -0
  55. package/dist/token-goat-chunk-EC5F37F4.mjs +244 -0
  56. package/dist/{token-goat-chunk-XTQAOTSO.mjs → token-goat-chunk-EDBDRVH5.mjs} +4 -1
  57. package/dist/{token-goat-chunk-5BCIJXMO.mjs → token-goat-chunk-EELTBKDM.mjs} +14 -10
  58. package/dist/{token-goat-chunk-W3QCJS6G.mjs → token-goat-chunk-F4HYL64R.mjs} +8 -6
  59. package/dist/token-goat-chunk-F6PAUIEK.mjs +624 -0
  60. package/dist/token-goat-chunk-FDSREWLX.mjs +692 -0
  61. package/dist/token-goat-chunk-GGGG7RWB.mjs +236 -0
  62. package/dist/{token-goat-chunk-C63JQV5K.mjs → token-goat-chunk-GL3ETKSC.mjs} +233 -15
  63. package/dist/token-goat-chunk-GVB2MUST.mjs +1298 -0
  64. package/dist/token-goat-chunk-GWFLAUMQ.mjs +307 -0
  65. package/dist/{token-goat-chunk-ZEJVMUQH.mjs → token-goat-chunk-HLPW63A7.mjs} +2 -2
  66. package/dist/{token-goat-chunk-GOLEOXZP.mjs → token-goat-chunk-HU4TORC5.mjs} +44 -26
  67. package/dist/{token-goat-chunk-Z57YODA2.mjs → token-goat-chunk-I7VKZZAW.mjs} +2 -2
  68. package/dist/{token-goat-chunk-NYKZLXMK.mjs → token-goat-chunk-IA6XSPE3.mjs} +6 -6
  69. package/dist/{token-goat-chunk-E3OQX2XT.mjs → token-goat-chunk-IAGXMHIK.mjs} +81 -42
  70. package/dist/{token-goat-chunk-HYBFA5X3.mjs → token-goat-chunk-IK2DRMFX.mjs} +24 -68
  71. package/dist/{token-goat-chunk-COBQGL5S.mjs → token-goat-chunk-INNPTRUX.mjs} +249 -299
  72. package/dist/{token-goat-chunk-7NADEDKJ.mjs → token-goat-chunk-JJ5BX4F4.mjs} +6 -1
  73. package/dist/{token-goat-chunk-PEPTHRFF.mjs → token-goat-chunk-JVFSHVFJ.mjs} +6 -6
  74. package/dist/token-goat-chunk-KGEFFSHD.mjs +50 -0
  75. package/dist/token-goat-chunk-KQBLRPBN.mjs +433 -0
  76. package/dist/{token-goat-chunk-Q5VTGRH7.mjs → token-goat-chunk-LCNQ2CNN.mjs} +55 -319
  77. package/dist/token-goat-chunk-M3LFJDPU.mjs +58 -0
  78. package/dist/token-goat-chunk-M52KPT3C.mjs +87 -0
  79. package/dist/token-goat-chunk-MBEG42H7.mjs +150 -0
  80. package/dist/{token-goat-chunk-EVC4TOLE.mjs → token-goat-chunk-METECDOH.mjs} +3 -12
  81. package/dist/{token-goat-chunk-T4FK7VOV.mjs → token-goat-chunk-MHX7XCC3.mjs} +2 -1
  82. package/dist/token-goat-chunk-N5LSOVSU.mjs +137 -0
  83. package/dist/{token-goat-chunk-LOBGHXPB.mjs → token-goat-chunk-N5MMR2IW.mjs} +1 -1
  84. package/dist/token-goat-chunk-N7B3JQ2C.mjs +160 -0
  85. package/dist/{token-goat-chunk-RHXKCZX3.mjs → token-goat-chunk-NISNMD7T.mjs} +2182 -2959
  86. package/dist/token-goat-chunk-NMD42SFQ.mjs +434 -0
  87. package/dist/token-goat-chunk-NOSS5VWY.mjs +174 -0
  88. package/dist/{token-goat-chunk-KQNZDCBD.mjs → token-goat-chunk-NSNSPPBG.mjs} +25 -3
  89. package/dist/token-goat-chunk-OBOFIHKN.mjs +38 -0
  90. package/dist/token-goat-chunk-OBRFJ5O5.mjs +76 -0
  91. package/dist/{token-goat-chunk-JTQQGXZH.mjs → token-goat-chunk-ODBT2USM.mjs} +124 -57
  92. package/dist/token-goat-chunk-OS5EM5PP.mjs +107 -0
  93. package/dist/token-goat-chunk-OUKDTVNU.mjs +1178 -0
  94. package/dist/token-goat-chunk-OXFMP75N.mjs +566 -0
  95. package/dist/{token-goat-chunk-DZX2YDPT.mjs → token-goat-chunk-OYIYKDDT.mjs} +2 -2
  96. package/dist/{token-goat-chunk-QCLDAQTS.mjs → token-goat-chunk-P6HQSWQ3.mjs} +50 -53
  97. package/dist/token-goat-chunk-P6VGNTQT.mjs +71 -0
  98. package/dist/{token-goat-chunk-7BXSNBY5.mjs → token-goat-chunk-PFWIMH2E.mjs} +23 -15
  99. package/dist/token-goat-chunk-PJZXIS3G.mjs +39 -0
  100. package/dist/token-goat-chunk-PUO5INXP.mjs +606 -0
  101. package/dist/{token-goat-chunk-GFBSN7BD.mjs → token-goat-chunk-PX5PQWTY.mjs} +22 -250
  102. package/dist/token-goat-chunk-Q5QDBC6O.mjs +111 -0
  103. package/dist/token-goat-chunk-QFNQXSDT.mjs +40 -0
  104. package/dist/{token-goat-chunk-FBNQNSJK.mjs → token-goat-chunk-QH7YVYOY.mjs} +2198 -2782
  105. package/dist/{token-goat-chunk-64FBPDTK.mjs → token-goat-chunk-QLMUHEPB.mjs} +12 -9
  106. package/dist/{token-goat-chunk-RZRTDST7.mjs → token-goat-chunk-QQOJIHL3.mjs} +37 -11
  107. package/dist/{token-goat-chunk-XKI4SEMX.mjs → token-goat-chunk-QQTWJY2O.mjs} +19 -0
  108. package/dist/{token-goat-chunk-U4N3BN2W.mjs → token-goat-chunk-QYHO5CPH.mjs} +3 -2
  109. package/dist/token-goat-chunk-RELAVWAD.mjs +27 -0
  110. package/dist/{token-goat-chunk-ETBHVDB6.mjs → token-goat-chunk-RSLPOBKQ.mjs} +22 -11
  111. package/dist/token-goat-chunk-SAMFDIS2.mjs +712 -0
  112. package/dist/token-goat-chunk-SDELXLDM.mjs +48 -0
  113. package/dist/{token-goat-chunk-4JJS54TR.mjs → token-goat-chunk-SOAFZNNZ.mjs} +161 -38
  114. package/dist/{token-goat-chunk-664RTTUV.mjs → token-goat-chunk-SRTHT7KV.mjs} +21 -16
  115. package/dist/{token-goat-chunk-4FVIAHSI.mjs → token-goat-chunk-T5P5ACNQ.mjs} +7 -6
  116. package/dist/token-goat-chunk-T5YGG4V3.mjs +45 -0
  117. package/dist/token-goat-chunk-TAUZ4OFS.mjs +110 -0
  118. package/dist/{token-goat-chunk-COTXZHTS.mjs → token-goat-chunk-TM6MC754.mjs} +4 -3
  119. package/dist/token-goat-chunk-TWUKBOMP.mjs +72 -0
  120. package/dist/{token-goat-chunk-3CHUNJ2O.mjs → token-goat-chunk-U2KSB4SG.mjs} +8 -5
  121. package/dist/{token-goat-chunk-3Z5S4KGM.mjs → token-goat-chunk-U4WHMG6Y.mjs} +29 -49
  122. package/dist/{token-goat-chunk-PY533T7F.mjs → token-goat-chunk-UGJHGR5A.mjs} +21 -15
  123. package/dist/{token-goat-chunk-CYCEYAEO.mjs → token-goat-chunk-UOUDVA5U.mjs} +1 -1
  124. package/dist/{token-goat-chunk-JDHE26RP.mjs → token-goat-chunk-URRJ33GR.mjs} +16 -5
  125. package/dist/{token-goat-chunk-56EIMS3E.mjs → token-goat-chunk-UZOROKIS.mjs} +23 -17
  126. package/dist/{token-goat-chunk-CZ3LUXYZ.mjs → token-goat-chunk-VIHGGGEI.mjs} +427 -308
  127. package/dist/token-goat-chunk-VTJLAA7P.mjs +21 -0
  128. package/dist/token-goat-chunk-VWDXLT4F.mjs +678 -0
  129. package/dist/{token-goat-chunk-YARZFCZS.mjs → token-goat-chunk-VWZA2H4P.mjs} +62 -53
  130. package/dist/{token-goat-chunk-SQSSNQPE.mjs → token-goat-chunk-VXEXMJDL.mjs} +3979 -4745
  131. package/dist/token-goat-chunk-WBA5SKT4.mjs +547 -0
  132. package/dist/{token-goat-chunk-SJHWVNDQ.mjs → token-goat-chunk-WDH44VAU.mjs} +7 -4
  133. package/dist/token-goat-chunk-X2SUP3EI.mjs +107 -0
  134. package/dist/token-goat-chunk-X3BELZSJ.mjs +125 -0
  135. package/dist/{token-goat-chunk-FZ3NEW5O.mjs → token-goat-chunk-XLRBNZCC.mjs} +13 -8
  136. package/dist/{token-goat-chunk-Z44YO3QZ.mjs → token-goat-chunk-XRKUX6CM.mjs} +1 -1
  137. package/dist/token-goat-chunk-XX6O25RN.mjs +82 -0
  138. package/dist/token-goat-chunk-XZSUHBVS.mjs +65 -0
  139. package/dist/{token-goat-chunk-WY3L4DVT.mjs → token-goat-chunk-Y2ZTQOCL.mjs} +13 -8
  140. package/dist/{token-goat-chunk-UQ5UK2T7.mjs → token-goat-chunk-YB4VMGK2.mjs} +1 -1
  141. package/dist/token-goat-chunk-YBIIY3HR.mjs +51 -0
  142. package/dist/{token-goat-chunk-ZQSJMO2R.mjs → token-goat-chunk-YHVDKQBR.mjs} +105 -105
  143. package/dist/{token-goat-chunk-H2K3QP6H.mjs → token-goat-chunk-YJB5XLWI.mjs} +8 -6
  144. package/dist/{token-goat-chunk-ZCDTCVIS.mjs → token-goat-chunk-YKB6AQG3.mjs} +5 -2
  145. package/dist/token-goat-chunk-YMTG2YA5.mjs +35 -0
  146. package/dist/token-goat-chunk-YPBZYQRV.mjs +40 -0
  147. package/dist/{token-goat-chunk-HOJLCGDP.mjs → token-goat-chunk-YY6AVUFL.mjs} +2033 -2251
  148. package/dist/token-goat-chunk-Z7N5OMMP.mjs +98 -0
  149. package/dist/token-goat-chunk-ZNMNUPAZ.mjs +938 -0
  150. package/dist/token-goat-hook-client.cjs +1 -1
  151. package/dist/token-goat-hook-client.mjs +3 -3
  152. package/dist/token-goat-hook.mjs +67 -38
  153. package/dist/token-goat.core.mjs +4 -4
  154. package/docs/C4_RUNTIME_ARCHITECTURE.md +1 -1
  155. package/docs/cli.md +40 -21
  156. package/docs/install.md +19 -9
  157. package/docs/security.md +5 -3
  158. package/package.json +2 -1
  159. package/dist/token-goat-chunk-5KDMCMF2.mjs +0 -362
  160. package/dist/token-goat-chunk-6QMAS7AB.mjs +0 -42
  161. package/dist/token-goat-chunk-7F2UBPD3.mjs +0 -397
  162. package/dist/token-goat-chunk-ARDNEC2U.mjs +0 -248
  163. package/dist/token-goat-chunk-ATCPY7EQ.mjs +0 -134
  164. package/dist/token-goat-chunk-EFHMMIGP.mjs +0 -68
  165. package/dist/token-goat-chunk-IVALLT3S.mjs +0 -48
  166. package/dist/token-goat-chunk-JDU3EXSU.mjs +0 -65
  167. package/dist/token-goat-chunk-MKPF4CL5.mjs +0 -37
  168. package/dist/token-goat-chunk-RC35RBUL.mjs +0 -312
  169. package/dist/token-goat-chunk-USILZ3T3.mjs +0 -53
  170. package/dist/token-goat-chunk-VL3YIFHZ.mjs +0 -2975
  171. package/dist/token-goat-chunk-XU4P6Z24.mjs +0 -133
  172. package/dist/token-goat-chunk-Y776AENC.mjs +0 -1597
@@ -2,6 +2,11 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  SpanCollector,
5
+ bodyBraceAt,
6
+ bodyResumeAt,
7
+ bodySegments,
8
+ endOpenMember,
9
+ endOpenMembers,
5
10
  extractAbap,
6
11
  extractAbl,
7
12
  extractAsm,
@@ -24,22 +29,27 @@ import {
24
29
  extractSolidity,
25
30
  extractSwift,
26
31
  extractThrift,
27
- extractWgsl
28
- } from "./token-goat-chunk-4JJS54TR.mjs";
32
+ extractWgsl,
33
+ openMembersOf,
34
+ spanUnsettled
35
+ } from "./token-goat-chunk-SOAFZNNZ.mjs";
29
36
  import {
30
37
  extractShellBannerHeading
31
- } from "./token-goat-chunk-RHXKCZX3.mjs";
38
+ } from "./token-goat-chunk-OXFMP75N.mjs";
39
+ import "./token-goat-chunk-NISNMD7T.mjs";
32
40
  import "./token-goat-chunk-EVMZJ27Z.mjs";
33
- import "./token-goat-chunk-HYBFA5X3.mjs";
41
+ import "./token-goat-chunk-IK2DRMFX.mjs";
42
+ import {
43
+ extractEnv,
44
+ extractIni
45
+ } from "./token-goat-chunk-GVB2MUST.mjs";
46
+ import "./token-goat-chunk-XB5KKOCG.mjs";
34
47
  import {
35
48
  GENERIC_CLAUSE,
36
- assignBraceBlockSpans,
37
49
  assignFlatEndLines,
38
50
  buildLineIndex,
39
- extractEnv,
40
- extractIni,
51
+ closingQuoteRunEnd,
41
52
  findHtmlHeadingMatches,
42
- findMatchingBraceEndLine,
43
53
  isInsideStringLiteral,
44
54
  lineTextAt,
45
55
  makeLineSymbol,
@@ -51,6 +61,7 @@ import {
51
61
  offsetToLine,
52
62
  precedingDocComment,
53
63
  propagateEndLinesToSymbols,
64
+ scalaCharLiteralLength,
54
65
  scanQuotedStringEnd,
55
66
  stripBlockCommentSpan,
56
67
  stripCstyleComments,
@@ -60,21 +71,27 @@ import {
60
71
  stripMultilineStringSpan,
61
72
  stripStringLiterals,
62
73
  stripXmlComments
63
- } from "./token-goat-chunk-VL3YIFHZ.mjs";
64
- import "./token-goat-chunk-XB5KKOCG.mjs";
65
- import "./token-goat-chunk-7IN2MKDS.mjs";
66
- import "./token-goat-chunk-U4N3BN2W.mjs";
74
+ } from "./token-goat-chunk-OUKDTVNU.mjs";
75
+ import "./token-goat-chunk-7EZTZOMC.mjs";
76
+ import "./token-goat-chunk-QYHO5CPH.mjs";
77
+ import "./token-goat-chunk-4GBVPH3D.mjs";
67
78
  import "./token-goat-chunk-YZAAZU2S.mjs";
68
79
  import "./token-goat-chunk-IVE6U7KV.mjs";
80
+ import {
81
+ elementCursor,
82
+ findElements,
83
+ gtFinder
84
+ } from "./token-goat-chunk-E45INMY3.mjs";
69
85
  import "./token-goat-chunk-Y4AFKTHK.mjs";
70
86
  import {
71
87
  countContentLines,
72
88
  escapeRegExp,
73
89
  pushAll
74
- } from "./token-goat-chunk-GOLEOXZP.mjs";
90
+ } from "./token-goat-chunk-HU4TORC5.mjs";
91
+ import "./token-goat-chunk-GGGG7RWB.mjs";
75
92
  import "./token-goat-chunk-AM5V6GSX.mjs";
76
93
  import "./token-goat-chunk-FNFBKLRD.mjs";
77
- import "./token-goat-chunk-VES7EL7O.mjs";
94
+ import "./token-goat-chunk-CO3UYX6G.mjs";
78
95
  import {
79
96
  init_define_import_meta_env
80
97
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -82,6 +99,682 @@ import {
82
99
  // src/languages/registry.ts
83
100
  init_define_import_meta_env();
84
101
 
102
+ // src/languages/brace_spans.ts
103
+ init_define_import_meta_env();
104
+ function tripleQuoteDelimiters(opts) {
105
+ const delims = [];
106
+ if (opts?.tripleQuote === true) delims.push('"""');
107
+ if (opts?.tripleSingleQuote === true) delims.push("'''");
108
+ return delims;
109
+ }
110
+ function quoteRunLength(content, i) {
111
+ let n = 0;
112
+ while (content[i + n] === '"') n++;
113
+ return n;
114
+ }
115
+ function skipRawStringQuotes(content, from, min) {
116
+ return closingQuoteRunEnd(content, from, '"', min, "last");
117
+ }
118
+ function stepPowershellString(content, i, quote) {
119
+ const ch = content[i];
120
+ if (quote === '"' && ch === "`") return { next: i + 1, open: true };
121
+ return { next: i, open: ch !== quote };
122
+ }
123
+ function opensCsharpVerbatimString(content, i) {
124
+ const prev = content[i - 1];
125
+ return prev === "@" || prev === "$" && content[i - 2] === "@";
126
+ }
127
+ function toLineCommentPrefixes(prefix) {
128
+ if (prefix === void 0) return [];
129
+ return typeof prefix === "string" ? [prefix] : prefix;
130
+ }
131
+ function atLineComment(content, i, prefixes, exceptions) {
132
+ if (exceptions.some((e) => content.startsWith(e, i))) return false;
133
+ return prefixes.some((prefix) => content.startsWith(prefix, i));
134
+ }
135
+ function skipBlockComment(content, start, block, nested) {
136
+ let i = start + block[0].length;
137
+ let depth = 1;
138
+ while (i < content.length) {
139
+ if (nested && content.startsWith(block[0], i)) {
140
+ depth++;
141
+ i += block[0].length;
142
+ continue;
143
+ }
144
+ if (content.startsWith(block[1], i)) {
145
+ depth--;
146
+ i += block[1].length;
147
+ if (depth === 0) return i;
148
+ continue;
149
+ }
150
+ i++;
151
+ }
152
+ return -1;
153
+ }
154
+ function findMatchingBraceEndLine(content, openBraceIndex, totalLines, lineIndex, lineCommentPrefix, opts) {
155
+ const linePrefixes = toLineCommentPrefixes(lineCommentPrefix);
156
+ const lineExceptions = opts?.lineCommentExceptions ?? [];
157
+ const block = opts?.blockComment;
158
+ const backtick = opts?.backtickQuote === true;
159
+ const escapes = opts?.stringEscapes ?? "backslash";
160
+ const nestedBlock = opts?.nestedBlockComments === true;
161
+ const rawString = opts?.rawStringQuotes === true;
162
+ const rRaw = opts?.rRawStrings === true;
163
+ const tripleDelims = tripleQuoteDelimiters(opts);
164
+ const lineString = opts?.lineStringPrefix;
165
+ const interpolation = opts?.interpolation;
166
+ let interpolated = false;
167
+ let depth = 0;
168
+ let quote = null;
169
+ let verbatim = false;
170
+ for (let i = openBraceIndex; i < content.length; i++) {
171
+ const ch = content[i];
172
+ if (quote !== null) {
173
+ if (interpolated && interpolation !== void 0) {
174
+ const past = skipInterpolationAt(content, i, content.length, interpolation);
175
+ if (past !== null) {
176
+ i = past - 1;
177
+ continue;
178
+ }
179
+ }
180
+ if (verbatim) {
181
+ if (ch === quote) {
182
+ if (content[i + 1] === quote) {
183
+ i++;
184
+ continue;
185
+ }
186
+ quote = null;
187
+ verbatim = false;
188
+ }
189
+ continue;
190
+ }
191
+ if (escapes === "powershell") {
192
+ const step = stepPowershellString(content, i, quote);
193
+ i = step.next;
194
+ if (!step.open) quote = null;
195
+ continue;
196
+ }
197
+ if (ch === "\\") {
198
+ i++;
199
+ continue;
200
+ }
201
+ if (ch === quote) quote = null;
202
+ continue;
203
+ }
204
+ if (block !== void 0 && content.startsWith(block[0], i)) {
205
+ const end = skipBlockComment(content, i, block, nestedBlock);
206
+ i = end === -1 ? content.length : end - 1;
207
+ continue;
208
+ }
209
+ if (atLineComment(content, i, linePrefixes, lineExceptions)) {
210
+ while (i < content.length && content[i] !== "\n") i++;
211
+ continue;
212
+ }
213
+ if (lineString !== void 0 && content.startsWith(lineString, i)) {
214
+ while (i < content.length && content[i] !== "\n") i++;
215
+ continue;
216
+ }
217
+ if (rRaw) {
218
+ const rOpen = matchRRawOpener(content, i);
219
+ if (rOpen !== null) {
220
+ const end = content.indexOf(rOpen.closer, rOpen.openerEnd);
221
+ i = end === -1 ? content.length : end + rOpen.closer.length - 1;
222
+ continue;
223
+ }
224
+ }
225
+ if (rawString && ch === '"') {
226
+ const run = quoteRunLength(content, i);
227
+ if (run >= 3) {
228
+ const end = skipRawStringQuotes(content, i + run, run);
229
+ i = end === -1 ? content.length : end - 1;
230
+ continue;
231
+ }
232
+ }
233
+ const tripleAt = tripleDelims.find((t) => content.startsWith(t, i));
234
+ if (tripleAt !== void 0) {
235
+ const end = closingQuoteRunEnd(content, i + 3, tripleAt[0] ?? '"', 3, opts?.tripleQuoteRunClose ?? "last");
236
+ i = end === -1 ? content.length : end - 1;
237
+ continue;
238
+ }
239
+ if (ch === "'" && opts?.symbolLiterals === true) {
240
+ const charLen = scalaCharLiteralLength(content, i);
241
+ if (charLen > 0) i += charLen - 1;
242
+ continue;
243
+ }
244
+ if (ch === '"' || ch === "'" || backtick && ch === "`") {
245
+ quote = ch;
246
+ verbatim = escapes === "csharp" && ch === '"' && opensCsharpVerbatimString(content, i);
247
+ interpolated = interpolation !== void 0 && opensInterpolatedString(content, i, interpolation);
248
+ continue;
249
+ }
250
+ if (ch === "{") depth++;
251
+ else if (ch === "}") {
252
+ depth--;
253
+ if (depth === 0) {
254
+ return offsetToLine(lineIndex, i);
255
+ }
256
+ }
257
+ }
258
+ return opts?.noMatchValue ?? totalLines;
259
+ }
260
+ function assignBraceBlockSpans(symbols, content, opts = {}) {
261
+ const lineCommentPrefix = opts.lineComment;
262
+ const stringEscapes = opts.stringEscapes ?? "backslash";
263
+ const nestedBlockComments = opts.nestedBlockComments ?? false;
264
+ const tripleQuote = opts.tripleQuote ?? false;
265
+ const lineStringPrefix = opts.lineStringPrefix;
266
+ const firstLinePrefix = toLineCommentPrefixes(lineCommentPrefix)[0];
267
+ if (symbols.length === 0) return [...symbols];
268
+ const lines = content.split("\n");
269
+ const totalLines = lines.length;
270
+ const lineIndex = buildLineIndex(content);
271
+ const starts = [...new Set(symbols.map((s) => s.lineStart))].sort((a, b) => a - b);
272
+ const scanContent = opts.multilineLang === void 0 ? content : maskMultilineStrings(content, opts.multilineLang);
273
+ const blockComment = opts.blockComment !== void 0 ? opts.blockComment ?? void 0 : firstLinePrefix === "//" ? ["/*", "*/"] : firstLinePrefix === "#" ? ["<#", "#>"] : void 0;
274
+ const scanOpts = {
275
+ noMatchValue: -1,
276
+ stringEscapes,
277
+ tripleQuote,
278
+ rawStringQuotes: opts.rawStringQuotes ?? false,
279
+ tripleSingleQuote: opts.tripleSingleQuote ?? false,
280
+ tripleQuoteRunClose: opts.tripleQuoteRunClose ?? "last",
281
+ ...opts.interpolation === void 0 ? {} : { interpolation: opts.interpolation },
282
+ ...blockComment === void 0 ? {} : { blockComment, nestedBlockComments },
283
+ ...lineStringPrefix === void 0 ? {} : { lineStringPrefix },
284
+ ...opts.symbolLiterals === true ? { symbolLiterals: true } : {},
285
+ ...opts.lineCommentExceptions === void 0 ? {} : { lineCommentExceptions: opts.lineCommentExceptions }
286
+ };
287
+ return symbols.map((sym) => {
288
+ if (sym.lineEnd !== sym.lineStart) return sym;
289
+ const nextStart = starts.find((s) => s > sym.lineStart);
290
+ if (opts.expressionBodies === true) {
291
+ const arrowLast = Math.min(nextStart !== void 0 ? nextStart - 1 : totalLines, sym.lineStart + BRACE_SEARCH_MAX_LINES);
292
+ const arrowEnd = findArrowBodyEndLine(scanContent, lineIndex, sym.lineStart, arrowLast);
293
+ if (arrowEnd !== null) {
294
+ return arrowEnd <= sym.lineStart ? withWholeLineBody(sym, lines) : { ...sym, lineEnd: arrowEnd, body: lines.slice(sym.lineStart - 1, arrowEnd).join("\n") };
295
+ }
296
+ } else if (opts.expressionBodies === "kotlin") {
297
+ const eqEnd = findKotlinEqualsBodyEndLine(scanContent, lineIndex, sym.lineStart, nextStart !== void 0 ? nextStart - 1 : totalLines, opts.symbolLiterals === true);
298
+ if (eqEnd !== null) {
299
+ return eqEnd <= sym.lineStart ? withWholeLineBody(sym, lines) : { ...sym, lineEnd: eqEnd, body: lines.slice(sym.lineStart - 1, eqEnd).join("\n") };
300
+ }
301
+ }
302
+ const lastSearchLine = Math.min(nextStart !== void 0 ? nextStart - 1 : totalLines, sym.lineStart + BRACE_SEARCH_MAX_LINES);
303
+ const openIndex = findBlockOpenBrace(scanContent, lineIndex, sym.lineStart, lastSearchLine, lineCommentPrefix, TYPE_HEADER_KINDS.test(sym.kind) ? { ...scanOpts, typeHeader: true } : scanOpts);
304
+ if (openIndex === null) return sym;
305
+ if (opts.expressionBodies === "kotlin" && isAbstractValueFollowedByBareBlock(sym, scanContent, lineIndex, openIndex)) return sym;
306
+ const endLine = findMatchingBraceEndLine(
307
+ scanContent,
308
+ openIndex,
309
+ totalLines,
310
+ lineIndex,
311
+ lineCommentPrefix,
312
+ scanOpts
313
+ );
314
+ if (endLine === sym.lineStart) return withWholeLineBody(sym, lines);
315
+ if (endLine < sym.lineStart) return sym;
316
+ return { ...sym, lineEnd: endLine, body: lines.slice(sym.lineStart - 1, endLine).join("\n") };
317
+ });
318
+ }
319
+ function withWholeLineBody(sym, lines) {
320
+ const line = lines[sym.lineStart - 1];
321
+ if (line === void 0 || sym.body.includes("{") || !line.includes("{")) return sym;
322
+ return { ...sym, body: line.trimEnd() };
323
+ }
324
+ var BRACE_SEARCH_MAX_LINES = 10;
325
+ function skipCsharpInterpolationHole(content, i, to) {
326
+ let depth = 0;
327
+ for (let k = i; k < to; k++) {
328
+ const lit = skipCsharpLiteral(content, k, to);
329
+ if (lit !== null) {
330
+ k = lit - 1;
331
+ continue;
332
+ }
333
+ const ch = content[k];
334
+ if (ch === "{") depth++;
335
+ else if (ch === "}" && --depth === 0) return k + 1;
336
+ }
337
+ return to;
338
+ }
339
+ function skipCsharpLiteral(content, i, to) {
340
+ const first = content[i];
341
+ if (first === "'") {
342
+ if (content[i + 1] === "\\") {
343
+ const close = content.indexOf("'", i + 3);
344
+ return close === -1 || close >= to ? null : close + 1;
345
+ }
346
+ return content[i + 2] === "'" ? i + 3 : null;
347
+ }
348
+ let j = i;
349
+ while ((content[j] === "$" || content[j] === "@") && j - i < 3) j++;
350
+ if (content[j] !== '"') return null;
351
+ const prefix = content.slice(i, j);
352
+ if (j > i && /[A-Za-z0-9_]/.test(content[i - 1] ?? "")) return null;
353
+ const interpolated = prefix.includes("$");
354
+ const verbatim = prefix.includes("@");
355
+ const run = quoteRunLength(content, j);
356
+ if (run >= 3) {
357
+ const end = skipRawStringQuotes(content, j + run, run);
358
+ return end === -1 ? to : end;
359
+ }
360
+ for (let k = j + 1; k < to; k++) {
361
+ const ch = content[k];
362
+ if (ch === void 0) break;
363
+ if (verbatim) {
364
+ if (ch === '"') {
365
+ if (content[k + 1] === '"') {
366
+ k++;
367
+ continue;
368
+ }
369
+ return k + 1;
370
+ }
371
+ } else if (ch === "\\") {
372
+ k++;
373
+ continue;
374
+ } else if (ch === '"') return k + 1;
375
+ if (interpolated) {
376
+ if (ch === "{") {
377
+ if (content[k + 1] === "{") {
378
+ k++;
379
+ continue;
380
+ }
381
+ k = skipCsharpInterpolationHole(content, k, to) - 1;
382
+ }
383
+ }
384
+ }
385
+ return to;
386
+ }
387
+ function findArrowBodyEndLine(content, lineIndex, startLine, lastSearchLine) {
388
+ const from = lineIndex[startLine - 1];
389
+ if (from === void 0) return null;
390
+ const to = lineIndex[lastSearchLine] ?? content.length;
391
+ let depth = 0;
392
+ let seenArrow = false;
393
+ for (let i = from; i < to; i++) {
394
+ const ch = content[i];
395
+ if (ch === void 0) break;
396
+ if (ch === "/" && content[i + 1] === "/") {
397
+ while (i + 1 < to && content[i + 1] !== "\n") i++;
398
+ continue;
399
+ }
400
+ if (ch === "/" && content[i + 1] === "*") {
401
+ const end = content.indexOf("*/", i + 2);
402
+ if (end === -1) return null;
403
+ i = end + 1;
404
+ continue;
405
+ }
406
+ const lit = skipCsharpLiteral(content, i, to);
407
+ if (lit !== null) {
408
+ i = lit - 1;
409
+ continue;
410
+ }
411
+ if (ch === "(" || ch === "[") depth++;
412
+ else if (ch === ")" || ch === "]") {
413
+ if (depth > 0) depth--;
414
+ } else if (ch === "=" && content[i + 1] === ">" && depth === 0) {
415
+ seenArrow = true;
416
+ i++;
417
+ } else if (ch === "{") {
418
+ if (!seenArrow && depth === 0) return null;
419
+ depth++;
420
+ } else if (ch === "}") {
421
+ if (depth === 0) return null;
422
+ depth--;
423
+ } else if (ch === ";" && depth === 0) {
424
+ if (!seenArrow) return null;
425
+ let line = startLine;
426
+ for (let k = from; k < i; k++) if (content[k] === "\n") line++;
427
+ return line;
428
+ }
429
+ }
430
+ return null;
431
+ }
432
+ function skipKotlinTemplateHole(content, i, to, symbolLiterals = false) {
433
+ let depth = 0;
434
+ for (let k = i; k < to; k++) {
435
+ const lit = skipKotlinLiteral(content, k, to, symbolLiterals);
436
+ if (lit !== null) {
437
+ k = lit - 1;
438
+ continue;
439
+ }
440
+ const ch = content[k];
441
+ if (ch === "{") depth++;
442
+ else if (ch === "}" && --depth === 0) return k + 1;
443
+ }
444
+ return to;
445
+ }
446
+ function skipKotlinLiteral(content, i, to, symbolLiterals = false) {
447
+ const first = content[i];
448
+ if (first === "'" && symbolLiterals) {
449
+ const len = scalaCharLiteralLength(content, i);
450
+ return len > 0 ? i + len : null;
451
+ }
452
+ if (first === "'") {
453
+ for (let k = i + 1; k < to && content[k] !== "\n"; k++) {
454
+ if (content[k] === "\\") {
455
+ k++;
456
+ continue;
457
+ }
458
+ if (content[k] === "'") return k + 1;
459
+ }
460
+ return null;
461
+ }
462
+ if (first !== '"') return null;
463
+ const triple = content.startsWith('"""', i);
464
+ for (let k = i + (triple ? 3 : 1); k < to; k++) {
465
+ const ch = content[k];
466
+ if (triple) {
467
+ if (ch === '"' && content.startsWith('"""', k)) {
468
+ k += 3;
469
+ while (content[k] === '"') k++;
470
+ return k;
471
+ }
472
+ } else if (ch === "\\") {
473
+ k++;
474
+ continue;
475
+ } else if (ch === '"') return k + 1;
476
+ else if (ch === "\n") return k;
477
+ if (ch === "$" && content[k + 1] === "{") k = skipKotlinTemplateHole(content, k + 1, to, symbolLiterals) - 1;
478
+ }
479
+ return to;
480
+ }
481
+ function opensInterpolatedString(content, i, lang) {
482
+ const q = content[i];
483
+ const prev = content[i - 1] ?? "";
484
+ if (lang === "csharp") return q === '"' && (prev === "$" || prev === "@" && content[i - 2] === "$");
485
+ if (lang === "scala") return q === '"' && /[A-Za-z0-9_]/.test(prev);
486
+ if (lang === "dart") return !(prev === "r" && !/[A-Za-z0-9_$]/.test(content[i - 2] ?? ""));
487
+ return q === '"';
488
+ }
489
+ function skipInterpolationAt(content, i, to, lang) {
490
+ const ch = content[i];
491
+ if (lang === "swift") return ch === "\\" && content[i + 1] === "(" ? skipInterpolationHole(content, i + 1, to, lang) : null;
492
+ if (lang === "csharp") {
493
+ if (ch !== "{") return null;
494
+ return content[i + 1] === "{" ? i + 2 : skipInterpolationHole(content, i, to, lang);
495
+ }
496
+ return ch === "$" && content[i + 1] === "{" ? skipInterpolationHole(content, i + 1, to, lang) : null;
497
+ }
498
+ function skipInterpolationHole(content, i, to, lang) {
499
+ const open = content[i];
500
+ const close = open === "(" ? ")" : "}";
501
+ let depth = 0;
502
+ for (let k = i; k < to; k++) {
503
+ const lit = skipNestedLiteral(content, k, to, lang);
504
+ if (lit !== null) {
505
+ k = lit - 1;
506
+ continue;
507
+ }
508
+ const ch = content[k];
509
+ if (ch === open) depth++;
510
+ else if (ch === close && --depth === 0) return k + 1;
511
+ }
512
+ return to;
513
+ }
514
+ function skipNestedLiteral(content, i, to, lang) {
515
+ const ch = content[i];
516
+ if (lang === "csharp") return skipCsharpLiteral(content, i, to);
517
+ if (lang === "kotlin") return skipKotlinLiteral(content, i, to);
518
+ if (ch === "'" && lang === "scala") {
519
+ const len = scalaCharLiteralLength(content, i);
520
+ return len > 0 ? i + len : null;
521
+ }
522
+ if (ch !== '"' && !(ch === "'" && lang === "dart")) return null;
523
+ return skipInterpolatedString(content, i, to, lang, opensInterpolatedString(content, i, lang));
524
+ }
525
+ function skipInterpolatedString(content, i, to, lang, interpolated) {
526
+ const q = content[i];
527
+ if (content.startsWith(q + q + q, i)) {
528
+ const end = content.indexOf(q + q + q, i + 3);
529
+ return end === -1 || end >= to ? to : end + 3;
530
+ }
531
+ for (let k = i + 1; k < to; k++) {
532
+ const ch = content[k];
533
+ if (ch === "\n") return k;
534
+ if (interpolated) {
535
+ const past = skipInterpolationAt(content, k, to, lang);
536
+ if (past !== null) {
537
+ k = past - 1;
538
+ continue;
539
+ }
540
+ }
541
+ if (ch === "\\") {
542
+ k++;
543
+ continue;
544
+ }
545
+ if (ch === q) return k + 1;
546
+ }
547
+ return to;
548
+ }
549
+ function kotlinBodyContinues(content, lastSig, ifParenClosedAt, nextLineFrom) {
550
+ const c = content[lastSig];
551
+ const prev = content[lastSig - 1];
552
+ if (lastSig === ifParenClosedAt) return true;
553
+ if (c !== void 0 && "=*/%&|,.:".includes(c)) return true;
554
+ if ((c === "+" || c === "-") && prev !== c) return true;
555
+ if (c === ">" && prev === "-") return true;
556
+ if (/(?:^|[^A-Za-z0-9_])else$/.test(content.slice(Math.max(0, lastSig - 4), lastSig + 1))) return true;
557
+ const rest = content.slice(nextLineFrom);
558
+ const next = /^(?:[ \t\r]*(?:\/\/[^\n]*)?\n)*[ \t]*(\.|\?\.|\?:|&&|\|\||else\b|as\b|catch\b|finally\b)/.exec(rest);
559
+ return next !== null;
560
+ }
561
+ var NEXT_LINE_STARTS_WITH_EQUALS = /^(?:[ \t\r]*(?:\/\/[^\n]*)?\n)*[ \t]*=(?!=)/;
562
+ function findKotlinEqualsBodyEndLine(content, lineIndex, startLine, lastLine, symbolLiterals = false) {
563
+ const from = lineIndex[startLine - 1];
564
+ if (from === void 0) return null;
565
+ const to = lineIndex[lastLine] ?? content.length;
566
+ let depth = 0;
567
+ let seenEq = false;
568
+ let line = startLine;
569
+ let lastSig = -1;
570
+ let ifParenClosedAt = -1;
571
+ const ifParens = [];
572
+ for (let i = from; i < to; i++) {
573
+ const ch = content[i];
574
+ if (ch === void 0) break;
575
+ if (ch === "\n") {
576
+ if (depth === 0) {
577
+ if (!seenEq && !NEXT_LINE_STARTS_WITH_EQUALS.test(content.slice(i + 1, to))) return null;
578
+ if (seenEq && !kotlinBodyContinues(content, lastSig, ifParenClosedAt, i + 1)) return line;
579
+ }
580
+ line++;
581
+ continue;
582
+ }
583
+ if (ch === " " || ch === " " || ch === "\r") continue;
584
+ if (ch === "/" && content[i + 1] === "/") {
585
+ while (i + 1 < to && content[i + 1] !== "\n") i++;
586
+ continue;
587
+ }
588
+ if (ch === "/" && content[i + 1] === "*") {
589
+ const end = content.indexOf("*/", i + 2);
590
+ if (end === -1) return null;
591
+ for (let k = i; k < end; k++) if (content[k] === "\n") line++;
592
+ i = end + 1;
593
+ continue;
594
+ }
595
+ const lit = skipKotlinLiteral(content, i, to, symbolLiterals);
596
+ if (lit !== null) {
597
+ for (let k = i; k < lit; k++) if (content[k] === "\n") line++;
598
+ lastSig = lit - 1;
599
+ i = lit - 1;
600
+ continue;
601
+ }
602
+ lastSig = i;
603
+ if (ch === "(" || ch === "[" || ch === "{") {
604
+ if (ch === "{" && !seenEq && depth === 0) return null;
605
+ ifParens.push(ch === "(" && /\bif\s*$/.test(content.slice(Math.max(from, i - 8), i)));
606
+ depth++;
607
+ } else if (ch === ")" || ch === "]" || ch === "}") {
608
+ if (depth === 0) return null;
609
+ depth--;
610
+ if (ifParens.pop() === true) ifParenClosedAt = i;
611
+ } else if (ch === "=" && !seenEq && depth === 0 && !"=!<>".includes(content[i - 1] ?? " ") && content[i + 1] !== "=") {
612
+ seenEq = true;
613
+ }
614
+ }
615
+ return seenEq && depth === 0 ? line : null;
616
+ }
617
+ function maskMultilineStrings(content, lang) {
618
+ let state = null;
619
+ const parts = [];
620
+ let pos = 0;
621
+ for (; ; ) {
622
+ const nl = content.indexOf("\n", pos);
623
+ const end = nl === -1 ? content.length : nl;
624
+ const lineEnd = end > pos && content[end - 1] === "\r" ? end - 1 : end;
625
+ const masked = stripMultilineStringSpan(content.slice(pos, lineEnd), state, lang);
626
+ state = masked.state;
627
+ parts.push(masked.code, content.slice(lineEnd, end));
628
+ if (nl === -1) break;
629
+ parts.push("\n");
630
+ pos = nl + 1;
631
+ }
632
+ return parts.join("");
633
+ }
634
+ function findBlockOpenBrace(content, lineIndex, startLine, lastSearchLine, lineCommentPrefix, opts) {
635
+ const blockComment = opts?.blockComment;
636
+ const stringEscapes = opts?.stringEscapes ?? "backslash";
637
+ const nestedBlockComments = opts?.nestedBlockComments === true;
638
+ const rawString = opts?.rawStringQuotes === true;
639
+ const tripleDelims = tripleQuoteDelimiters(opts);
640
+ const lineString = opts?.lineStringPrefix;
641
+ const linePrefixes = toLineCommentPrefixes(lineCommentPrefix);
642
+ const lineExceptions = opts?.lineCommentExceptions ?? [];
643
+ const from = lineIndex[startLine - 1];
644
+ if (from === void 0) return null;
645
+ const to = lineIndex[lastSearchLine] ?? content.length;
646
+ const interpolation = opts?.interpolation;
647
+ let interpolated = false;
648
+ let quote = null;
649
+ let parenDepth = 0;
650
+ let linesSeen = 0;
651
+ let atLineStart = false;
652
+ let verbatim = false;
653
+ for (let i = from; i < to; i++) {
654
+ const ch = content[i];
655
+ if (ch === void 0) break;
656
+ if (quote !== null) {
657
+ if (interpolated && interpolation !== void 0) {
658
+ const past = skipInterpolationAt(content, i, to, interpolation);
659
+ if (past !== null) {
660
+ i = past - 1;
661
+ continue;
662
+ }
663
+ }
664
+ if (verbatim) {
665
+ if (ch === quote) {
666
+ if (content[i + 1] === quote) {
667
+ i++;
668
+ continue;
669
+ }
670
+ quote = null;
671
+ verbatim = false;
672
+ }
673
+ continue;
674
+ }
675
+ if (stringEscapes === "powershell") {
676
+ const step = stepPowershellString(content, i, quote);
677
+ i = step.next;
678
+ if (!step.open) quote = null;
679
+ continue;
680
+ }
681
+ if (ch === "\\") {
682
+ i++;
683
+ continue;
684
+ }
685
+ if (ch === quote) quote = null;
686
+ continue;
687
+ }
688
+ if (ch === "\n") {
689
+ linesSeen++;
690
+ atLineStart = true;
691
+ continue;
692
+ }
693
+ if (blockComment !== void 0 && content.startsWith(blockComment[0], i)) {
694
+ const end = skipBlockComment(content, i, blockComment, nestedBlockComments);
695
+ if (end === -1) return null;
696
+ i = end - 1;
697
+ continue;
698
+ }
699
+ if (atLineComment(content, i, linePrefixes, lineExceptions)) {
700
+ while (i + 1 < to && content[i + 1] !== "\n") i++;
701
+ continue;
702
+ }
703
+ if (atLineStart && !/\s/.test(ch)) {
704
+ atLineStart = false;
705
+ if (parenDepth === 0 && linesSeen >= 1 && startsWithBlockKeyword(content, i, to, opts?.typeHeader !== true)) return null;
706
+ }
707
+ if (lineString !== void 0 && content.startsWith(lineString, i)) {
708
+ while (i + 1 < to && content[i + 1] !== "\n") i++;
709
+ continue;
710
+ }
711
+ if (rawString && ch === '"') {
712
+ const run = quoteRunLength(content, i);
713
+ if (run >= 3) {
714
+ const end = skipRawStringQuotes(content, i + run, run);
715
+ if (end === -1) return null;
716
+ i = end - 1;
717
+ continue;
718
+ }
719
+ }
720
+ const tripleAt = tripleDelims.find((t) => content.startsWith(t, i));
721
+ if (tripleAt !== void 0) {
722
+ const end = closingQuoteRunEnd(content, i + 3, tripleAt[0] ?? '"', 3, opts?.tripleQuoteRunClose ?? "last");
723
+ if (end === -1) return null;
724
+ i = end - 1;
725
+ continue;
726
+ }
727
+ if (ch === "'" && opts?.symbolLiterals === true) {
728
+ const charLen = scalaCharLiteralLength(content, i);
729
+ if (charLen > 0) i += charLen - 1;
730
+ continue;
731
+ }
732
+ if (ch === '"' || ch === "'") {
733
+ quote = ch;
734
+ verbatim = stringEscapes === "csharp" && ch === '"' && opensCsharpVerbatimString(content, i);
735
+ interpolated = interpolation !== void 0 && opensInterpolatedString(content, i, interpolation);
736
+ continue;
737
+ }
738
+ if (ch === "(" || ch === "[") parenDepth++;
739
+ else if (ch === ")" || ch === "]") {
740
+ if (parenDepth > 0) parenDepth--;
741
+ } else if (ch === ";") return null;
742
+ else if (ch === "}" && parenDepth === 0) return null;
743
+ else if (ch === "{") return i;
744
+ }
745
+ return null;
746
+ }
747
+ var BLOCK_OPENING_KEYWORDS = /* @__PURE__ */ new Set([
748
+ "if",
749
+ "for",
750
+ "while",
751
+ "do",
752
+ "switch",
753
+ "when",
754
+ "match",
755
+ "try",
756
+ "foreach",
757
+ "loop",
758
+ "guard",
759
+ "repeat",
760
+ "unless",
761
+ "until"
762
+ ]);
763
+ function isAbstractValueFollowedByBareBlock(sym, content, lineIndex, openIndex) {
764
+ const openLine = offsetToLine(lineIndex, openIndex);
765
+ return /^va[lr]$/.test(sym.kind) && openLine > sym.lineStart && lineTextAt(content, lineIndex, openLine) === "{" && !lineTextAt(content, lineIndex, sym.lineStart).includes("=");
766
+ }
767
+ var TYPE_HEADER_KINDS = /^(?:class|object|interface|trait|enum|struct|protocol|record|extension)$/;
768
+ var MEMBER_START_WORDS = /* @__PURE__ */ new Set(["init", "locally", "constructor", "companion"]);
769
+ function startsWithBlockKeyword(content, i, to, members) {
770
+ const first = content[i];
771
+ if (first === void 0 || !/[A-Za-z_]/.test(first)) return false;
772
+ let j = i + 1;
773
+ while (j < to && /[A-Za-z0-9_]/.test(content[j])) j++;
774
+ const word = content.slice(i, j);
775
+ return BLOCK_OPENING_KEYWORDS.has(word) || members && MEMBER_START_WORDS.has(word);
776
+ }
777
+
85
778
  // src/languages/csharp.ts
86
779
  init_define_import_meta_env();
87
780
  var IDENT = "@?[A-Za-z_][A-Za-z0-9_]*";
@@ -167,6 +860,66 @@ function nextCodeLines(lines, from, count) {
167
860
  }
168
861
  return out;
169
862
  }
863
+ function typeKind(keyword) {
864
+ return keyword === "struct" ? "struct" : keyword === "interface" ? "interface" : keyword === "enum" ? "enum" : "class";
865
+ }
866
+ function operatorName(opM) {
867
+ return opM[1] !== void 0 ? `operator ${opM[1].replace(/\s+/g, " ").trim()}` : `operator${opM[2] !== void 0 ? " checked " : ""}${opM[3] ?? ""}`;
868
+ }
869
+ function memberDecls(decl, parent) {
870
+ const delM = DELEGATE_RE.exec(decl);
871
+ if (delM) return [[stripVerbatim(delM[1] ?? ""), "type"]];
872
+ const eventM = EVENT_RE.exec(decl);
873
+ if (eventM) {
874
+ const out = [];
875
+ for (const part of splitEventDeclarators(decl.slice(eventM[0].length).split(/[;{]/)[0] ?? "")) {
876
+ const declM = EVENT_NAME_RE.exec(part.split("=")[0]?.trim() ?? "");
877
+ if (declM) out.push([stripVerbatim(declM[1] ?? ""), "var"]);
878
+ }
879
+ return out;
880
+ }
881
+ const ctorM = CONSTRUCTOR_RE.exec(decl);
882
+ if (ctorM && stripVerbatim(ctorM[1] ?? "") === parent) return [[parent, "method"]];
883
+ const propM = PROPERTY_RE.exec(decl) ?? PROPERTY_ARROW_RE.exec(decl);
884
+ if (propM) return [[stripVerbatim(propM[1] ?? ""), "var"]];
885
+ const finM = FINALIZER_RE.exec(decl);
886
+ if (finM && stripVerbatim(finM[1] ?? "") === parent) return [[`~${parent}`, "method"]];
887
+ const opM = OPERATOR_RE.exec(decl);
888
+ if (opM && isDeclarationPrefix(decl.slice(0, opM.index))) return [[operatorName(opM), "method"]];
889
+ const ixM = INDEXER_RE.exec(decl);
890
+ if (ixM && isDeclarationPrefix(decl.slice(0, ixM.index))) return [["this[]", "var"]];
891
+ const methM = METHOD_RE.exec(decl);
892
+ const mname = methM ? stripVerbatim(methM[1] ?? "") : "";
893
+ return mname && mname !== parent ? [[mname, "method"]] : [];
894
+ }
895
+ function inlineCsharpMembers(line, code, segs, parent, filePath, lineNum, level = 0) {
896
+ const members = [];
897
+ const opens = [];
898
+ for (const seg of segs) {
899
+ const text = line.slice(seg.start, seg.end).trim();
900
+ const decl = stripLeadingAttributes(text);
901
+ const classM = CLASS_HEADER_RE.exec(decl);
902
+ if (classM) {
903
+ const brace = bodyBraceAt(code, seg.start, seg.end);
904
+ if (seg.open && brace === -1) continue;
905
+ const name = stripVerbatim(classM[2] ?? "");
906
+ const typeSym = makeLineSymbol(filePath, name, typeKind(classM[1] ?? "class"), lineNum, text, parent);
907
+ members.push(typeSym);
908
+ if (brace !== -1) {
909
+ const inner = inlineCsharpMembers(line, code, bodySegments(code, brace + 1), name, filePath, lineNum, level + 1);
910
+ members.push(...inner.members);
911
+ if (seg.open) opens.push({ sym: typeSym, level, isType: true }, ...inner.opens);
912
+ }
913
+ continue;
914
+ }
915
+ for (const [name, kind] of memberDecls(decl, parent)) {
916
+ const sym = makeLineSymbol(filePath, name, kind, lineNum, text, parent);
917
+ members.push(sym);
918
+ if (seg.open) opens.push({ sym, level, isType: false });
919
+ }
920
+ }
921
+ return { members, opens };
922
+ }
170
923
  var CS_REF_NOISE = /* @__PURE__ */ new Set([
171
924
  "if",
172
925
  "else",
@@ -272,6 +1025,8 @@ function extractCsharp(content, filePath) {
272
1025
  let falseNesting = 0;
273
1026
  let currentMember;
274
1027
  let memberBodyEntered = false;
1028
+ const settled = /* @__PURE__ */ new Set();
1029
+ let openMembers = [];
275
1030
  for (let i = 0; i < lines.length; i++) {
276
1031
  const rawLine = lines[i] ?? "";
277
1032
  const lineNum = i + 1;
@@ -313,13 +1068,11 @@ function extractCsharp(content, filePath) {
313
1068
  const delegateParent = classStack.length > 0 ? classStack[classStack.length - 1].name : void 0;
314
1069
  symbols.push(makeLineSymbol(filePath, stripVerbatim(delM[1] ?? ""), "type", lineNum, stripped.slice(0, 200), delegateParent, lines, "c"));
315
1070
  }
1071
+ const outerFrame = classStack.length > 0 ? classStack[classStack.length - 1] : null;
316
1072
  const cm = CLASS_HEADER_RE.exec(stripLeadingAttributes(stripped));
317
1073
  if (cm) {
318
- const keyword = cm[1] ?? "class";
319
1074
  const cname = stripVerbatim(cm[2] ?? "");
320
- const kind = keyword === "struct" ? "struct" : keyword === "interface" ? "interface" : keyword === "enum" ? "enum" : "class";
321
- const parent = classStack.length > 0 ? classStack[classStack.length - 1].name : void 0;
322
- symbols.push(makeLineSymbol(filePath, cname, kind, lineNum, stripped.slice(0, 200), parent, lines, "c"));
1075
+ symbols.push(makeLineSymbol(filePath, cname, typeKind(cm[1] ?? "class"), lineNum, stripped.slice(0, 200), outerFrame?.name, lines, "c"));
323
1076
  classStack.push({ name: cname, startDepth: braceDepth, bodyEntered: false });
324
1077
  }
325
1078
  let ctorM = null;
@@ -386,7 +1139,7 @@ function extractCsharp(content, filePath) {
386
1139
  if (finM && stripVerbatim(finM[1] ?? "") === frame.name) specialName = `~${frame.name}`;
387
1140
  else finM = null;
388
1141
  const opM = specialName === null && !isPropertyLine ? OPERATOR_RE.exec(lineNoAttr) : null;
389
- if (opM && isDeclarationPrefix(lineNoAttr.slice(0, opM.index))) specialName = opM[1] !== void 0 ? `operator ${opM[1].replace(/\s+/g, " ").trim()}` : `operator${opM[2] !== void 0 ? " checked " : ""}${opM[3] ?? ""}`;
1142
+ if (opM && isDeclarationPrefix(lineNoAttr.slice(0, opM.index))) specialName = operatorName(opM);
390
1143
  const ixM = specialName === null && !isPropertyLine ? INDEXER_RE.exec(lineNoAttr) : null;
391
1144
  if (ixM && isDeclarationPrefix(lineNoAttr.slice(0, ixM.index))) {
392
1145
  specialName = "this[]";
@@ -416,6 +1169,30 @@ function extractCsharp(content, filePath) {
416
1169
  const isInterpolatedLine = rawLine.includes('$"') || rawLine.includes('$@"') || rawLine.includes('@$"');
417
1170
  const baseLine = isInterpolatedLine ? stripLineComment(rawLine) : stripLineComment(line);
418
1171
  const braceLine = stripStringLiterals(baseLine, { tripleQuotes: true });
1172
+ const segCode = stripStringLiterals(line, { tripleQuotes: true });
1173
+ const lineOpens = [];
1174
+ const queueMembers = (segs, parent, bodyDepth) => {
1175
+ const { members, opens } = inlineCsharpMembers(line, segCode, segs, parent, filePath, lineNum);
1176
+ symbols.push(...members);
1177
+ for (const m of members) settled.add(m);
1178
+ lineOpens.push(...openMembersOf(opens, bodyDepth));
1179
+ for (const o of opens) {
1180
+ if (!o.isType) continue;
1181
+ const enclosing = classStack[classStack.length - 1];
1182
+ if (enclosing !== void 0) enclosing.bodyEntered = true;
1183
+ classStack.push({ name: o.sym.name, startDepth: bodyDepth + o.level, bodyEntered: true });
1184
+ }
1185
+ };
1186
+ const lineSegs = bodySegments(segCode, 0);
1187
+ if (frame !== null && frame !== outerFrame && lineSegs[0] !== void 0) {
1188
+ const brace = bodyBraceAt(segCode, lineSegs[0].start, lineSegs[0].end);
1189
+ if (brace !== -1) queueMembers(bodySegments(segCode, brace + 1), frame.name, braceDepth + 1);
1190
+ }
1191
+ const insideMember = outerFrame === null ? -1 : braceDepth - outerFrame.startDepth - 1;
1192
+ if (outerFrame !== null && insideMember >= 0) {
1193
+ const resume = bodyResumeAt(segCode, insideMember);
1194
+ if (resume >= 0) queueMembers(insideMember === 0 ? lineSegs.slice(1) : bodySegments(segCode, resume), outerFrame.name, outerFrame.startDepth + 1);
1195
+ }
419
1196
  if (!inFalseBlock && !stripped.startsWith("#")) {
420
1197
  const declSpans = [];
421
1198
  if (cm) {
@@ -524,6 +1301,8 @@ function extractCsharp(content, filePath) {
524
1301
  const openBraces = (braceLine.match(/\{/g) ?? []).length;
525
1302
  const closeBraces = (braceLine.match(/\}/g) ?? []).length;
526
1303
  braceDepth += openBraces - closeBraces;
1304
+ openMembers = endOpenMembers(symbols, settled, openMembers, braceDepth, lineNum, lines);
1305
+ openMembers.push(...lineOpens);
527
1306
  if (currentMember !== void 0) {
528
1307
  if (!memberBodyEntered) {
529
1308
  if (openBraces > 0 && braceDepth > (frame?.startDepth ?? 0) + 1) {
@@ -554,7 +1333,7 @@ function extractCsharp(content, filePath) {
554
1333
  }
555
1334
  }
556
1335
  }
557
- return { symbols, refs, imports };
1336
+ return { symbols, refs, imports, settled };
558
1337
  }
559
1338
 
560
1339
  // src/languages/php.ts
@@ -582,6 +1361,18 @@ var USE_RE = /^use\s+(?:function\s+|const\s+)?([\w\\]+)(?:\s+as\s+\w+)?\s*;/i;
582
1361
  var GROUP_USE_RE = /^use\s+(?:function\s+|const\s+)?([\w\\]+)\\\{([^}]*)\}/i;
583
1362
  var REQUIRE_RE = /^(?:require|include)(?:_once)?\s+['"]([^'"]+)['"]/i;
584
1363
  var ENUM_CASE_RE = /^case\s+([A-Za-z_][A-Za-z0-9_]*)\s*(?:=|;)/i;
1364
+ function inlinePhpMember(text, kind, parent, filePath, lineNum) {
1365
+ const enumCaseM = kind === "enum" && parent !== void 0 ? ENUM_CASE_RE.exec(text) : null;
1366
+ if (enumCaseM) return makeLineSymbol(filePath, enumCaseM[1] ?? "", "const", lineNum, text, parent);
1367
+ if (ANON_FN_RE.test(text)) return null;
1368
+ const methM = METHOD_RE2.exec(text);
1369
+ if (methM) return makeLineSymbol(filePath, methM[1] ?? "", parent === void 0 ? "function" : "method", lineNum, text, parent);
1370
+ const propM = parent === void 0 ? null : PROP_RE.exec(text);
1371
+ if (propM) return makeLineSymbol(filePath, propM[1] ?? "", "var", lineNum, text, parent);
1372
+ const constM = CONST_RE.exec(text);
1373
+ if (constM) return makeLineSymbol(filePath, constM[1] ?? "", "const", lineNum, text, parent);
1374
+ return null;
1375
+ }
585
1376
  function maskPhpInlineHtml(content) {
586
1377
  const opener = /<\?(?:php\b|=)/i;
587
1378
  if (!opener.test(content)) return content;
@@ -612,12 +1403,34 @@ function extractPhp(content, filePath) {
612
1403
  const symbols = [];
613
1404
  const imports = [];
614
1405
  const lines = maskPhpInlineHtml(content).split(/\r?\n/);
1406
+ const settled = /* @__PURE__ */ new Set();
1407
+ let lineMembers = [];
1408
+ let openMember = null;
1409
+ let pendingBrace = null;
1410
+ const queueMembers = (segs, line, kind, parent, lineNum, bodyDepth) => {
1411
+ let open = null;
1412
+ for (const seg of segs) {
1413
+ const text = line.slice(seg.start, seg.end).trim();
1414
+ const sym = inlinePhpMember(text, kind, parent, filePath, lineNum);
1415
+ if (sym === null) continue;
1416
+ lineMembers.push(sym);
1417
+ settled.add(sym);
1418
+ if (seg.open) open = { sym, depth: bodyDepth + 1 };
1419
+ else if (seg === segs[segs.length - 1] && sym.kind !== "const" && sym.kind !== "var" && !/[;}]$/.test(text) && stripStringLiterals(text).split("(").length === stripStringLiterals(text).split(")").length) pendingBrace = { sym, depth: bodyDepth + 1 };
1420
+ }
1421
+ return open;
1422
+ };
1423
+ const flushMembers = () => {
1424
+ symbols.push(...lineMembers);
1425
+ lineMembers = [];
1426
+ };
615
1427
  const contextStack = [];
616
1428
  let braceDepth = 0;
617
1429
  let parenDepth = 0;
618
1430
  let inComment = false;
619
1431
  let mlState = null;
620
1432
  for (let i = 0; i < lines.length; i++) {
1433
+ flushMembers();
621
1434
  const rawLine = lines[i] ?? "";
622
1435
  const lineNum = i + 1;
623
1436
  let mlLine = rawLine;
@@ -645,6 +1458,23 @@ function extractPhp(content, filePath) {
645
1458
  if (topFrame !== void 0 && braceDepth > topFrame[1]) {
646
1459
  topFrame[2] = true;
647
1460
  }
1461
+ if (pendingBrace !== null) {
1462
+ if (stripped.startsWith("{")) openMember = pendingBrace;
1463
+ pendingBrace = null;
1464
+ }
1465
+ if (openMember !== null && braceDepth < openMember.depth) {
1466
+ endOpenMember(symbols, settled, openMember, lineNum, lines);
1467
+ openMember = null;
1468
+ }
1469
+ const bodyBase = topFrame === void 0 ? 0 : topFrame[1] + 1;
1470
+ const preDepth = braceDepth - openB + closeB;
1471
+ if ((topFrame === void 0 || topFrame[2]) && preDepth >= bodyBase && preLineParenDepth === 0) {
1472
+ const resume = bodyResumeAt(braceLine, preDepth - bodyBase);
1473
+ if (resume >= 0 && (preDepth > bodyBase || topFrame !== void 0)) {
1474
+ const segs = bodySegments(braceLine, resume);
1475
+ openMember = queueMembers(preDepth === bodyBase ? segs.slice(1) : segs, line, topFrame?.[3] ?? "file", topFrame?.[0], lineNum, bodyBase) ?? openMember;
1476
+ }
1477
+ }
648
1478
  while (contextStack.length > 0) {
649
1479
  const top = contextStack[contextStack.length - 1];
650
1480
  if (top !== void 0 && top[2] && braceDepth <= top[1]) {
@@ -691,6 +1521,8 @@ function extractPhp(content, filePath) {
691
1521
  const parent = topFrame2 !== void 0 && preLineDepth === topFrame2[1] + 1 ? topFrame2[0] : null;
692
1522
  symbols.push(makeLineSymbol(filePath, name, kind, lineNum, stripped.slice(0, 200), parent ?? void 0, lines, "c"));
693
1523
  contextStack.push([name, braceDepth - openB + closeB, false, kind]);
1524
+ const bodyOpen = braceLine.indexOf("{");
1525
+ if (bodyOpen !== -1) openMember = queueMembers(bodySegments(braceLine, bodyOpen + 1), line, kind, name, lineNum, preLineDepth + 1) ?? openMember;
694
1526
  if (openB > 0 && openB === closeB) {
695
1527
  contextStack.pop();
696
1528
  }
@@ -742,7 +1574,8 @@ function extractPhp(content, filePath) {
742
1574
  symbols.push(makeLineSymbol(filePath, defineM[1] ?? "", "const", lineNum, stripped.slice(0, 200), void 0, lines, "c"));
743
1575
  }
744
1576
  }
745
- return { symbols, imports };
1577
+ flushMembers();
1578
+ return { symbols, imports, settled };
746
1579
  }
747
1580
 
748
1581
  // src/languages/html.ts
@@ -791,20 +1624,66 @@ function isNoise(name) {
791
1624
  }
792
1625
  var MAX_SYMBOLS = 1e4;
793
1626
  var VOID_ELEMENTS = /* @__PURE__ */ new Set(["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"]);
794
- var TAG_RE = /<(\/?)([a-zA-Z][a-zA-Z0-9:-]*)(?:\s(?:"[^"]*"|'[^']*'|[^'">])*)?>/g;
1627
+ function makeTagScanner(code) {
1628
+ const head = /<(\/?)([a-zA-Z][a-zA-Z0-9:-]*)/g;
1629
+ const stop = /[>"']/g;
1630
+ let dead = null;
1631
+ return (from) => {
1632
+ head.lastIndex = from;
1633
+ let m;
1634
+ while ((m = head.exec(code)) !== null) {
1635
+ const nameEnd = m.index + m[0].length;
1636
+ let end = -1;
1637
+ if (code[nameEnd] === ">") {
1638
+ end = nameEnd + 1;
1639
+ } else if (nameEnd < code.length && /\s/.test(code[nameEnd])) {
1640
+ let i = nameEnd + 1;
1641
+ const outside = [];
1642
+ for (; ; ) {
1643
+ if (dead !== null && dead[i] === 1) break;
1644
+ stop.lastIndex = i;
1645
+ const h = stop.exec(code);
1646
+ if (h === null) {
1647
+ outside.push(i, code.length + 1);
1648
+ break;
1649
+ }
1650
+ if (h[0] === ">") {
1651
+ end = h.index + 1;
1652
+ break;
1653
+ }
1654
+ outside.push(i, h.index + 1);
1655
+ const closeQuote = code.indexOf(h[0], h.index + 1);
1656
+ if (closeQuote < 0) break;
1657
+ i = closeQuote + 1;
1658
+ }
1659
+ if (end < 0 && outside.length > 0) {
1660
+ dead ??= new Uint8Array(code.length + 2);
1661
+ for (let k = 0; k < outside.length; k += 2) dead.fill(1, outside[k], outside[k + 1]);
1662
+ }
1663
+ }
1664
+ if (end >= 0) {
1665
+ return { start: m.index, end, isClose: m[1] === "/", name: (m[2] ?? "").toLowerCase(), selfClosing: code[end - 2] === "/" };
1666
+ }
1667
+ head.lastIndex = m.index + 1;
1668
+ }
1669
+ return null;
1670
+ };
1671
+ }
795
1672
  var ELEMENT_SPAN_SCAN_CAP = 2e6;
796
1673
  function buildElementSpans(code) {
797
1674
  const spans = /* @__PURE__ */ new Map();
798
1675
  const openTagRanges = [];
799
1676
  const stack = [];
800
- TAG_RE.lastIndex = 0;
1677
+ const nextTag = makeTagScanner(code);
1678
+ const styleClose = /<\/style\s*>/gi;
1679
+ let styleCloseMissing = false;
1680
+ let from = 0;
801
1681
  let m;
802
- while ((m = TAG_RE.exec(code)) !== null) {
803
- if (m.index > ELEMENT_SPAN_SCAN_CAP) break;
804
- const isClose = m[1] === "/";
805
- const name = (m[2] ?? "").toLowerCase();
806
- const selfClosing = m[0][m[0].length - 2] === "/";
807
- const tagEnd = m.index + m[0].length;
1682
+ while ((m = nextTag(from)) !== null) {
1683
+ if (m.start > ELEMENT_SPAN_SCAN_CAP) break;
1684
+ const { isClose, name, selfClosing } = m;
1685
+ const tagEnd = m.end;
1686
+ from = tagEnd;
808
1687
  if (isClose) {
809
1688
  for (let i = stack.length - 1; i >= 0; i--) {
810
1689
  if (stack[i].name === name) {
@@ -815,14 +1694,17 @@ function buildElementSpans(code) {
815
1694
  }
816
1695
  continue;
817
1696
  }
818
- openTagRanges.push({ start: m.index, end: tagEnd });
1697
+ openTagRanges.push({ start: m.start, end: tagEnd });
819
1698
  if (selfClosing || VOID_ELEMENTS.has(name)) continue;
820
1699
  if (name === "style") {
821
- const closeMatch = /<\/style\s*>/gi.exec(code.slice(tagEnd));
822
- if (closeMatch !== null) TAG_RE.lastIndex = tagEnd + closeMatch.index + closeMatch[0].length;
1700
+ if (styleCloseMissing) continue;
1701
+ styleClose.lastIndex = tagEnd;
1702
+ const closeMatch = styleClose.exec(code);
1703
+ if (closeMatch === null) styleCloseMissing = true;
1704
+ else from = closeMatch.index + closeMatch[0].length;
823
1705
  continue;
824
1706
  }
825
- stack.push({ name, start: m.index });
1707
+ stack.push({ name, start: m.start });
826
1708
  }
827
1709
  return { spans, openTagRanges };
828
1710
  }
@@ -1015,12 +1897,47 @@ var TYPEALIAS_RE = new RegExp(
1015
1897
  var TOP_FUN_RE = new RegExp(
1016
1898
  "^(?:(?:public|internal|private|suspend|inline|infix|operator|external|actual|expect|tailrec)\\s+)*fun\\s+(?:" + GENERIC_CLAUSE + "\\s*)?" + RECEIVER_RE + "(" + NAME_RE + ")\\s*[(<]"
1017
1899
  );
1900
+ function inlineKotlinMembers(line, code, segs, parent, filePath, lineNum, level = 0) {
1901
+ const members = [];
1902
+ const opens = [];
1903
+ for (const seg of segs) {
1904
+ const text = line.slice(seg.start, seg.end).trim();
1905
+ const noAnn = stripLeadingAnnotations(text);
1906
+ const fm = (parent === void 0 ? TOP_FUN_RE : FUN_RE).exec(noAnn);
1907
+ const constM = fm === null ? CONST_RE2.exec(noAnn) : null;
1908
+ const companionM = fm === null && constM === null && parent !== void 0 ? COMPANION_RE.exec(noAnn) : null;
1909
+ const classM = fm === null && constM === null && companionM === null ? CLASS_HEADER_RE2.exec(noAnn) : null;
1910
+ let sym = null;
1911
+ if (fm) sym = makeLineSymbol(filePath, unquoteName(fm[1] ?? ""), parent === void 0 ? "function" : "method", lineNum, text, parent);
1912
+ else if (constM) sym = makeLineSymbol(filePath, constM[1] ?? "", "const", lineNum, text, parent);
1913
+ else if (companionM !== null || classM !== null) {
1914
+ const brace = bodyBraceAt(code, seg.start, seg.end);
1915
+ if (seg.open && brace === -1) continue;
1916
+ const name = unquoteName((companionM !== null ? companionM[1] : classM?.[2]) ?? "Companion");
1917
+ const keyword = companionM !== null ? "object" : classM?.[1] ?? "class";
1918
+ const typeSym = makeLineSymbol(filePath, name, keyword === "interface" ? "interface" : keyword === "object" ? "object" : "class", lineNum, text, parent);
1919
+ members.push(typeSym);
1920
+ if (brace !== -1) {
1921
+ const inner = inlineKotlinMembers(line, code, bodySegments(code, brace + 1), name, filePath, lineNum, level + 1);
1922
+ members.push(...inner.members);
1923
+ if (seg.open) opens.push({ sym: typeSym, level, isType: true }, ...inner.opens);
1924
+ }
1925
+ continue;
1926
+ }
1927
+ if (sym === null) continue;
1928
+ members.push(sym);
1929
+ if (seg.open) opens.push({ sym, level, isType: false });
1930
+ }
1931
+ return { members, opens };
1932
+ }
1018
1933
  function extractKotlin(content, filePath) {
1019
1934
  const symbols = [];
1020
1935
  const imports = [];
1021
1936
  const lines = content.split(/\r?\n/);
1022
1937
  const classStack = [];
1023
1938
  let braceDepth = 0;
1939
+ const settled = /* @__PURE__ */ new Set();
1940
+ let openMembers = [];
1024
1941
  let inComment = false;
1025
1942
  let mlState = null;
1026
1943
  for (let i = 0; i < lines.length; i++) {
@@ -1111,6 +2028,23 @@ function extractKotlin(content, filePath) {
1111
2028
  }
1112
2029
  }
1113
2030
  const braceLine = stripStringLiterals(line);
2031
+ const lineOpens = [];
2032
+ const queueMembers = (segs, parent, bodyDepth) => {
2033
+ const { members, opens } = inlineKotlinMembers(line, braceLine, segs, parent, filePath, lineNum);
2034
+ symbols.push(...members);
2035
+ for (const m of members) settled.add(m);
2036
+ lineOpens.push(...openMembersOf(opens, bodyDepth));
2037
+ for (const o of opens) if (o.isType) classStack.push({ name: o.sym.name, braceDepth: bodyDepth + o.level, bodyEntered: true, parenBalance: 0, pendingPop: false });
2038
+ };
2039
+ const lineSegs = bodySegments(braceLine, 0);
2040
+ if (frame !== null && frame !== outerFrame && lineSegs[0] !== void 0) {
2041
+ const brace = bodyBraceAt(braceLine, lineSegs[0].start, lineSegs[0].end);
2042
+ if (brace !== -1) queueMembers(bodySegments(braceLine, brace + 1), frame.name, braceDepth + 1);
2043
+ }
2044
+ if (outerFrame !== null && outerDepthInClass >= 1) {
2045
+ const resume = bodyResumeAt(braceLine, outerDepthInClass - 1);
2046
+ if (resume >= 0) queueMembers(outerDepthInClass === 1 ? lineSegs.slice(1) : bodySegments(braceLine, resume), outerFrame.name, outerFrame.braceDepth + 1);
2047
+ } else if (outerFrame === null && !isIndented) queueMembers(lineSegs.slice(1), void 0, braceDepth);
1114
2048
  for (const ch of braceLine) {
1115
2049
  if (ch === "{") {
1116
2050
  braceDepth++;
@@ -1125,6 +2059,8 @@ function extractKotlin(content, filePath) {
1125
2059
  frame.parenBalance--;
1126
2060
  }
1127
2061
  }
2062
+ openMembers = endOpenMembers(symbols, settled, openMembers, braceDepth, lineNum, lines);
2063
+ openMembers.push(...lineOpens);
1128
2064
  if (frame !== null && !frame.bodyEntered && frame.parenBalance <= 0) {
1129
2065
  frame.pendingPop = !(stripped.endsWith(":") || stripped.endsWith(","));
1130
2066
  }
@@ -1137,7 +2073,7 @@ function extractKotlin(content, filePath) {
1137
2073
  }
1138
2074
  }
1139
2075
  }
1140
- return { symbols, imports };
2076
+ return { symbols, imports, settled };
1141
2077
  }
1142
2078
 
1143
2079
  // src/languages/scala.ts
@@ -1174,11 +2110,151 @@ var OBJECT_RE = new RegExp("^\\s*(?:package\\s+)?" + MODS + "object\\s+(" + NAME
1174
2110
  var TRAIT_RE = new RegExp("^\\s*" + MODS + "trait\\s+(" + NAME + ")(?:\\s|\\[|:|$)");
1175
2111
  var ENUM_RE = new RegExp("^\\s*(?:private|protected)?\\s*enum\\s+(" + NAME + ")(?:\\s|\\[|\\(|:|$)");
1176
2112
  var DEF_NAME = "(?:`[^`\\r\\n]+`|[A-Za-z_][A-Za-z0-9_]*_[+\\-*/%=!<>&|^~:]+|[+\\-*/%=!<>&|^~:]+|[A-Za-z_][A-Za-z0-9_]*)";
1177
- var FUNC_RE = new RegExp("^\\s*" + MODS + "def\\s+(" + DEF_NAME + ")(?:\\s*\\[|\\s*\\(|\\s*:)");
2113
+ var FUNC_RE = new RegExp("^\\s*" + MODS + "def\\s+(" + DEF_NAME + ")(?:\\s*\\[|\\s*\\(|\\s*:|\\s*=(?!=))");
1178
2114
  var VAL_RE = new RegExp("^\\s*" + MODS + "val\\s+(" + NAME + ")");
1179
2115
  var VAR_RE = new RegExp("^\\s*" + MODS + "var\\s+(" + NAME + ")");
2116
+ var GIVEN_RE = /^\s*(?:(?:(?:private|protected)(?:\[[A-Za-z_][A-Za-z0-9_]*\])?|inline|transparent|override|final|implicit|lazy)\s+)*given\s+(?!=(?!>))(\S.*)$/;
2117
+ var SIMPLE_TYPE_HEAD_RE = /^(?:[A-Za-z_][A-Za-z0-9_]*\.)*([A-Za-z_][A-Za-z0-9_]*)\s*/;
2118
+ function splitTopLevel(text) {
2119
+ const parts = [];
2120
+ let depth = 0;
2121
+ let start = 0;
2122
+ for (let i = 0; i < text.length; i++) {
2123
+ const ch = text[i];
2124
+ if (ch === "(" || ch === "[") depth++;
2125
+ else if (ch === ")" || ch === "]") depth--;
2126
+ else if (ch === "," && depth === 0) {
2127
+ parts.push(text.slice(start, i).trim());
2128
+ start = i + 1;
2129
+ }
2130
+ }
2131
+ parts.push(text.slice(start).trim());
2132
+ return parts;
2133
+ }
2134
+ function anonymousGivenName(typeText) {
2135
+ let text = typeText.trim();
2136
+ while (text.startsWith("[") || text.startsWith("(")) {
2137
+ let depth = 0;
2138
+ let i = 0;
2139
+ for (; i < text.length; i++) {
2140
+ const ch = text[i];
2141
+ if (ch === "(" || ch === "[") depth++;
2142
+ else if (ch === ")" || ch === "]") depth--;
2143
+ if (depth === 0) break;
2144
+ }
2145
+ const after = text.slice(i + 1).trimStart();
2146
+ if (!after.startsWith("=>")) return "given";
2147
+ text = after.slice(2).trim();
2148
+ }
2149
+ const head = SIMPLE_TYPE_HEAD_RE.exec(text);
2150
+ if (!head) return "given";
2151
+ const parts = [head[1]];
2152
+ const tail = text.slice(head[0].length);
2153
+ if (tail !== "") {
2154
+ if (!tail.startsWith("[") || !tail.endsWith("]")) return "given";
2155
+ for (const arg of splitTopLevel(tail.slice(1, -1))) {
2156
+ const members = arg.startsWith("(") && arg.endsWith(")") ? splitTopLevel(arg.slice(1, -1)) : [arg];
2157
+ for (const member of members) {
2158
+ if (member.replace(/\[.*\]/g, "").includes("=>")) {
2159
+ parts.push("Function");
2160
+ continue;
2161
+ }
2162
+ const m = SIMPLE_TYPE_HEAD_RE.exec(member);
2163
+ if (!m || !/^(?:\[.*\])?$/.test(member.slice(m[0].length))) return "given";
2164
+ parts.push(m[1]);
2165
+ }
2166
+ }
2167
+ }
2168
+ return `given_${parts.join("_")}`;
2169
+ }
2170
+ function givenHead(stripped) {
2171
+ const m = GIVEN_RE.exec(stripped);
2172
+ if (!m) return null;
2173
+ const rest = m[1];
2174
+ const blanked = stripStringLiterals(rest, SCALA_STRIP);
2175
+ let depth = 0;
2176
+ let sigColon = -1;
2177
+ let end = blanked.length;
2178
+ let body = null;
2179
+ for (let i = 0; i < blanked.length; i++) {
2180
+ const ch = blanked[i];
2181
+ if (ch === "(" || ch === "[") depth++;
2182
+ else if (ch === ")" || ch === "]") depth--;
2183
+ else if (depth !== 0) continue;
2184
+ else if (ch === "{") {
2185
+ end = i;
2186
+ body = "brace";
2187
+ break;
2188
+ } else if (ch === "=" && blanked[i + 1] !== ">") {
2189
+ end = i;
2190
+ break;
2191
+ } else if (ch === ":") {
2192
+ if (blanked.slice(i + 1).trim() === "") {
2193
+ end = i;
2194
+ body = "colon";
2195
+ break;
2196
+ }
2197
+ if (sigColon < 0) sigColon = i;
2198
+ } else if (blanked.startsWith("with", i) && !/[A-Za-z0-9_]/.test(blanked[i - 1] ?? "") && !/[A-Za-z0-9_]/.test(blanked[i + 4] ?? "")) {
2199
+ end = i;
2200
+ body = blanked.slice(i + 4).trim().startsWith("{") ? "brace" : "colon";
2201
+ break;
2202
+ }
2203
+ }
2204
+ const sig = sigColon >= 0 ? rest.slice(0, sigColon).trim() : "";
2205
+ const named = new RegExp("^(" + NAME + ")\\s*(?:[[(]|$)").exec(sig);
2206
+ if (named) return { name: unquoteName2(named[1]), anonymous: false, body };
2207
+ return { name: anonymousGivenName(sigColon >= 0 ? rest.slice(sigColon + 1, end) : rest.slice(0, end)), anonymous: true, body };
2208
+ }
1180
2209
  function startsDeclaration(stripped) {
1181
- return CLASS_RE3.test(stripped) || OBJECT_RE.test(stripped) || TRAIT_RE.test(stripped) || ENUM_RE.test(stripped) || FUNC_RE.test(stripped) || VAL_RE.test(stripped) || VAR_RE.test(stripped);
2210
+ return CLASS_RE3.test(stripped) || OBJECT_RE.test(stripped) || TRAIT_RE.test(stripped) || ENUM_RE.test(stripped) || FUNC_RE.test(stripped) || VAL_RE.test(stripped) || VAR_RE.test(stripped) || GIVEN_RE.test(stripped) || extensionClauseTail(stripped) !== null;
2211
+ }
2212
+ function extensionClauseTail(stripped) {
2213
+ if (!/^extension\s*[[(]/.test(stripped)) return null;
2214
+ const blanked = stripStringLiterals(stripped, SCALA_STRIP);
2215
+ let i = "extension".length;
2216
+ let depth = 0;
2217
+ for (; i < blanked.length; i++) {
2218
+ const ch = blanked[i];
2219
+ if (ch === "(" || ch === "[") depth++;
2220
+ else if (ch === ")" || ch === "]") depth--;
2221
+ else if (depth === 0 && ch !== " " && ch !== " ") break;
2222
+ }
2223
+ return depth === 0 ? stripped.slice(i).trim() : null;
2224
+ }
2225
+ var INLINE_TYPES = [[CLASS_RE3, "class"], [OBJECT_RE, "object"], [TRAIT_RE, "trait"], [ENUM_RE, "enum"]];
2226
+ function inlineScalaMembers(line, code, segs, parent, filePath, lineNum, level = 0) {
2227
+ const members = [];
2228
+ const opens = [];
2229
+ for (const seg of segs) {
2230
+ const text = line.slice(seg.start, seg.end).trim();
2231
+ const fm = FUNC_RE.exec(text);
2232
+ const vm = fm === null ? VAL_RE.exec(text) : null;
2233
+ const varm = fm === null && vm === null ? VAR_RE.exec(text) : null;
2234
+ const member = fm !== null ? [fm, "function"] : vm !== null ? [vm, "val"] : varm !== null ? [varm, "var"] : null;
2235
+ if (member !== null) {
2236
+ const sym = makeLineSymbol(filePath, unquoteName2(member[0][1] ?? ""), member[1], lineNum, text, parent);
2237
+ members.push(sym);
2238
+ if (seg.open) opens.push({ sym, level, isType: false });
2239
+ continue;
2240
+ }
2241
+ for (const [re, kind] of INLINE_TYPES) {
2242
+ const tm = re.exec(text);
2243
+ if (tm === null) continue;
2244
+ const brace = bodyBraceAt(code, seg.start, seg.end);
2245
+ if (seg.open && brace === -1) break;
2246
+ const name = unquoteName2(tm[1] ?? "");
2247
+ const typeSym = makeLineSymbol(filePath, name, kind, lineNum, text, parent);
2248
+ members.push(typeSym);
2249
+ if (brace !== -1) {
2250
+ const inner = inlineScalaMembers(line, code, bodySegments(code, brace + 1), name, filePath, lineNum, level + 1);
2251
+ members.push(...inner.members);
2252
+ if (seg.open) opens.push({ sym: typeSym, level, isType: true }, ...inner.opens);
2253
+ }
2254
+ break;
2255
+ }
2256
+ }
2257
+ return { members, opens };
1182
2258
  }
1183
2259
  function extractScala(content, filePath) {
1184
2260
  const symbols = [];
@@ -1186,9 +2262,12 @@ function extractScala(content, filePath) {
1186
2262
  const lines = content.split(/\r?\n/);
1187
2263
  const typeStack = [];
1188
2264
  let braceDepth = 0;
2265
+ const settled = /* @__PURE__ */ new Set();
2266
+ let openMembers = [];
1189
2267
  let inComment = false;
1190
2268
  let mlState = null;
1191
2269
  let lastCodeLine = 0;
2270
+ let extBlock = null;
1192
2271
  const closeColonFrame = (frame, endLine) => {
1193
2272
  const open = symbols[frame.symbolIndex];
1194
2273
  if (open !== void 0) symbols[frame.symbolIndex] = withSpanEnd(open, endLine, lines);
@@ -1202,7 +2281,7 @@ function extractScala(content, filePath) {
1202
2281
  mlLine = masked.code;
1203
2282
  mlState = masked.state;
1204
2283
  }
1205
- const { code: blockStripped, inComment: nextInComment } = stripBlockCommentSpan(mlLine, inComment);
2284
+ const { code: blockStripped, inComment: nextInComment } = stripBlockCommentSpan(mlLine, inComment, SCALA_STRIP);
1206
2285
  inComment = nextInComment;
1207
2286
  const line = stripLineComment(blockStripped, ["//"], SCALA_STRIP).trimEnd();
1208
2287
  const stripped = line.trim();
@@ -1217,7 +2296,7 @@ function extractScala(content, filePath) {
1217
2296
  const top = typeStack[typeStack.length - 1];
1218
2297
  if (!top.colonBody || indent > top.declIndent) break;
1219
2298
  typeStack.pop();
1220
- const closesWithMarker = indent === top.declIndent && stripped === `end ${top.name}`;
2299
+ const closesWithMarker = indent === top.declIndent && stripped === (top.endMarker ?? `end ${top.name}`);
1221
2300
  closeColonFrame(top, closesWithMarker ? lineNum : lastCodeLine);
1222
2301
  if (closesWithMarker) lastCodeLine = lineNum;
1223
2302
  }
@@ -1287,7 +2366,34 @@ function extractScala(content, filePath) {
1287
2366
  typeStack.push({ name: enname, startDepth: braceDepth, bodyEntered: false, openParens: 0, declIndent: indent, colonBody: opensColonBody, bodyIndent: null, symbolIndex: symbols.length - 1 });
1288
2367
  matched = true;
1289
2368
  }
2369
+ const gm = !matched && typeDetectionGateOk && (!isIndented || typeStack.length > 0) ? givenHead(stripped) : null;
2370
+ if (gm) {
2371
+ const parent = typeStack.length > 0 ? typeStack[typeStack.length - 1].name : void 0;
2372
+ symbols.push(makeLineSymbol(filePath, gm.name, gm.body === null ? "val" : "object", lineNum, stripped.slice(0, 200), parent, lines, "c"));
2373
+ if (gm.body !== null) {
2374
+ typeStack.push({ name: gm.name, startDepth: braceDepth, bodyEntered: false, openParens: 0, declIndent: indent, colonBody: gm.body === "colon", bodyIndent: null, symbolIndex: symbols.length - 1, ...gm.anonymous ? { endMarker: "end given" } : {} });
2375
+ }
2376
+ matched = true;
2377
+ }
1290
2378
  const frame = typeStack.length > 0 ? typeStack[typeStack.length - 1] : null;
2379
+ if (extBlock !== null && braceDepth <= extBlock.depth && indent <= extBlock.indent) extBlock = null;
2380
+ if (!matched && extBlock !== null) {
2381
+ if (extBlock.bodyIndent === null) {
2382
+ extBlock.bodyIndent = indent;
2383
+ extBlock.bodyDepth = braceDepth;
2384
+ }
2385
+ const fm = indent === extBlock.bodyIndent && braceDepth === extBlock.bodyDepth ? FUNC_RE.exec(stripped) : null;
2386
+ if (fm) symbols.push(makeLineSymbol(filePath, unquoteName2(fm[1] ?? ""), "function", lineNum, stripped.slice(0, 200), extBlock.parent, lines, "c"));
2387
+ matched = true;
2388
+ }
2389
+ const memberSlot = frame === null ? !isIndented : braceDepth - frame.startDepth === 1 || inColonBody && frame === colonTop;
2390
+ const extTail = !matched && memberSlot ? extensionClauseTail(stripped) : null;
2391
+ if (extTail !== null) {
2392
+ const fm = FUNC_RE.exec(extTail);
2393
+ if (fm) symbols.push(makeLineSymbol(filePath, unquoteName2(fm[1] ?? ""), "function", lineNum, stripped.slice(0, 200), frame?.name, lines, "c"));
2394
+ else extBlock = { indent, depth: braceDepth, parent: frame?.name, bodyIndent: null, bodyDepth: braceDepth };
2395
+ matched = true;
2396
+ }
1291
2397
  if (!matched && frame !== null) {
1292
2398
  const depthInType = braceDepth - frame.startDepth;
1293
2399
  if (depthInType === 1 || inColonBody && frame === colonTop) {
@@ -1331,6 +2437,29 @@ function extractScala(content, filePath) {
1331
2437
  symbols[symbols.length - 1] = withSpanEnd(lastSymbol, indentedBodyEnd(lines, lineNum, indent), lines);
1332
2438
  }
1333
2439
  const braceLine = stripStringLiterals(line, SCALA_STRIP);
2440
+ const lineOpens = [];
2441
+ const queueMembers = (segs, parent, bodyDepth) => {
2442
+ const { members, opens } = inlineScalaMembers(line, braceLine, segs, parent, filePath, lineNum);
2443
+ symbols.push(...members);
2444
+ for (const m of members) settled.add(m);
2445
+ lineOpens.push(...openMembersOf(opens, bodyDepth));
2446
+ for (const o of opens) {
2447
+ if (!o.isType) continue;
2448
+ const enclosing = typeStack[typeStack.length - 1];
2449
+ if (enclosing !== void 0) enclosing.bodyEntered = true;
2450
+ typeStack.push({ name: o.sym.name, startDepth: bodyDepth + o.level, bodyEntered: true, openParens: 0, declIndent: indent, colonBody: false, bodyIndent: null, symbolIndex: symbols.indexOf(o.sym) });
2451
+ }
2452
+ };
2453
+ const lineSegs = bodySegments(braceLine, 0);
2454
+ if (frame !== null && frame !== outerFrame && lineSegs[0] !== void 0) {
2455
+ const brace = bodyBraceAt(braceLine, lineSegs[0].start, lineSegs[0].end);
2456
+ if (brace !== -1) queueMembers(bodySegments(braceLine, brace + 1), frame.name, braceDepth + 1);
2457
+ }
2458
+ if (outerFrame !== null && (outerDepthInType === 1 || inColonBody && outerFrame === colonTop)) queueMembers(lineSegs.slice(1), outerFrame.name, braceDepth);
2459
+ else if (outerFrame !== null && !outerFrame.colonBody && outerDepthInType > 1) {
2460
+ const resume = bodyResumeAt(braceLine, outerDepthInType - 1);
2461
+ if (resume >= 0) queueMembers(bodySegments(braceLine, resume), outerFrame.name, outerFrame.startDepth + 1);
2462
+ } else if (outerFrame === null && !isIndented) queueMembers(lineSegs.slice(1), void 0, braceDepth);
1334
2463
  if (frame !== null && !frame.bodyEntered) {
1335
2464
  const parenDelta2 = (braceLine.match(/\(/g) ?? []).length - (braceLine.match(/\)/g) ?? []).length;
1336
2465
  frame.openParens = Math.max(0, frame.openParens + parenDelta2);
@@ -1345,6 +2474,8 @@ function extractScala(content, filePath) {
1345
2474
  braceDepth--;
1346
2475
  }
1347
2476
  }
2477
+ openMembers = endOpenMembers(symbols, settled, openMembers, braceDepth, lineNum, lines);
2478
+ openMembers.push(...lineOpens);
1348
2479
  while (typeStack.length > 0) {
1349
2480
  const top = typeStack[typeStack.length - 1];
1350
2481
  if (!top.colonBody && top.bodyEntered && braceDepth <= top.startDepth) {
@@ -1358,7 +2489,7 @@ function extractScala(content, filePath) {
1358
2489
  const top = typeStack.pop();
1359
2490
  if (top.colonBody) closeColonFrame(top, lastCodeLine);
1360
2491
  }
1361
- return { symbols, imports };
2492
+ return { symbols, imports, settled };
1362
2493
  }
1363
2494
 
1364
2495
  // src/languages/lua.ts
@@ -4524,12 +5655,12 @@ function extractApex(content, filePath) {
4524
5655
  }
4525
5656
  const typeNamesLower = /* @__PURE__ */ new Set();
4526
5657
  for (const match of code.matchAll(TYPE_DECL_RE)) {
4527
- const typeKind = match[1] ?? "";
5658
+ const typeKind2 = match[1] ?? "";
4528
5659
  const name = match[2] ?? "";
4529
5660
  const startOffset = match.index ?? 0;
4530
5661
  const line = offsetToLine(lineIndex, startOffset);
4531
5662
  const bodyStartLine = annotationStartLine(codeLines, line);
4532
- const typeKindLower = typeKind.toLowerCase();
5663
+ const typeKindLower = typeKind2.toLowerCase();
4533
5664
  const kind = typeKindLower === "class" ? "apex_class" : `apex_${typeKindLower}`;
4534
5665
  typeNamesLower.add(name.toLowerCase());
4535
5666
  emit2(name, kind, spanForMatch(content, code, lineIndex, startOffset, bodyStartLine, match[0]));
@@ -4586,36 +5717,52 @@ var FLOW_TAG_KIND = {
4586
5717
  variables: "sf_flow_variable"
4587
5718
  };
4588
5719
  function xmlText(content, tag) {
4589
- const re = new RegExp(
4590
- `<(?:[A-Za-z_][\\w.-]*:)?${tag}(?:\\s[^>]*)?>([\\s\\S]*?)</(?:[A-Za-z_][\\w.-]*:)?${tag}\\s*>`,
4591
- "i"
4592
- );
4593
- const match = re.exec(content);
4594
- if (match?.[1] === void 0) return null;
4595
- return decodeXml(match[1].trim());
5720
+ const first = findElements(content, tagOpenRe(tag, "gi"), tagCloseRe(tag, "gi"), 1)[0];
5721
+ if (first === void 0) return null;
5722
+ return decodeXml(first.body.trim());
5723
+ }
5724
+ function tagOpenRe(tag, flags) {
5725
+ return new RegExp(`<(?:[A-Za-z_][\\w.-]*:)?${tag}(?=[\\s>])`, flags);
5726
+ }
5727
+ function tagCloseRe(tag, flags) {
5728
+ return new RegExp(`</(?:[A-Za-z_][\\w.-]*:)?${tag}\\s*>`, flags);
4596
5729
  }
4597
5730
  function directChildText(content, tag) {
4598
- const candidateRe = new RegExp(
4599
- `<(?:[A-Za-z_][\\w.-]*:)?${tag}(?:\\s[^>]*)?>([\\s\\S]*?)</(?:[A-Za-z_][\\w.-]*:)?${tag}\\s*>`,
4600
- "gi"
4601
- );
4602
- const tagRe = /<(\/?)([A-Za-z_:][\w.:-]*)\b[^>]*?(\/?)>/g;
4603
- for (const cand of content.matchAll(candidateRe)) {
4604
- const idx = cand.index ?? 0;
4605
- let depth = 0;
4606
- tagRe.lastIndex = 0;
4607
- let t;
4608
- while ((t = tagRe.exec(content)) !== null) {
4609
- if (t.index >= idx) break;
4610
- const closing = t[1] === "/";
4611
- const selfClosing = t[3] === "/";
4612
- if (selfClosing) continue;
4613
- depth += closing ? -1 : 1;
4614
- }
4615
- if (depth === 0) return decodeXml((cand[1] ?? "").trim());
5731
+ const nextCandidate = elementCursor(content, tagOpenRe(tag, "gi"), tagCloseRe(tag, "gi"));
5732
+ let depthBefore = null;
5733
+ let cand;
5734
+ while ((cand = nextCandidate()) !== null) {
5735
+ depthBefore ??= depthCursor(content);
5736
+ if (depthBefore(cand.start) === 0) return decodeXml(cand.body.trim());
4616
5737
  }
4617
5738
  return null;
4618
5739
  }
5740
+ function depthCursor(content) {
5741
+ const re = /<(\/?)([A-Za-z_:][\w.:-]*)\b/g;
5742
+ let depth = 0;
5743
+ let heldStart = -1;
5744
+ let heldDelta = 0;
5745
+ let done = false;
5746
+ return (pos) => {
5747
+ for (; ; ) {
5748
+ if (heldStart < 0) {
5749
+ const m = done ? null : re.exec(content);
5750
+ const gt = m === null ? -1 : content.indexOf(">", m.index + m[0].length);
5751
+ if (m === null || gt < 0) {
5752
+ done = true;
5753
+ return depth;
5754
+ }
5755
+ const nameEnd = m.index + m[0].length;
5756
+ heldStart = m.index;
5757
+ heldDelta = content[gt - 1] === "/" && gt - 1 >= nameEnd ? 0 : m[1] === "/" ? -1 : 1;
5758
+ re.lastIndex = gt + 1;
5759
+ }
5760
+ if (heldStart >= pos) return depth;
5761
+ depth += heldDelta;
5762
+ heldStart = -1;
5763
+ }
5764
+ };
5765
+ }
4619
5766
  function decodeXml(value) {
4620
5767
  return value.replace(/&apos;/g, "'").replace(/&quot;/g, '"').replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&amp;/g, "&");
4621
5768
  }
@@ -4635,8 +5782,7 @@ function wholeFileSpan(content) {
4635
5782
  return {
4636
5783
  startLine: 1,
4637
5784
  endLine: lines.length > 1 && lines[lines.length - 1] === "" ? lines.length - 1 : lines.length,
4638
- // File-level metadata symbols can be several megabytes (profiles are a common case).
4639
- // Keep only the source span in the index; `read` reconstructs empty bodies from disk.
5785
+ // File-level metadata symbols can be several megabytes (profiles are a common case). Keep only the source span in the index; `read` reconstructs empty bodies from disk.
4640
5786
  body: ""
4641
5787
  };
4642
5788
  }
@@ -4650,11 +5796,13 @@ function spanFromOffsets(content, lineIndex, startOffset, endOffset) {
4650
5796
  };
4651
5797
  }
4652
5798
  function rootElement(content) {
4653
- const match = /<(?!\?|!)(?:[A-Za-z_][\w.-]*:)?([A-Za-z_][\w.-]*)\b[^>]*>/.exec(content);
5799
+ const match = /<(?!\?|!)(?:[A-Za-z_][\w.-]*:)?([A-Za-z_][\w.-]*)\b/.exec(content);
4654
5800
  if (match === null) return null;
4655
5801
  const root = match[1];
4656
5802
  if (root === void 0) return null;
4657
- if (match[0].endsWith("/>")) return root;
5803
+ const gt = content.indexOf(">", match.index + match[0].length);
5804
+ if (gt < 0) return null;
5805
+ if (content[gt - 1] === "/") return root;
4658
5806
  const close = new RegExp(`</(?:[A-Za-z_][\\w.-]*:)?${escapeRegExp(root)}\\s*>`, "i");
4659
5807
  return close.test(content) ? root : null;
4660
5808
  }
@@ -4672,14 +5820,10 @@ function metadataArtifactName(filePath) {
4672
5820
  return match?.[1] ?? basenameWithout(filePath, "-meta.xml");
4673
5821
  }
4674
5822
  function elementBlocks(content, tag) {
4675
- const re = new RegExp(
4676
- `<(?:[A-Za-z_][\\w.-]*:)?${tag}(?:\\s[^>]*)?>([\\s\\S]*?)</(?:[A-Za-z_][\\w.-]*:)?${tag}\\s*>`,
4677
- "gi"
4678
- );
4679
- return [...content.matchAll(re)].map((match) => ({
4680
- inner: match[1] ?? "",
4681
- offset: match.index ?? 0,
4682
- text: match[0]
5823
+ return findElements(content, tagOpenRe(tag, "gi"), tagCloseRe(tag, "gi")).map((el) => ({
5824
+ inner: el.body,
5825
+ offset: el.start,
5826
+ text: content.slice(el.start, el.end)
4683
5827
  }));
4684
5828
  }
4685
5829
  function attributeValue(attributes, name) {
@@ -4687,11 +5831,33 @@ function attributeValue(attributes, name) {
4687
5831
  return match?.[2] === void 0 ? null : decodeXml(match[2]);
4688
5832
  }
4689
5833
  function propertyElements(content) {
4690
- const re = /<(?:[A-Za-z_][\w.-]*:)?property\b([^>]*?)(?:\/>|>([\s\S]*?)<\/(?:[A-Za-z_][\w.-]*:)?property\s*>)/gi;
5834
+ const open = /<(?:[A-Za-z_][\w.-]*:)?property\b/gi;
5835
+ const close = /<\/(?:[A-Za-z_][\w.-]*:)?property\s*>/gi;
5836
+ const nextGt = gtFinder(content);
4691
5837
  const out = [];
4692
- for (const match of content.matchAll(re)) {
4693
- const name = attributeValue(match[1] ?? "", "name");
4694
- if (name !== null && name !== "") out.push({ name, offset: match.index ?? 0, text: match[0] });
5838
+ let deadFrom = Infinity;
5839
+ let m;
5840
+ while ((m = open.exec(content)) !== null) {
5841
+ const nameEnd = m.index + m[0].length;
5842
+ const gt = nextGt(nameEnd);
5843
+ if (gt < 0) break;
5844
+ let end = gt + 1;
5845
+ let attrs = content.slice(nameEnd, gt);
5846
+ if (content[gt - 1] === "/" && gt - 1 >= nameEnd) {
5847
+ attrs = content.slice(nameEnd, gt - 1);
5848
+ } else {
5849
+ if (gt >= deadFrom) continue;
5850
+ close.lastIndex = gt + 1;
5851
+ const c = close.exec(content);
5852
+ if (c === null) {
5853
+ deadFrom = gt;
5854
+ continue;
5855
+ }
5856
+ end = c.index + c[0].length;
5857
+ }
5858
+ const name = attributeValue(attrs, "name");
5859
+ if (name !== null && name !== "") out.push({ name, offset: m.index, text: content.slice(m.index, end) });
5860
+ open.lastIndex = end;
4695
5861
  }
4696
5862
  return out;
4697
5863
  }
@@ -4723,15 +5889,35 @@ function metadataName(filePath, content, suffix) {
4723
5889
  function addFlowElements(symbols, seen, content, filePath, flowName) {
4724
5890
  const lineIndex = buildLineIndex(content);
4725
5891
  const tagAlternation = Object.keys(FLOW_TAG_KIND).join("|");
4726
- const re = new RegExp(`<(?:[A-Za-z_][\\w.-]*:)?(${tagAlternation})(?:\\s[^>]*)?>\\s*([\\s\\S]*?)\\s*</(?:[A-Za-z_][\\w.-]*:)?\\1\\s*>`, "g");
4727
- for (const match of content.matchAll(re)) {
5892
+ const open = new RegExp(`<(?:[A-Za-z_][\\w.-]*:)?(${tagAlternation})(?=[\\s>])`, "g");
5893
+ const closeByTag = /* @__PURE__ */ new Map();
5894
+ const deadFromByTag = /* @__PURE__ */ new Map();
5895
+ const nextGt = gtFinder(content);
5896
+ let m;
5897
+ while ((m = open.exec(content)) !== null) {
4728
5898
  if (symbols.length >= MAX_SYMBOLS11) return;
4729
- const tag = match[1] ?? "";
4730
- const inner = match[2] ?? "";
5899
+ const tag = m[1] ?? "";
5900
+ const nameEnd = m.index + m[0].length;
5901
+ const gt = nextGt(nameEnd);
5902
+ if (gt < 0) break;
5903
+ if (gt >= (deadFromByTag.get(tag) ?? Infinity)) continue;
5904
+ let close = closeByTag.get(tag);
5905
+ if (close === void 0) {
5906
+ close = tagCloseRe(tag, "g");
5907
+ closeByTag.set(tag, close);
5908
+ }
5909
+ close.lastIndex = gt + 1;
5910
+ const c = close.exec(content);
5911
+ if (c === null) {
5912
+ deadFromByTag.set(tag, gt);
5913
+ continue;
5914
+ }
5915
+ const startOffset = m.index;
5916
+ const endOffset = c.index + c[0].length;
5917
+ open.lastIndex = endOffset;
5918
+ const inner = content.slice(gt + 1, c.index).trim();
4731
5919
  const name = directChildText(inner, "name");
4732
5920
  if (name === null || name === "") continue;
4733
- const startOffset = match.index ?? 0;
4734
- const endOffset = startOffset + match[0].length;
4735
5921
  const span = spanFromOffsets(content, lineIndex, startOffset, endOffset);
4736
5922
  const kind = FLOW_TAG_KIND[tag] ?? "sf_flow_element";
4737
5923
  emit(symbols, seen, makeSpanSymbol(filePath, name, kind, span, flowName));
@@ -4942,7 +6128,9 @@ function blankJsStringLiterals(content) {
4942
6128
  }
4943
6129
  var FUNC_DECL_RE = /^(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s*\*?\s+([A-Za-z_$][\w$]*)/;
4944
6130
  var CONST_DECL_RE = /^(?:export\s+)?const\s+([A-Za-z_$][\w$]*)\s*[:=]/;
4945
- var CLASS_DECL_RE = /^(?:export\s+)?(?:default\s+)?(?:abstract\s+)?class\s+([A-Za-z_$][\w$]*)/;
6131
+ var CLASS_DECL_RE = /^(?:export\s+)?(?:default\s+)?(?:abstract\s+)?class\s+(?!extends\b)([A-Za-z_$][\w$]*)/;
6132
+ var ANONYMOUS_DEFAULT_RE = /^export\s+default\s+(?:async\s+)?(?:function\b|(class)\b|(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*=>)/;
6133
+ var DEFAULT_VALUE_RE = /^export\s+default\s+(?:\{|[A-Za-z_$][\w$.]*\s*\()/;
4946
6134
  function declarationEndIdx(blanked, startIdx) {
4947
6135
  let depth = 0;
4948
6136
  for (let j = startIdx; j < blanked.length; j++) {
@@ -4976,9 +6164,11 @@ function extractTopLevelDeclarations(scriptContent, filePath, startLine) {
4976
6164
  const fm = FUNC_DECL_RE.exec(trimmed);
4977
6165
  const cm = fm ? null : CONST_DECL_RE.exec(trimmed);
4978
6166
  const clm = fm || cm ? null : CLASS_DECL_RE.exec(trimmed);
4979
- const name = fm?.[1] ?? cm?.[1] ?? clm?.[1];
6167
+ const am = fm || cm || clm ? null : ANONYMOUS_DEFAULT_RE.exec(trimmed);
6168
+ const dm = fm || cm || clm || am ? null : DEFAULT_VALUE_RE.exec(trimmed);
6169
+ const name = fm?.[1] ?? cm?.[1] ?? clm?.[1] ?? (am || dm ? "default" : void 0);
4980
6170
  if (name) {
4981
- const kind = fm ? "sfc_script_function" : cm ? "sfc_script_const" : "sfc_script_class";
6171
+ const kind = fm || am && am[1] === void 0 ? "sfc_script_function" : cm || dm ? "sfc_script_const" : "sfc_script_class";
4982
6172
  const sym = makeLineSymbol(filePath, name, kind, line);
4983
6173
  const endIdx = declarationEndIdx(lines, i);
4984
6174
  symbols.push(endIdx > i ? { ...sym, lineEnd: startLine + endIdx, body: rawLines.slice(i, endIdx + 1).join("\n") } : sym);
@@ -5009,19 +6199,14 @@ function extractComponentRefs(markup, filePath, startLine, allowKebab) {
5009
6199
  }
5010
6200
  function extractTagBlocks(content, lineIndex, tag) {
5011
6201
  const masked = blankJsStringLiterals(content);
5012
- const re = new RegExp(`<${tag}\\b([^>]*)>([\\s\\S]*?)<\\/${tag}\\s*>`, "gi");
5013
6202
  const blocks = [];
5014
- for (const m of masked.matchAll(re)) {
5015
- const matchStart = m.index ?? 0;
5016
- const attrs = m[1] ?? "";
5017
- const innerLen = (m[2] ?? "").length;
5018
- const openTagLen = 1 + tag.length + attrs.length + 1;
5019
- const innerStart = matchStart + openTagLen;
6203
+ for (const el of findElements(masked, new RegExp(`<${tag}\\b`, "gi"), new RegExp(`<\\/${tag}\\s*>`, "gi"))) {
6204
+ const innerStart = el.bodyEnd - el.body.length;
5020
6205
  blocks.push({
5021
- content: content.slice(innerStart, innerStart + innerLen),
6206
+ content: content.slice(innerStart, el.bodyEnd),
5022
6207
  contentStartLine: offsetToLine(lineIndex, innerStart),
5023
- matchStart,
5024
- matchEnd: matchStart + m[0].length
6208
+ matchStart: el.start,
6209
+ matchEnd: el.end
5025
6210
  });
5026
6211
  }
5027
6212
  return blocks;
@@ -6840,12 +8025,17 @@ function sectionsToHeadingSymbols(sections, filePath) {
6840
8025
  parent: ""
6841
8026
  }));
6842
8027
  }
8028
+ var CSHARP_SPAN_OPTS = { lineComment: "//", stringEscapes: "csharp", rawStringQuotes: true, expressionBodies: true, interpolation: "csharp" };
6843
8029
  var ADAPTER_EXTRACTORS = {
6844
- csharp: (content, filePath) => assignBraceBlockSpans(extractCsharp(content, filePath).symbols, content, { lineComment: "//", stringEscapes: "csharp", rawStringQuotes: true, expressionBodies: true, interpolation: "csharp" }),
8030
+ csharp: (content, filePath) => {
8031
+ const { symbols, settled } = extractCsharp(content, filePath);
8032
+ return spanUnsettled(symbols, settled, (rest) => assignBraceBlockSpans(rest, content, CSHARP_SPAN_OPTS));
8033
+ },
6845
8034
  // Both halves walk the SAME masked text: the brace pass used to span raw file content, so it nested on braces in the inline HTML the extractor is no longer reading.
6846
8035
  php: (content, filePath) => {
6847
8036
  const code = maskPhpInlineHtml(content);
6848
- return assignBraceBlockSpans(extractPhp(code, filePath).symbols, code, { lineComment: ["//", "#"], lineCommentExceptions: ["#["], multilineLang: "php" });
8037
+ const { symbols, settled } = extractPhp(code, filePath);
8038
+ return spanUnsettled(symbols, settled, (rest) => assignBraceBlockSpans(rest, code, { lineComment: ["//", "#"], lineCommentExceptions: ["#["], multilineLang: "php" }));
6849
8039
  },
6850
8040
  html: (content, filePath) => {
6851
8041
  const r = extractHtml(content, filePath);
@@ -6855,9 +8045,7 @@ var ADAPTER_EXTRACTORS = {
6855
8045
  const r = extractLiquid(content, filePath);
6856
8046
  return [...r.symbols, ...sectionsToHeadingSymbols(r.sections, filePath)];
6857
8047
  },
6858
- // The six template dialects mask their own delimiters out and hand off to extractHtml, so they
6859
- // compose the same way html/liquid do above -- see templates_idx.ts's module doc for why this
6860
- // is the one place in Batch G/F where sharing IS correct.
8048
+ // The six template dialects mask their own delimiters out and hand off to extractHtml, so they compose the same way html/liquid do above -- see templates_idx.ts's module doc for why this is the one place in Batch G/F where sharing IS correct.
6861
8049
  jinja2: (content, filePath) => {
6862
8050
  const r = extractJinja2(content, filePath);
6863
8051
  return [...r.symbols, ...sectionsToHeadingSymbols(r.sections, filePath)];
@@ -6882,9 +8070,18 @@ var ADAPTER_EXTRACTORS = {
6882
8070
  const r = extractTwig(content, filePath);
6883
8071
  return [...r.symbols, ...sectionsToHeadingSymbols(r.sections, filePath)];
6884
8072
  },
6885
- kotlin: (content, filePath) => assignBraceBlockSpans(extractKotlin(content, filePath).symbols, content, { lineComment: "//", nestedBlockComments: true, tripleQuote: true, tripleQuoteRunClose: "last", expressionBodies: "kotlin", interpolation: "kotlin" }),
6886
- swift: (content, filePath) => assignBraceBlockSpans(extractSwift(content, filePath).symbols, content, { lineComment: "//", nestedBlockComments: true, tripleQuote: true, tripleQuoteRunClose: "last", multilineLang: "swift", interpolation: "swift" }),
6887
- scala: (content, filePath) => assignBraceBlockSpans(extractScala(content, filePath).symbols, content, { lineComment: "//", nestedBlockComments: true, tripleQuote: true, tripleQuoteRunClose: "last", interpolation: "scala" }),
8073
+ kotlin: (content, filePath) => {
8074
+ const { symbols, settled } = extractKotlin(content, filePath);
8075
+ return spanUnsettled(symbols, settled, (rest) => assignBraceBlockSpans(rest, content, { lineComment: "//", nestedBlockComments: true, tripleQuote: true, tripleQuoteRunClose: "last", expressionBodies: "kotlin", interpolation: "kotlin" }));
8076
+ },
8077
+ swift: (content, filePath) => {
8078
+ const { symbols, settled } = extractSwift(content, filePath);
8079
+ return spanUnsettled(symbols, settled, (rest) => assignBraceBlockSpans(rest, content, { lineComment: "//", nestedBlockComments: true, tripleQuote: true, tripleQuoteRunClose: "last", multilineLang: "swift", interpolation: "swift" }));
8080
+ },
8081
+ scala: (content, filePath) => {
8082
+ const { symbols, settled } = extractScala(content, filePath);
8083
+ return spanUnsettled(symbols, settled, (rest) => assignBraceBlockSpans(rest, content, { lineComment: "//", nestedBlockComments: true, tripleQuote: true, tripleQuoteRunClose: "last", expressionBodies: "kotlin", interpolation: "scala", symbolLiterals: true }));
8084
+ },
6888
8085
  lua: (content, filePath) => extractLua(content, filePath).symbols,
6889
8086
  vb: (content, filePath) => extractVb(content, filePath).symbols,
6890
8087
  elixir: (content, filePath) => extractElixir(content, filePath).symbols,
@@ -6940,6 +8137,7 @@ var ADAPTER_EXTRACTORS = {
6940
8137
  };
6941
8138
  export {
6942
8139
  ADAPTER_EXTRACTORS,
8140
+ CSHARP_SPAN_OPTS,
6943
8141
  assignBraceBlockSpans,
6944
8142
  extractAstro,
6945
8143
  extractCobol,
@@ -6947,5 +8145,6 @@ export {
6947
8145
  extractNatural,
6948
8146
  extractSalesforceMetadata,
6949
8147
  extractSvelte,
6950
- extractVue
8148
+ extractVue,
8149
+ spanUnsettled
6951
8150
  };