token-goat 2.9.29 → 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 (197) hide show
  1. package/README.md +53 -42
  2. package/SECURITY.md +37 -11
  3. package/THIRD_PARTY_NOTICES.md +41 -4
  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/ort-wasm-simd-threaded.mjs +59 -0
  9. package/dist/{token-goat-chunk-SE6E4BKJ.mjs → token-goat-chunk-25TRAWET.mjs} +23 -6
  10. package/dist/token-goat-chunk-2KXO6V2B.mjs +203 -0
  11. package/dist/{token-goat-chunk-UXSXQQIY.mjs → token-goat-chunk-2M7E4PF7.mjs} +43 -14
  12. package/dist/token-goat-chunk-2UPZGKKY.mjs +188 -0
  13. package/dist/token-goat-chunk-2WLPWKHV.mjs +135 -0
  14. package/dist/token-goat-chunk-2XBMMDBD.mjs +126 -0
  15. package/dist/token-goat-chunk-32ZOY4N5.mjs +23 -0
  16. package/dist/token-goat-chunk-3EZRNKTK.mjs +188 -0
  17. package/dist/token-goat-chunk-4ADZHI7J.mjs +63 -0
  18. package/dist/token-goat-chunk-4GBVPH3D.mjs +242 -0
  19. package/dist/{token-goat-chunk-2WOUYWLM.mjs → token-goat-chunk-4GILLLWY.mjs} +34 -7
  20. package/dist/token-goat-chunk-4NAPX7BA.mjs +90 -0
  21. package/dist/{token-goat-chunk-NMBWLRHW.mjs → token-goat-chunk-4SC7UJYV.mjs} +9981 -11563
  22. package/dist/token-goat-chunk-4SMRO4TO.mjs +366 -0
  23. package/dist/{token-goat-chunk-O6I2XU4P.mjs → token-goat-chunk-4ZBFWLXF.mjs} +310 -441
  24. package/dist/token-goat-chunk-57BIAXJL.mjs +286 -0
  25. package/dist/token-goat-chunk-5AC66HNP.mjs +115 -0
  26. package/dist/token-goat-chunk-5IMLKSOP.mjs +145 -0
  27. package/dist/token-goat-chunk-5RG5SBL6.mjs +221 -0
  28. package/dist/{token-goat-chunk-RRNZMM3A.mjs → token-goat-chunk-5Y6ZYL6U.mjs} +21 -2
  29. package/dist/token-goat-chunk-646E6U44.mjs +398 -0
  30. package/dist/token-goat-chunk-65N4RHP4.mjs +33 -0
  31. package/dist/{token-goat-chunk-6AK46ZT7.mjs → token-goat-chunk-6DG6HWP3.mjs} +13 -3
  32. package/dist/token-goat-chunk-6ENQSNRZ.mjs +573 -0
  33. package/dist/token-goat-chunk-6ZY4GNF2.mjs +91 -0
  34. package/dist/{token-goat-chunk-E5TK5DNO.mjs → token-goat-chunk-76FGDLRO.mjs} +574 -340
  35. package/dist/{token-goat-chunk-TGOXNAHW.mjs → token-goat-chunk-7EZTZOMC.mjs} +780 -767
  36. package/dist/token-goat-chunk-7MAOA6X4.mjs +3647 -0
  37. package/dist/token-goat-chunk-7R2ZVVAX.mjs +218 -0
  38. package/dist/{token-goat-chunk-TCQANXYC.mjs → token-goat-chunk-AM5V6GSX.mjs} +18 -2
  39. package/dist/token-goat-chunk-AUNGYYQX.mjs +184 -0
  40. package/dist/token-goat-chunk-AUQYRMMH.mjs +2985 -0
  41. package/dist/token-goat-chunk-B3PEKBYG.mjs +128 -0
  42. package/dist/{token-goat-chunk-KOPIR3KZ.mjs → token-goat-chunk-BA4HI6BW.mjs} +1910 -165
  43. package/dist/{token-goat-chunk-52NSDWYY.mjs → token-goat-chunk-BFCWY73P.mjs} +58 -20
  44. package/dist/token-goat-chunk-BPGCUMR7.mjs +30 -0
  45. package/dist/token-goat-chunk-BWGFUZZE.mjs +25 -0
  46. package/dist/token-goat-chunk-C75NA7PL.mjs +322 -0
  47. package/dist/token-goat-chunk-CBIQ7WTD.mjs +87 -0
  48. package/dist/token-goat-chunk-CETM74KC.mjs +307 -0
  49. package/dist/token-goat-chunk-CIMQ2BB3.mjs +233 -0
  50. package/dist/{token-goat-chunk-DNSPXQXQ.mjs → token-goat-chunk-CJLS3CDL.mjs} +70 -18
  51. package/dist/{token-goat-chunk-MELOKFDJ.mjs → token-goat-chunk-CO3UYX6G.mjs} +7 -1
  52. package/dist/token-goat-chunk-COPNXRJM.mjs +154 -0
  53. package/dist/token-goat-chunk-CSJ5L3NL.mjs +479 -0
  54. package/dist/token-goat-chunk-CVCEVUGK.mjs +315 -0
  55. package/dist/token-goat-chunk-CXHOFN7R.mjs +371 -0
  56. package/dist/token-goat-chunk-D735C4QM.mjs +603 -0
  57. package/dist/{token-goat-chunk-E4ZOJIZK.mjs → token-goat-chunk-DGS2LVNA.mjs} +70 -160
  58. package/dist/{token-goat-chunk-L7H3U27L.mjs → token-goat-chunk-DOWRSMWO.mjs} +1 -1
  59. package/dist/token-goat-chunk-E45INMY3.mjs +71 -0
  60. package/dist/token-goat-chunk-EC5F37F4.mjs +244 -0
  61. package/dist/{token-goat-chunk-XTQAOTSO.mjs → token-goat-chunk-EDBDRVH5.mjs} +4 -1
  62. package/dist/token-goat-chunk-EELTBKDM.mjs +613 -0
  63. package/dist/token-goat-chunk-EVMZJ27Z.mjs +147 -0
  64. package/dist/token-goat-chunk-EXKGNHEG.mjs +2096 -0
  65. package/dist/{token-goat-chunk-YOOVFPTP.mjs → token-goat-chunk-F4HYL64R.mjs} +12 -2
  66. package/dist/token-goat-chunk-F6PAUIEK.mjs +624 -0
  67. package/dist/token-goat-chunk-FDSREWLX.mjs +692 -0
  68. package/dist/{token-goat-chunk-NMTKNYGF.mjs → token-goat-chunk-FNFBKLRD.mjs} +74 -9
  69. package/dist/token-goat-chunk-G5PJ7AGM.mjs +36 -0
  70. package/dist/token-goat-chunk-GGGG7RWB.mjs +236 -0
  71. package/dist/{token-goat-chunk-TDUT2CL6.mjs → token-goat-chunk-GL3ETKSC.mjs} +276 -19
  72. package/dist/{token-goat-chunk-7CPMDFGB.mjs → token-goat-chunk-GVB2MUST.mjs} +265 -1567
  73. package/dist/token-goat-chunk-GWFLAUMQ.mjs +307 -0
  74. package/dist/token-goat-chunk-HAVAOB3S.mjs +87 -0
  75. package/dist/token-goat-chunk-HLPW63A7.mjs +48 -0
  76. package/dist/token-goat-chunk-HU4TORC5.mjs +1377 -0
  77. package/dist/token-goat-chunk-I7VKZZAW.mjs +35 -0
  78. package/dist/token-goat-chunk-IA6XSPE3.mjs +218 -0
  79. package/dist/token-goat-chunk-IAGXMHIK.mjs +863 -0
  80. package/dist/{token-goat-chunk-435UQTKD.mjs → token-goat-chunk-IK2DRMFX.mjs} +129 -74
  81. package/dist/{token-goat-chunk-ZER6EAXZ.mjs → token-goat-chunk-INNPTRUX.mjs} +2954 -2783
  82. package/dist/token-goat-chunk-JJ5BX4F4.mjs +129 -0
  83. package/dist/token-goat-chunk-JVFSHVFJ.mjs +129 -0
  84. package/dist/token-goat-chunk-KGEFFSHD.mjs +50 -0
  85. package/dist/token-goat-chunk-KKUFXAPD.mjs +25 -0
  86. package/dist/token-goat-chunk-KQBLRPBN.mjs +433 -0
  87. package/dist/token-goat-chunk-LCNQ2CNN.mjs +497 -0
  88. package/dist/token-goat-chunk-M3LFJDPU.mjs +58 -0
  89. package/dist/token-goat-chunk-M52KPT3C.mjs +87 -0
  90. package/dist/token-goat-chunk-MBEG42H7.mjs +150 -0
  91. package/dist/{token-goat-chunk-EVC4TOLE.mjs → token-goat-chunk-METECDOH.mjs} +3 -12
  92. package/dist/{token-goat-chunk-2AWQ2R5X.mjs → token-goat-chunk-MHX7XCC3.mjs} +3 -2
  93. package/dist/token-goat-chunk-MNWKPRAL.mjs +13 -0
  94. package/dist/token-goat-chunk-N5LSOVSU.mjs +137 -0
  95. package/dist/{token-goat-chunk-DPNLUJWB.mjs → token-goat-chunk-N5MMR2IW.mjs} +30 -8
  96. package/dist/token-goat-chunk-N7B3JQ2C.mjs +160 -0
  97. package/dist/{token-goat-chunk-VMFWNHGR.mjs → token-goat-chunk-NISNMD7T.mjs} +2545 -2953
  98. package/dist/token-goat-chunk-NMD42SFQ.mjs +434 -0
  99. package/dist/token-goat-chunk-NOSS5VWY.mjs +174 -0
  100. package/dist/token-goat-chunk-NSNSPPBG.mjs +69 -0
  101. package/dist/token-goat-chunk-OBOFIHKN.mjs +38 -0
  102. package/dist/token-goat-chunk-OBRFJ5O5.mjs +76 -0
  103. package/dist/token-goat-chunk-ODBT2USM.mjs +800 -0
  104. package/dist/token-goat-chunk-OS5EM5PP.mjs +107 -0
  105. package/dist/token-goat-chunk-OUKDTVNU.mjs +1178 -0
  106. package/dist/token-goat-chunk-OXFMP75N.mjs +566 -0
  107. package/dist/{token-goat-chunk-ASLWOQ3I.mjs → token-goat-chunk-OYIYKDDT.mjs} +2 -1
  108. package/dist/{token-goat-chunk-67BNIKKO.mjs → token-goat-chunk-P6HQSWQ3.mjs} +55 -47
  109. package/dist/token-goat-chunk-P6VGNTQT.mjs +71 -0
  110. package/dist/token-goat-chunk-PFWIMH2E.mjs +261 -0
  111. package/dist/token-goat-chunk-PJZXIS3G.mjs +39 -0
  112. package/dist/token-goat-chunk-PUO5INXP.mjs +606 -0
  113. package/dist/token-goat-chunk-PX5PQWTY.mjs +462 -0
  114. package/dist/token-goat-chunk-Q5QDBC6O.mjs +111 -0
  115. package/dist/token-goat-chunk-QFNQXSDT.mjs +40 -0
  116. package/dist/token-goat-chunk-QH7YVYOY.mjs +3957 -0
  117. package/dist/token-goat-chunk-QLMUHEPB.mjs +43 -0
  118. package/dist/{token-goat-chunk-PYSUADX4.mjs → token-goat-chunk-QQOJIHL3.mjs} +50 -14
  119. package/dist/token-goat-chunk-QQTWJY2O.mjs +85 -0
  120. package/dist/token-goat-chunk-QYHO5CPH.mjs +93 -0
  121. package/dist/token-goat-chunk-RELAVWAD.mjs +27 -0
  122. package/dist/token-goat-chunk-RSLPOBKQ.mjs +339 -0
  123. package/dist/token-goat-chunk-SAMFDIS2.mjs +712 -0
  124. package/dist/token-goat-chunk-SDELXLDM.mjs +48 -0
  125. package/dist/{token-goat-chunk-PGTH2U4C.mjs → token-goat-chunk-SOAFZNNZ.mjs} +164 -40
  126. package/dist/{token-goat-chunk-G23DWHV4.mjs → token-goat-chunk-SRTHT7KV.mjs} +33 -15
  127. package/dist/token-goat-chunk-T5P5ACNQ.mjs +212 -0
  128. package/dist/token-goat-chunk-T5YGG4V3.mjs +45 -0
  129. package/dist/token-goat-chunk-TAUZ4OFS.mjs +110 -0
  130. package/dist/token-goat-chunk-TM6MC754.mjs +40 -0
  131. package/dist/token-goat-chunk-TWUKBOMP.mjs +72 -0
  132. package/dist/token-goat-chunk-U2KSB4SG.mjs +56 -0
  133. package/dist/token-goat-chunk-U4WHMG6Y.mjs +898 -0
  134. package/dist/token-goat-chunk-UA5V6P3P.mjs +122 -0
  135. package/dist/token-goat-chunk-UGJHGR5A.mjs +52 -0
  136. package/dist/{token-goat-chunk-RQGGMPCR.mjs → token-goat-chunk-UOUDVA5U.mjs} +76 -16
  137. package/dist/{token-goat-chunk-HNFZZHFW.mjs → token-goat-chunk-URRJ33GR.mjs} +22 -4
  138. package/dist/token-goat-chunk-UZOROKIS.mjs +165 -0
  139. package/dist/token-goat-chunk-VIHGGGEI.mjs +4234 -0
  140. package/dist/token-goat-chunk-VTJLAA7P.mjs +21 -0
  141. package/dist/token-goat-chunk-VWDXLT4F.mjs +678 -0
  142. package/dist/token-goat-chunk-VWZA2H4P.mjs +368 -0
  143. package/dist/{token-goat-chunk-QO3LXVVR.mjs → token-goat-chunk-VXEXMJDL.mjs} +2964 -3153
  144. package/dist/token-goat-chunk-WBA5SKT4.mjs +547 -0
  145. package/dist/{token-goat-chunk-ONXH6NZ5.mjs → token-goat-chunk-WDH44VAU.mjs} +19 -22
  146. package/dist/token-goat-chunk-X2SUP3EI.mjs +107 -0
  147. package/dist/token-goat-chunk-X3BELZSJ.mjs +125 -0
  148. package/dist/{token-goat-chunk-RLP6J7WR.mjs → token-goat-chunk-XLRBNZCC.mjs} +40 -21
  149. package/dist/{token-goat-chunk-S4VSXURL.mjs → token-goat-chunk-XRKUX6CM.mjs} +4 -0
  150. package/dist/token-goat-chunk-XX6O25RN.mjs +82 -0
  151. package/dist/token-goat-chunk-XZSUHBVS.mjs +65 -0
  152. package/dist/token-goat-chunk-Y2ZTQOCL.mjs +35 -0
  153. package/dist/{token-goat-chunk-UA5BKWWQ.mjs → token-goat-chunk-YB4VMGK2.mjs} +15 -4
  154. package/dist/token-goat-chunk-YBIIY3HR.mjs +51 -0
  155. package/dist/{token-goat-chunk-PKRWMHVP.mjs → token-goat-chunk-YHVDKQBR.mjs} +389 -221
  156. package/dist/token-goat-chunk-YJB5XLWI.mjs +26 -0
  157. package/dist/{token-goat-chunk-PQ53BSCF.mjs → token-goat-chunk-YKB6AQG3.mjs} +53 -31
  158. package/dist/token-goat-chunk-YMTG2YA5.mjs +35 -0
  159. package/dist/token-goat-chunk-YPBZYQRV.mjs +40 -0
  160. package/dist/{token-goat-chunk-HUYUHODZ.mjs → token-goat-chunk-YY6AVUFL.mjs} +13246 -12247
  161. package/dist/token-goat-chunk-Z7N5OMMP.mjs +98 -0
  162. package/dist/{token-goat-chunk-BGHSSJUA.mjs → token-goat-chunk-ZFOBKUWH.mjs} +1 -1
  163. package/dist/token-goat-chunk-ZMBL6UVV.mjs +110 -0
  164. package/dist/token-goat-chunk-ZNMNUPAZ.mjs +938 -0
  165. package/dist/token-goat-hook-client.cjs +87 -23
  166. package/dist/token-goat-hook-client.mjs +3 -3
  167. package/dist/token-goat-hook.mjs +76 -31
  168. package/dist/token-goat.core.mjs +6 -6
  169. package/docs/C4_RUNTIME_ARCHITECTURE.md +2 -2
  170. package/docs/cli.md +113 -60
  171. package/docs/install.md +63 -20
  172. package/docs/security.md +10 -8
  173. package/package.json +18 -7
  174. package/scripts/verify-native-dist.mjs +386 -0
  175. package/dist/token-goat-chunk-2NNUA2LR.mjs +0 -143
  176. package/dist/token-goat-chunk-44BM7DDQ.mjs +0 -294
  177. package/dist/token-goat-chunk-BGYOZ6DO.mjs +0 -24
  178. package/dist/token-goat-chunk-C5YPNZKQ.mjs +0 -318
  179. package/dist/token-goat-chunk-CIQ2FTY3.mjs +0 -1990
  180. package/dist/token-goat-chunk-D4ETHJD6.mjs +0 -246
  181. package/dist/token-goat-chunk-DNRPXHYH.mjs +0 -1062
  182. package/dist/token-goat-chunk-EUSDXRXU.mjs +0 -1429
  183. package/dist/token-goat-chunk-FTP4U4QA.mjs +0 -64
  184. package/dist/token-goat-chunk-G7IWXCFF.mjs +0 -456
  185. package/dist/token-goat-chunk-GLXRTTLE.mjs +0 -36
  186. package/dist/token-goat-chunk-H5J3C56Q.mjs +0 -1511
  187. package/dist/token-goat-chunk-IVWI2OCK.mjs +0 -368
  188. package/dist/token-goat-chunk-JTKCQMQA.mjs +0 -418
  189. package/dist/token-goat-chunk-LZNBQTDK.mjs +0 -26
  190. package/dist/token-goat-chunk-ORNFMIER.mjs +0 -295
  191. package/dist/token-goat-chunk-RTMVLHWX.mjs +0 -7113
  192. package/dist/token-goat-chunk-VQ6F6T7X.mjs +0 -36
  193. package/dist/token-goat-chunk-VZQEWRVH.mjs +0 -312
  194. package/dist/token-goat-chunk-XYWPOSCN.mjs +0 -807
  195. package/dist/token-goat-chunk-YAGLESS3.mjs +0 -23
  196. package/dist/token-goat-chunk-YKSRAWUU.mjs +0 -33
  197. package/dist/token-goat-chunk-Z6KBMOBI.mjs +0 -53
@@ -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,21 +29,27 @@ import {
24
29
  extractSolidity,
25
30
  extractSwift,
26
31
  extractThrift,
27
- extractWgsl
28
- } from "./token-goat-chunk-PGTH2U4C.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-VMFWNHGR.mjs";
32
- import "./token-goat-chunk-435UQTKD.mjs";
38
+ } from "./token-goat-chunk-OXFMP75N.mjs";
39
+ import "./token-goat-chunk-NISNMD7T.mjs";
40
+ import "./token-goat-chunk-EVMZJ27Z.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";
33
47
  import {
34
48
  GENERIC_CLAUSE,
35
- assignBraceBlockSpans,
36
49
  assignFlatEndLines,
37
50
  buildLineIndex,
38
- extractEnv,
39
- extractIni,
51
+ closingQuoteRunEnd,
40
52
  findHtmlHeadingMatches,
41
- findMatchingBraceEndLine,
42
53
  isInsideStringLiteral,
43
54
  lineTextAt,
44
55
  makeLineSymbol,
@@ -50,6 +61,7 @@ import {
50
61
  offsetToLine,
51
62
  precedingDocComment,
52
63
  propagateEndLinesToSymbols,
64
+ scalaCharLiteralLength,
53
65
  scanQuotedStringEnd,
54
66
  stripBlockCommentSpan,
55
67
  stripCstyleComments,
@@ -59,21 +71,27 @@ import {
59
71
  stripMultilineStringSpan,
60
72
  stripStringLiterals,
61
73
  stripXmlComments
62
- } from "./token-goat-chunk-7CPMDFGB.mjs";
63
- import "./token-goat-chunk-TGOXNAHW.mjs";
64
- import "./token-goat-chunk-XB5KKOCG.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";
65
78
  import "./token-goat-chunk-YZAAZU2S.mjs";
66
79
  import "./token-goat-chunk-IVE6U7KV.mjs";
80
+ import {
81
+ elementCursor,
82
+ findElements,
83
+ gtFinder
84
+ } from "./token-goat-chunk-E45INMY3.mjs";
85
+ import "./token-goat-chunk-Y4AFKTHK.mjs";
67
86
  import {
68
87
  countContentLines,
69
88
  escapeRegExp,
70
89
  pushAll
71
- } from "./token-goat-chunk-XYWPOSCN.mjs";
72
- import "./token-goat-chunk-TCQANXYC.mjs";
73
- import "./token-goat-chunk-NMTKNYGF.mjs";
74
- import "./token-goat-chunk-MELOKFDJ.mjs";
75
- import "./token-goat-chunk-Y4AFKTHK.mjs";
76
- import "./token-goat-chunk-JTKCQMQA.mjs";
90
+ } from "./token-goat-chunk-HU4TORC5.mjs";
91
+ import "./token-goat-chunk-GGGG7RWB.mjs";
92
+ import "./token-goat-chunk-AM5V6GSX.mjs";
93
+ import "./token-goat-chunk-FNFBKLRD.mjs";
94
+ import "./token-goat-chunk-CO3UYX6G.mjs";
77
95
  import {
78
96
  init_define_import_meta_env
79
97
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -81,6 +99,682 @@ import {
81
99
  // src/languages/registry.ts
82
100
  init_define_import_meta_env();
83
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
+
84
778
  // src/languages/csharp.ts
85
779
  init_define_import_meta_env();
86
780
  var IDENT = "@?[A-Za-z_][A-Za-z0-9_]*";
@@ -144,6 +838,13 @@ var PROPERTY_ARROW_RE = new RegExp(
144
838
  var CONSTRUCTOR_RE = new RegExp(
145
839
  `${MEMBER_INDENT}(?:(?:public|protected|private|internal|static)\\s+)*(${IDENT})\\s*\\(`
146
840
  );
841
+ var FINALIZER_RE = new RegExp(`${MEMBER_INDENT}(?:(?:extern|unsafe)\\s+)*~\\s*(${IDENT})\\s*\\(`);
842
+ var OPERATOR_RE = /\b(?:implicit|explicit)\s+operator\s([^(]+)\(|\boperator(\s+checked)?\s*([-+!~*/%&|^<>=]+|true|false)\s*\(/;
843
+ var INDEXER_RE = /\bthis\s*\[/;
844
+ var DECLARATION_PREFIX_RE = /^[\w@.<>,?[\]()\s]*$/;
845
+ function isDeclarationPrefix(prefix) {
846
+ return DECLARATION_PREFIX_RE.test(prefix) && /\w/.test(prefix);
847
+ }
147
848
  var CLASS_HEADER_RE = new RegExp(
148
849
  `^(?:(?:public|protected|private|internal|abstract|sealed|static|partial|readonly|ref|unsafe|file|new)\\s+)*(class|struct|interface|enum|record)(?:\\s+(?:class|struct))?\\s+(${IDENT})`
149
850
  );
@@ -159,9 +860,162 @@ function nextCodeLines(lines, from, count) {
159
860
  }
160
861
  return out;
161
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
+ }
923
+ var CS_REF_NOISE = /* @__PURE__ */ new Set([
924
+ "if",
925
+ "else",
926
+ "while",
927
+ "for",
928
+ "foreach",
929
+ "switch",
930
+ "case",
931
+ "catch",
932
+ "finally",
933
+ "using",
934
+ "lock",
935
+ "fixed",
936
+ "sizeof",
937
+ "typeof",
938
+ "nameof",
939
+ "default",
940
+ "checked",
941
+ "unchecked",
942
+ "delegate",
943
+ "return",
944
+ "throw",
945
+ "yield",
946
+ "base",
947
+ "this",
948
+ "new",
949
+ "var",
950
+ "async",
951
+ "await",
952
+ "get",
953
+ "set",
954
+ "init",
955
+ "add",
956
+ "remove",
957
+ "where",
958
+ "when",
959
+ "select",
960
+ "from",
961
+ "join",
962
+ "into",
963
+ "let",
964
+ "orderby",
965
+ "group",
966
+ "by",
967
+ "equals",
968
+ "on",
969
+ "ascending",
970
+ "descending",
971
+ "true",
972
+ "false",
973
+ "null",
974
+ "void",
975
+ "bool",
976
+ "byte",
977
+ "sbyte",
978
+ "short",
979
+ "ushort",
980
+ "int",
981
+ "uint",
982
+ "long",
983
+ "ulong",
984
+ "float",
985
+ "double",
986
+ "decimal",
987
+ "char",
988
+ "string",
989
+ "object",
990
+ "dynamic",
991
+ "public",
992
+ "private",
993
+ "protected",
994
+ "internal",
995
+ "static",
996
+ "readonly",
997
+ "volatile",
998
+ "virtual",
999
+ "override",
1000
+ "abstract",
1001
+ "sealed",
1002
+ "extern",
1003
+ "unsafe",
1004
+ "partial",
1005
+ "class",
1006
+ "struct",
1007
+ "interface",
1008
+ "enum",
1009
+ "record"
1010
+ ]);
1011
+ var CS_NEW_CALL_RE = /\bnew\s+([A-Za-z_][A-Za-z0-9_.]*)(?:<[^>()]+>)?\s*(?:\(|(?=\{))/g;
1012
+ var CS_INVOCATION_RE = /(?:\b([A-Za-z_][A-Za-z0-9_]*)\s*(?:\.|\?\.)\s*|(?:\.|\?\.)\s*)?\b([A-Za-z_][A-Za-z0-9_]*)(?:\s*<[^>()\n]+>)?\s*\(/g;
1013
+ var CS_MULTILINE_INVOCATION_RE = /(?:\b([A-Za-z_][A-Za-z0-9_]*)\s*(?:\.|\?\.)\s*|(?:\.|\?\.)\s*)?\b([A-Za-z_][A-Za-z0-9_]*)(?:\s*<[^>()\n]+>)?\s*$/;
162
1014
  function extractCsharp(content, filePath) {
163
1015
  const symbols = [];
1016
+ const refs = [];
164
1017
  const imports = [];
1018
+ const seenRefs = /* @__PURE__ */ new Set();
165
1019
  const lines = content.split(/\r?\n/);
166
1020
  const classStack = [];
167
1021
  let braceDepth = 0;
@@ -169,6 +1023,10 @@ function extractCsharp(content, filePath) {
169
1023
  let mlState = null;
170
1024
  let inFalseBlock = false;
171
1025
  let falseNesting = 0;
1026
+ let currentMember;
1027
+ let memberBodyEntered = false;
1028
+ const settled = /* @__PURE__ */ new Set();
1029
+ let openMembers = [];
172
1030
  for (let i = 0; i < lines.length; i++) {
173
1031
  const rawLine = lines[i] ?? "";
174
1032
  const lineNum = i + 1;
@@ -210,25 +1068,31 @@ function extractCsharp(content, filePath) {
210
1068
  const delegateParent = classStack.length > 0 ? classStack[classStack.length - 1].name : void 0;
211
1069
  symbols.push(makeLineSymbol(filePath, stripVerbatim(delM[1] ?? ""), "type", lineNum, stripped.slice(0, 200), delegateParent, lines, "c"));
212
1070
  }
1071
+ const outerFrame = classStack.length > 0 ? classStack[classStack.length - 1] : null;
213
1072
  const cm = CLASS_HEADER_RE.exec(stripLeadingAttributes(stripped));
214
1073
  if (cm) {
215
- const keyword = cm[1] ?? "class";
216
1074
  const cname = stripVerbatim(cm[2] ?? "");
217
- const kind = keyword === "struct" ? "struct" : keyword === "interface" ? "interface" : keyword === "enum" ? "enum" : "class";
218
- const parent = classStack.length > 0 ? classStack[classStack.length - 1].name : void 0;
219
- 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"));
220
1076
  classStack.push({ name: cname, startDepth: braceDepth, bodyEntered: false });
221
1077
  }
1078
+ let ctorM = null;
1079
+ let finM = null;
1080
+ let methM = null;
1081
+ let propM = null;
1082
+ let headerM = null;
1083
+ let arrowM = null;
222
1084
  const frame = classStack.length > 0 ? classStack[classStack.length - 1] : null;
223
1085
  if (frame !== null) {
224
1086
  const depthInClass = braceDepth - frame.startDepth;
225
1087
  if (depthInClass === 1) {
226
1088
  const lineNoAttr = stripLeadingAttributes(line);
227
- const ctorM = CONSTRUCTOR_RE.exec(lineNoAttr);
1089
+ ctorM = CONSTRUCTOR_RE.exec(lineNoAttr);
228
1090
  if (ctorM && stripVerbatim(ctorM[1] ?? "") === frame.name) {
229
1091
  const sigEnd = line.indexOf("{");
230
1092
  const sig = sigEnd >= 0 ? line.slice(0, sigEnd).trimEnd() : line.trimEnd();
231
1093
  symbols.push(makeLineSymbol(filePath, frame.name, "method", lineNum, sig.slice(0, 200), frame.name, lines, "c"));
1094
+ currentMember = frame.name;
1095
+ memberBodyEntered = line.includes("{");
232
1096
  }
233
1097
  let isPropertyLine = false;
234
1098
  const eventM = EVENT_RE.exec(lineNoAttr);
@@ -240,41 +1104,217 @@ function extractCsharp(content, filePath) {
240
1104
  if (declM) symbols.push(makeLineSymbol(filePath, stripVerbatim(declM[1] ?? ""), "var", lineNum, stripped.slice(0, 200), frame.name, lines, "c"));
241
1105
  }
242
1106
  }
243
- const propM = isPropertyLine ? null : PROPERTY_RE.exec(lineNoAttr);
1107
+ propM = isPropertyLine ? null : PROPERTY_RE.exec(lineNoAttr);
244
1108
  if (propM) {
245
1109
  isPropertyLine = true;
246
- symbols.push(makeLineSymbol(filePath, stripVerbatim(propM[1] ?? ""), "var", lineNum, stripped.slice(0, 200), frame.name, lines, "c"));
1110
+ const propName = stripVerbatim(propM[1] ?? "");
1111
+ symbols.push(makeLineSymbol(filePath, propName, "var", lineNum, stripped.slice(0, 200), frame.name, lines, "c"));
1112
+ currentMember = propName;
1113
+ memberBodyEntered = line.includes("{");
247
1114
  } else {
248
- const headerM = PROPERTY_HEADER_RE.exec(lineNoAttr);
1115
+ headerM = PROPERTY_HEADER_RE.exec(lineNoAttr);
249
1116
  if (headerM) {
250
1117
  const [braceLineNext = "", accessorLine = ""] = nextCodeLines(lines, i, 2);
251
1118
  if (braceLineNext === "{" && (ALLMAN_ACCESSOR_RE.test(accessorLine) || ALLMAN_ACCESSOR_BODY_RE.test(accessorLine))) {
252
1119
  isPropertyLine = true;
253
- symbols.push(makeLineSymbol(filePath, stripVerbatim(headerM[1] ?? ""), "var", lineNum, stripped.slice(0, 200), frame.name, lines, "c"));
1120
+ const propName = stripVerbatim(headerM[1] ?? "");
1121
+ symbols.push(makeLineSymbol(filePath, propName, "var", lineNum, stripped.slice(0, 200), frame.name, lines, "c"));
1122
+ currentMember = propName;
1123
+ memberBodyEntered = false;
254
1124
  }
255
1125
  } else {
256
- const arrowM = PROPERTY_ARROW_RE.exec(lineNoAttr);
1126
+ arrowM = PROPERTY_ARROW_RE.exec(lineNoAttr);
257
1127
  if (arrowM) {
258
1128
  isPropertyLine = true;
259
- symbols.push(makeLineSymbol(filePath, stripVerbatim(arrowM[1] ?? ""), "var", lineNum, stripped.slice(0, 200), frame.name, lines, "c"));
1129
+ const propName = stripVerbatim(arrowM[1] ?? "");
1130
+ symbols.push(makeLineSymbol(filePath, propName, "var", lineNum, stripped.slice(0, 200), frame.name, lines, "c"));
1131
+ currentMember = propName;
1132
+ memberBodyEntered = false;
260
1133
  }
261
1134
  }
262
1135
  }
263
- const methM = isPropertyLine ? null : METHOD_RE.exec(lineNoAttr);
1136
+ let specialName = null;
1137
+ let specialKind = "method";
1138
+ finM = FINALIZER_RE.exec(lineNoAttr);
1139
+ if (finM && stripVerbatim(finM[1] ?? "") === frame.name) specialName = `~${frame.name}`;
1140
+ else finM = null;
1141
+ const opM = specialName === null && !isPropertyLine ? OPERATOR_RE.exec(lineNoAttr) : null;
1142
+ if (opM && isDeclarationPrefix(lineNoAttr.slice(0, opM.index))) specialName = operatorName(opM);
1143
+ const ixM = specialName === null && !isPropertyLine ? INDEXER_RE.exec(lineNoAttr) : null;
1144
+ if (ixM && isDeclarationPrefix(lineNoAttr.slice(0, ixM.index))) {
1145
+ specialName = "this[]";
1146
+ specialKind = "var";
1147
+ }
1148
+ if (specialName !== null) {
1149
+ isPropertyLine = true;
1150
+ const sigEnd = line.indexOf("{");
1151
+ const sig = sigEnd >= 0 ? line.slice(0, sigEnd).trimEnd() : line.trimEnd();
1152
+ symbols.push(makeLineSymbol(filePath, specialName, specialKind, lineNum, sig.slice(0, 200), frame.name, lines, "c"));
1153
+ currentMember = specialName;
1154
+ memberBodyEntered = line.includes("{");
1155
+ }
1156
+ methM = isPropertyLine ? null : METHOD_RE.exec(lineNoAttr);
264
1157
  if (methM) {
265
1158
  const mname = stripVerbatim(methM[1] ?? "");
266
1159
  if (mname && mname !== frame.name) {
267
1160
  const sigEnd = line.indexOf("{");
268
1161
  const sig = sigEnd >= 0 ? line.slice(0, sigEnd).trimEnd() : line.trimEnd();
269
1162
  symbols.push(makeLineSymbol(filePath, mname, "method", lineNum, sig.slice(0, 200), frame.name, lines, "c"));
1163
+ currentMember = mname;
1164
+ memberBodyEntered = line.includes("{");
1165
+ }
1166
+ }
1167
+ }
1168
+ }
1169
+ const isInterpolatedLine = rawLine.includes('$"') || rawLine.includes('$@"') || rawLine.includes('@$"');
1170
+ const baseLine = isInterpolatedLine ? stripLineComment(rawLine) : stripLineComment(line);
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
+ }
1196
+ if (!inFalseBlock && !stripped.startsWith("#")) {
1197
+ const declSpans = [];
1198
+ if (cm) {
1199
+ const name = stripVerbatim(cm[2] ?? "");
1200
+ declSpans.push({ name, col: line.indexOf(name) });
1201
+ }
1202
+ if (ctorM) {
1203
+ const name = stripVerbatim(ctorM[1] ?? "");
1204
+ declSpans.push({ name, col: line.indexOf(name) });
1205
+ }
1206
+ if (methM) {
1207
+ const name = stripVerbatim(methM[1] ?? "");
1208
+ declSpans.push({ name, col: line.indexOf(name) });
1209
+ }
1210
+ if (delM) {
1211
+ const name = stripVerbatim(delM[1] ?? "");
1212
+ declSpans.push({ name, col: line.indexOf(name) });
1213
+ }
1214
+ if (propM) {
1215
+ const name = stripVerbatim(propM[1] ?? "");
1216
+ declSpans.push({ name, col: line.indexOf(name) });
1217
+ }
1218
+ if (headerM) {
1219
+ const name = stripVerbatim(headerM[1] ?? "");
1220
+ declSpans.push({ name, col: line.indexOf(name) });
1221
+ }
1222
+ if (finM) declSpans.push({ name: stripVerbatim(finM[1] ?? ""), col: line.indexOf("~") + 1 });
1223
+ if (arrowM) {
1224
+ const name = stripVerbatim(arrowM[1] ?? "");
1225
+ declSpans.push({ name, col: line.indexOf(name) });
1226
+ }
1227
+ const isDeclaration = (name, col) => declSpans.some((d) => d.name === name && Math.abs(d.col - col) <= 2);
1228
+ const context = currentMember ?? (frame !== null ? frame.name : "");
1229
+ for (const m of braceLine.matchAll(CS_NEW_CALL_RE)) {
1230
+ const rawName = stripVerbatim(m[1] ?? "");
1231
+ const name = rawName.includes(".") ? rawName.slice(rawName.lastIndexOf(".") + 1) : rawName;
1232
+ if (name.length < 1 || CS_REF_NOISE.has(name)) continue;
1233
+ const nameOffset = m[0].lastIndexOf(name);
1234
+ const col = m.index !== void 0 ? m.index + (nameOffset >= 0 ? nameOffset : 0) : 0;
1235
+ if (isDeclaration(name, col)) continue;
1236
+ const key = `${name}\0${lineNum}`;
1237
+ if (!seenRefs.has(key)) {
1238
+ seenRefs.add(key);
1239
+ refs.push({ filePath, name, line: lineNum, col, context });
1240
+ }
1241
+ }
1242
+ for (const m of braceLine.matchAll(CS_INVOCATION_RE)) {
1243
+ const callee = stripVerbatim(m[2] ?? "");
1244
+ if (callee.length >= 1 && !CS_REF_NOISE.has(callee)) {
1245
+ const dotIdx = m[0].indexOf(".");
1246
+ const searchStart = dotIdx >= 0 ? m[0].lastIndexOf(".") + 1 : 0;
1247
+ const calleeOffset = m[0].indexOf(callee, searchStart);
1248
+ const col = m.index !== void 0 ? m.index + (calleeOffset >= 0 ? calleeOffset : 0) : 0;
1249
+ if (!isDeclaration(callee, col)) {
1250
+ const key = `${callee}\0${lineNum}`;
1251
+ if (!seenRefs.has(key)) {
1252
+ seenRefs.add(key);
1253
+ refs.push({ filePath, name: callee, line: lineNum, col, context });
1254
+ }
1255
+ }
1256
+ }
1257
+ const receiver = m[1] !== void 0 ? stripVerbatim(m[1]) : "";
1258
+ if (receiver.length > 1 && !CS_REF_NOISE.has(receiver)) {
1259
+ const col = m.index !== void 0 ? m.index + m[0].indexOf(receiver) : 0;
1260
+ if (!isDeclaration(receiver, col)) {
1261
+ const key = `${receiver}\0${lineNum}`;
1262
+ if (!seenRefs.has(key)) {
1263
+ seenRefs.add(key);
1264
+ refs.push({ filePath, name: receiver, line: lineNum, col, context });
1265
+ }
1266
+ }
1267
+ }
1268
+ }
1269
+ const nextCode = nextCodeLines(lines, i, 1)[0];
1270
+ if (nextCode?.startsWith("(")) {
1271
+ const mlMatch = CS_MULTILINE_INVOCATION_RE.exec(braceLine);
1272
+ if (mlMatch) {
1273
+ const callee = stripVerbatim(mlMatch[2] ?? "");
1274
+ if (callee.length >= 1 && !CS_REF_NOISE.has(callee)) {
1275
+ const dotIdx = mlMatch[0].indexOf(".");
1276
+ const searchStart = dotIdx >= 0 ? mlMatch[0].lastIndexOf(".") + 1 : 0;
1277
+ const calleeOffset = mlMatch[0].indexOf(callee, searchStart);
1278
+ const col = mlMatch.index !== void 0 ? mlMatch.index + (calleeOffset >= 0 ? calleeOffset : 0) : 0;
1279
+ if (!isDeclaration(callee, col)) {
1280
+ const key = `${callee}\0${lineNum}`;
1281
+ if (!seenRefs.has(key)) {
1282
+ seenRefs.add(key);
1283
+ refs.push({ filePath, name: callee, line: lineNum, col, context });
1284
+ }
1285
+ }
1286
+ }
1287
+ const receiver = mlMatch[1] !== void 0 ? stripVerbatim(mlMatch[1]) : "";
1288
+ if (receiver.length > 1 && !CS_REF_NOISE.has(receiver)) {
1289
+ const col = mlMatch.index !== void 0 ? mlMatch.index + mlMatch[0].indexOf(receiver) : 0;
1290
+ if (!isDeclaration(receiver, col)) {
1291
+ const key = `${receiver}\0${lineNum}`;
1292
+ if (!seenRefs.has(key)) {
1293
+ seenRefs.add(key);
1294
+ refs.push({ filePath, name: receiver, line: lineNum, col, context });
1295
+ }
1296
+ }
270
1297
  }
271
1298
  }
272
1299
  }
273
1300
  }
274
- const braceLine = stripStringLiterals(stripLineComment(line));
275
1301
  const openBraces = (braceLine.match(/\{/g) ?? []).length;
276
1302
  const closeBraces = (braceLine.match(/\}/g) ?? []).length;
277
1303
  braceDepth += openBraces - closeBraces;
1304
+ openMembers = endOpenMembers(symbols, settled, openMembers, braceDepth, lineNum, lines);
1305
+ openMembers.push(...lineOpens);
1306
+ if (currentMember !== void 0) {
1307
+ if (!memberBodyEntered) {
1308
+ if (openBraces > 0 && braceDepth > (frame?.startDepth ?? 0) + 1) {
1309
+ memberBodyEntered = true;
1310
+ } else if (stripped.endsWith(";")) {
1311
+ currentMember = void 0;
1312
+ }
1313
+ } else if (frame === null || braceDepth <= frame.startDepth + 1) {
1314
+ currentMember = void 0;
1315
+ memberBodyEntered = false;
1316
+ }
1317
+ }
278
1318
  const bracelessTop = classStack.length > 0 ? classStack[classStack.length - 1] : null;
279
1319
  if (bracelessTop !== null && !bracelessTop.bodyEntered && braceDepth === bracelessTop.startDepth && (openBraces > 0 && openBraces === closeBraces || openBraces === 0 && closeBraces === 0 && stripped.endsWith(";"))) {
280
1320
  classStack.pop();
@@ -293,7 +1333,7 @@ function extractCsharp(content, filePath) {
293
1333
  }
294
1334
  }
295
1335
  }
296
- return { symbols, imports };
1336
+ return { symbols, refs, imports, settled };
297
1337
  }
298
1338
 
299
1339
  // src/languages/php.ts
@@ -321,6 +1361,18 @@ var USE_RE = /^use\s+(?:function\s+|const\s+)?([\w\\]+)(?:\s+as\s+\w+)?\s*;/i;
321
1361
  var GROUP_USE_RE = /^use\s+(?:function\s+|const\s+)?([\w\\]+)\\\{([^}]*)\}/i;
322
1362
  var REQUIRE_RE = /^(?:require|include)(?:_once)?\s+['"]([^'"]+)['"]/i;
323
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
+ }
324
1376
  function maskPhpInlineHtml(content) {
325
1377
  const opener = /<\?(?:php\b|=)/i;
326
1378
  if (!opener.test(content)) return content;
@@ -351,12 +1403,34 @@ function extractPhp(content, filePath) {
351
1403
  const symbols = [];
352
1404
  const imports = [];
353
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
+ };
354
1427
  const contextStack = [];
355
1428
  let braceDepth = 0;
356
1429
  let parenDepth = 0;
357
1430
  let inComment = false;
358
1431
  let mlState = null;
359
1432
  for (let i = 0; i < lines.length; i++) {
1433
+ flushMembers();
360
1434
  const rawLine = lines[i] ?? "";
361
1435
  const lineNum = i + 1;
362
1436
  let mlLine = rawLine;
@@ -384,6 +1458,23 @@ function extractPhp(content, filePath) {
384
1458
  if (topFrame !== void 0 && braceDepth > topFrame[1]) {
385
1459
  topFrame[2] = true;
386
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
+ }
387
1478
  while (contextStack.length > 0) {
388
1479
  const top = contextStack[contextStack.length - 1];
389
1480
  if (top !== void 0 && top[2] && braceDepth <= top[1]) {
@@ -430,6 +1521,8 @@ function extractPhp(content, filePath) {
430
1521
  const parent = topFrame2 !== void 0 && preLineDepth === topFrame2[1] + 1 ? topFrame2[0] : null;
431
1522
  symbols.push(makeLineSymbol(filePath, name, kind, lineNum, stripped.slice(0, 200), parent ?? void 0, lines, "c"));
432
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;
433
1526
  if (openB > 0 && openB === closeB) {
434
1527
  contextStack.pop();
435
1528
  }
@@ -481,7 +1574,8 @@ function extractPhp(content, filePath) {
481
1574
  symbols.push(makeLineSymbol(filePath, defineM[1] ?? "", "const", lineNum, stripped.slice(0, 200), void 0, lines, "c"));
482
1575
  }
483
1576
  }
484
- return { symbols, imports };
1577
+ flushMembers();
1578
+ return { symbols, imports, settled };
485
1579
  }
486
1580
 
487
1581
  // src/languages/html.ts
@@ -530,20 +1624,66 @@ function isNoise(name) {
530
1624
  }
531
1625
  var MAX_SYMBOLS = 1e4;
532
1626
  var VOID_ELEMENTS = /* @__PURE__ */ new Set(["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"]);
533
- 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
+ }
534
1672
  var ELEMENT_SPAN_SCAN_CAP = 2e6;
535
1673
  function buildElementSpans(code) {
536
1674
  const spans = /* @__PURE__ */ new Map();
537
1675
  const openTagRanges = [];
538
1676
  const stack = [];
539
- TAG_RE.lastIndex = 0;
1677
+ const nextTag = makeTagScanner(code);
1678
+ const styleClose = /<\/style\s*>/gi;
1679
+ let styleCloseMissing = false;
1680
+ let from = 0;
540
1681
  let m;
541
- while ((m = TAG_RE.exec(code)) !== null) {
542
- if (m.index > ELEMENT_SPAN_SCAN_CAP) break;
543
- const isClose = m[1] === "/";
544
- const name = (m[2] ?? "").toLowerCase();
545
- const selfClosing = m[0][m[0].length - 2] === "/";
546
- 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;
547
1687
  if (isClose) {
548
1688
  for (let i = stack.length - 1; i >= 0; i--) {
549
1689
  if (stack[i].name === name) {
@@ -554,14 +1694,17 @@ function buildElementSpans(code) {
554
1694
  }
555
1695
  continue;
556
1696
  }
557
- openTagRanges.push({ start: m.index, end: tagEnd });
1697
+ openTagRanges.push({ start: m.start, end: tagEnd });
558
1698
  if (selfClosing || VOID_ELEMENTS.has(name)) continue;
559
1699
  if (name === "style") {
560
- const closeMatch = /<\/style\s*>/gi.exec(code.slice(tagEnd));
561
- 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;
562
1705
  continue;
563
1706
  }
564
- stack.push({ name, start: m.index });
1707
+ stack.push({ name, start: m.start });
565
1708
  }
566
1709
  return { spans, openTagRanges };
567
1710
  }
@@ -754,12 +1897,47 @@ var TYPEALIAS_RE = new RegExp(
754
1897
  var TOP_FUN_RE = new RegExp(
755
1898
  "^(?:(?:public|internal|private|suspend|inline|infix|operator|external|actual|expect|tailrec)\\s+)*fun\\s+(?:" + GENERIC_CLAUSE + "\\s*)?" + RECEIVER_RE + "(" + NAME_RE + ")\\s*[(<]"
756
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
+ }
757
1933
  function extractKotlin(content, filePath) {
758
1934
  const symbols = [];
759
1935
  const imports = [];
760
1936
  const lines = content.split(/\r?\n/);
761
1937
  const classStack = [];
762
1938
  let braceDepth = 0;
1939
+ const settled = /* @__PURE__ */ new Set();
1940
+ let openMembers = [];
763
1941
  let inComment = false;
764
1942
  let mlState = null;
765
1943
  for (let i = 0; i < lines.length; i++) {
@@ -850,6 +2028,23 @@ function extractKotlin(content, filePath) {
850
2028
  }
851
2029
  }
852
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);
853
2048
  for (const ch of braceLine) {
854
2049
  if (ch === "{") {
855
2050
  braceDepth++;
@@ -864,6 +2059,8 @@ function extractKotlin(content, filePath) {
864
2059
  frame.parenBalance--;
865
2060
  }
866
2061
  }
2062
+ openMembers = endOpenMembers(symbols, settled, openMembers, braceDepth, lineNum, lines);
2063
+ openMembers.push(...lineOpens);
867
2064
  if (frame !== null && !frame.bodyEntered && frame.parenBalance <= 0) {
868
2065
  frame.pendingPop = !(stripped.endsWith(":") || stripped.endsWith(","));
869
2066
  }
@@ -876,12 +2073,28 @@ function extractKotlin(content, filePath) {
876
2073
  }
877
2074
  }
878
2075
  }
879
- return { symbols, imports };
2076
+ return { symbols, imports, settled };
880
2077
  }
881
2078
 
882
2079
  // src/languages/scala.ts
883
2080
  init_define_import_meta_env();
884
- var SCALA_STRIP = { symbolLiterals: true };
2081
+ var SCALA_STRIP = { symbolLiterals: true, interpolatorPrefix: true };
2082
+ var MEMBER_KINDS = /* @__PURE__ */ new Set(["function", "val", "var"]);
2083
+ function withSpanEnd(sym, endLine, lines) {
2084
+ if (endLine <= sym.lineStart) return sym;
2085
+ return { ...sym, lineEnd: endLine, body: lines.slice(sym.lineStart - 1, endLine).join("\n") };
2086
+ }
2087
+ function indentedBodyEnd(lines, startLine, declIndent) {
2088
+ let end = startLine;
2089
+ for (let j = startLine; j < lines.length; j++) {
2090
+ const text = lines[j] ?? "";
2091
+ const trimmed = text.trim();
2092
+ if (trimmed === "" || trimmed.startsWith("//")) continue;
2093
+ if (indentOf(text) <= declIndent) break;
2094
+ end = j + 1;
2095
+ }
2096
+ return end;
2097
+ }
885
2098
  function indentOf(line) {
886
2099
  return line.length - line.trimStart().length;
887
2100
  }
@@ -897,11 +2110,151 @@ var OBJECT_RE = new RegExp("^\\s*(?:package\\s+)?" + MODS + "object\\s+(" + NAME
897
2110
  var TRAIT_RE = new RegExp("^\\s*" + MODS + "trait\\s+(" + NAME + ")(?:\\s|\\[|:|$)");
898
2111
  var ENUM_RE = new RegExp("^\\s*(?:private|protected)?\\s*enum\\s+(" + NAME + ")(?:\\s|\\[|\\(|:|$)");
899
2112
  var DEF_NAME = "(?:`[^`\\r\\n]+`|[A-Za-z_][A-Za-z0-9_]*_[+\\-*/%=!<>&|^~:]+|[+\\-*/%=!<>&|^~:]+|[A-Za-z_][A-Za-z0-9_]*)";
900
- 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*=(?!=))");
901
2114
  var VAL_RE = new RegExp("^\\s*" + MODS + "val\\s+(" + NAME + ")");
902
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
+ }
903
2209
  function startsDeclaration(stripped) {
904
- 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 };
905
2258
  }
906
2259
  function extractScala(content, filePath) {
907
2260
  const symbols = [];
@@ -909,8 +2262,16 @@ function extractScala(content, filePath) {
909
2262
  const lines = content.split(/\r?\n/);
910
2263
  const typeStack = [];
911
2264
  let braceDepth = 0;
2265
+ const settled = /* @__PURE__ */ new Set();
2266
+ let openMembers = [];
912
2267
  let inComment = false;
913
2268
  let mlState = null;
2269
+ let lastCodeLine = 0;
2270
+ let extBlock = null;
2271
+ const closeColonFrame = (frame, endLine) => {
2272
+ const open = symbols[frame.symbolIndex];
2273
+ if (open !== void 0) symbols[frame.symbolIndex] = withSpanEnd(open, endLine, lines);
2274
+ };
914
2275
  for (let i = 0; i < lines.length; i++) {
915
2276
  const rawLine = lines[i] ?? "";
916
2277
  const lineNum = i + 1;
@@ -920,7 +2281,7 @@ function extractScala(content, filePath) {
920
2281
  mlLine = masked.code;
921
2282
  mlState = masked.state;
922
2283
  }
923
- const { code: blockStripped, inComment: nextInComment } = stripBlockCommentSpan(mlLine, inComment);
2284
+ const { code: blockStripped, inComment: nextInComment } = stripBlockCommentSpan(mlLine, inComment, SCALA_STRIP);
924
2285
  inComment = nextInComment;
925
2286
  const line = stripLineComment(blockStripped, ["//"], SCALA_STRIP).trimEnd();
926
2287
  const stripped = line.trim();
@@ -933,9 +2294,13 @@ function extractScala(content, filePath) {
933
2294
  const indent = indentOf(line);
934
2295
  while (typeStack.length > 0) {
935
2296
  const top = typeStack[typeStack.length - 1];
936
- if (top.colonBody && indent <= top.declIndent) typeStack.pop();
937
- else break;
2297
+ if (!top.colonBody || indent > top.declIndent) break;
2298
+ typeStack.pop();
2299
+ const closesWithMarker = indent === top.declIndent && stripped === (top.endMarker ?? `end ${top.name}`);
2300
+ closeColonFrame(top, closesWithMarker ? lineNum : lastCodeLine);
2301
+ if (closesWithMarker) lastCodeLine = lineNum;
938
2302
  }
2303
+ lastCodeLine = lineNum;
939
2304
  const colonTop = typeStack.length > 0 && typeStack[typeStack.length - 1].colonBody ? typeStack[typeStack.length - 1] : null;
940
2305
  if (colonTop !== null && colonTop.bodyIndent === null) {
941
2306
  colonTop.bodyIndent = indent;
@@ -974,7 +2339,7 @@ function extractScala(content, filePath) {
974
2339
  const cname = unquoteName2(cm[1] ?? "");
975
2340
  const parent = typeStack.length > 0 ? typeStack[typeStack.length - 1].name : void 0;
976
2341
  symbols.push(makeLineSymbol(filePath, cname, "class", lineNum, stripped.slice(0, 200), parent, lines, "c"));
977
- typeStack.push({ name: cname, startDepth: braceDepth, bodyEntered: false, openParens: 0, declIndent: indent, colonBody: opensColonBody, bodyIndent: null });
2342
+ typeStack.push({ name: cname, startDepth: braceDepth, bodyEntered: false, openParens: 0, declIndent: indent, colonBody: opensColonBody, bodyIndent: null, symbolIndex: symbols.length - 1 });
978
2343
  matched = true;
979
2344
  }
980
2345
  const om = !matched && typeDetectionGateOk && (!isIndented || typeStack.length > 0) ? OBJECT_RE.exec(stripped) : null;
@@ -982,7 +2347,7 @@ function extractScala(content, filePath) {
982
2347
  const oname = unquoteName2(om[1] ?? "");
983
2348
  const parent = typeStack.length > 0 ? typeStack[typeStack.length - 1].name : void 0;
984
2349
  symbols.push(makeLineSymbol(filePath, oname, "object", lineNum, stripped.slice(0, 200), parent, lines, "c"));
985
- typeStack.push({ name: oname, startDepth: braceDepth, bodyEntered: false, openParens: 0, declIndent: indent, colonBody: opensColonBody, bodyIndent: null });
2350
+ typeStack.push({ name: oname, startDepth: braceDepth, bodyEntered: false, openParens: 0, declIndent: indent, colonBody: opensColonBody, bodyIndent: null, symbolIndex: symbols.length - 1 });
986
2351
  matched = true;
987
2352
  }
988
2353
  const tm = !matched && typeDetectionGateOk && (!isIndented || typeStack.length > 0) ? TRAIT_RE.exec(stripped) : null;
@@ -990,7 +2355,7 @@ function extractScala(content, filePath) {
990
2355
  const tname = unquoteName2(tm[1] ?? "");
991
2356
  const parent = typeStack.length > 0 ? typeStack[typeStack.length - 1].name : void 0;
992
2357
  symbols.push(makeLineSymbol(filePath, tname, "trait", lineNum, stripped.slice(0, 200), parent, lines, "c"));
993
- typeStack.push({ name: tname, startDepth: braceDepth, bodyEntered: false, openParens: 0, declIndent: indent, colonBody: opensColonBody, bodyIndent: null });
2358
+ typeStack.push({ name: tname, startDepth: braceDepth, bodyEntered: false, openParens: 0, declIndent: indent, colonBody: opensColonBody, bodyIndent: null, symbolIndex: symbols.length - 1 });
994
2359
  matched = true;
995
2360
  }
996
2361
  const enm = !matched && typeDetectionGateOk && (!isIndented || typeStack.length > 0) ? ENUM_RE.exec(stripped) : null;
@@ -998,10 +2363,37 @@ function extractScala(content, filePath) {
998
2363
  const enname = unquoteName2(enm[1] ?? "");
999
2364
  const parent = typeStack.length > 0 ? typeStack[typeStack.length - 1].name : void 0;
1000
2365
  symbols.push(makeLineSymbol(filePath, enname, "enum", lineNum, stripped.slice(0, 200), parent, lines, "c"));
1001
- typeStack.push({ name: enname, startDepth: braceDepth, bodyEntered: false, openParens: 0, declIndent: indent, colonBody: opensColonBody, bodyIndent: null });
2366
+ typeStack.push({ name: enname, startDepth: braceDepth, bodyEntered: false, openParens: 0, declIndent: indent, colonBody: opensColonBody, bodyIndent: null, symbolIndex: symbols.length - 1 });
2367
+ matched = true;
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
+ }
1002
2376
  matched = true;
1003
2377
  }
1004
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
+ }
1005
2397
  if (!matched && frame !== null) {
1006
2398
  const depthInType = braceDepth - frame.startDepth;
1007
2399
  if (depthInType === 1 || inColonBody && frame === colonTop) {
@@ -1040,7 +2432,34 @@ function extractScala(content, filePath) {
1040
2432
  }
1041
2433
  }
1042
2434
  }
2435
+ const lastSymbol = symbols[symbols.length - 1];
2436
+ if (lastSymbol !== void 0 && lastSymbol.lineStart === lineNum && MEMBER_KINDS.has(lastSymbol.kind) && stripped.endsWith("=") && !stripped.includes("{")) {
2437
+ symbols[symbols.length - 1] = withSpanEnd(lastSymbol, indentedBodyEnd(lines, lineNum, indent), lines);
2438
+ }
1043
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);
1044
2463
  if (frame !== null && !frame.bodyEntered) {
1045
2464
  const parenDelta2 = (braceLine.match(/\(/g) ?? []).length - (braceLine.match(/\)/g) ?? []).length;
1046
2465
  frame.openParens = Math.max(0, frame.openParens + parenDelta2);
@@ -1055,6 +2474,8 @@ function extractScala(content, filePath) {
1055
2474
  braceDepth--;
1056
2475
  }
1057
2476
  }
2477
+ openMembers = endOpenMembers(symbols, settled, openMembers, braceDepth, lineNum, lines);
2478
+ openMembers.push(...lineOpens);
1058
2479
  while (typeStack.length > 0) {
1059
2480
  const top = typeStack[typeStack.length - 1];
1060
2481
  if (!top.colonBody && top.bodyEntered && braceDepth <= top.startDepth) {
@@ -1064,11 +2485,19 @@ function extractScala(content, filePath) {
1064
2485
  }
1065
2486
  }
1066
2487
  }
1067
- return { symbols, imports };
2488
+ while (typeStack.length > 0) {
2489
+ const top = typeStack.pop();
2490
+ if (top.colonBody) closeColonFrame(top, lastCodeLine);
2491
+ }
2492
+ return { symbols, imports, settled };
1068
2493
  }
1069
2494
 
1070
2495
  // src/languages/lua.ts
1071
2496
  init_define_import_meta_env();
2497
+ function receiverName(fname) {
2498
+ const parts = fname.split(/[.:]/);
2499
+ return parts.length > 1 ? parts[parts.length - 2] : void 0;
2500
+ }
1072
2501
  function nearestFunctionName(stack) {
1073
2502
  for (let i = stack.length - 1; i >= 0; i--) {
1074
2503
  const frame = stack[i];
@@ -1160,7 +2589,7 @@ function extractLua(content, filePath) {
1160
2589
  if (fm) {
1161
2590
  const fname = fm[1] ?? "";
1162
2591
  const baseName = fname.split(/[.:]/).pop() ?? fname;
1163
- const parent = nearestFunctionName(funcStack);
2592
+ const parent = receiverName(fname) ?? nearestFunctionName(funcStack);
1164
2593
  if (parent !== void 0) {
1165
2594
  symbols.push(makeLineSymbol(filePath, baseName, "function", lineNum, stripped.slice(0, 200), parent));
1166
2595
  } else {
@@ -1189,7 +2618,7 @@ function extractLua(content, filePath) {
1189
2618
  if (afm) {
1190
2619
  const fname = afm[1] ?? "";
1191
2620
  const baseName = fname.split(/[.:]/).pop() ?? fname;
1192
- const parent = nearestFunctionName(funcStack);
2621
+ const parent = receiverName(fname) ?? nearestFunctionName(funcStack);
1193
2622
  if (parent !== void 0) {
1194
2623
  symbols.push(makeLineSymbol(filePath, baseName, "function", lineNum, stripped.slice(0, 200), parent));
1195
2624
  } else {
@@ -1249,7 +2678,7 @@ var DECLARE_RE = new RegExp(String.raw`^Declare\s+(?:(?:Ansi|Unicode|Auto|PtrSaf
1249
2678
  var VB6_PROPERTY_RE = new RegExp(String.raw`^Property\s+(?:Get|Let|Set)\s+(${ID})`, "i");
1250
2679
  var PROPERTY_RE2 = new RegExp(String.raw`^Property\s+(${ID})`, "i");
1251
2680
  var PROCEDURE_RE = new RegExp(String.raw`^(Sub|Function)\s+(${ID})`, "i");
1252
- var OPERATOR_RE = /^Operator\s+([^\s(]+)\s*\(/i;
2681
+ var OPERATOR_RE2 = /^Operator\s+([^\s(]+)\s*\(/i;
1253
2682
  var EVENT_RE2 = new RegExp(String.raw`^Event\s+(${ID})`, "i");
1254
2683
  var CONST_RE3 = /^Const\s+(\S.*)$/i;
1255
2684
  var DIM_RE = /^Dim\s+(\S.*)$/i;
@@ -1578,7 +3007,7 @@ function extractVb(content, filePath) {
1578
3007
  else open(keyword, name, procedureKind(), stmt);
1579
3008
  continue;
1580
3009
  }
1581
- if ((m = OPERATOR_RE.exec(rest)) !== null) {
3010
+ if ((m = OPERATOR_RE2.exec(rest)) !== null) {
1582
3011
  open("operator", m[1], "method", stmt);
1583
3012
  continue;
1584
3013
  }
@@ -1803,6 +3232,16 @@ function extractVhdl(content, filePath) {
1803
3232
 
1804
3233
  // src/languages/elixir.ts
1805
3234
  init_define_import_meta_env();
3235
+ function bracketDelta(line) {
3236
+ const code = line.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g, "");
3237
+ return (code.match(/[([{]/g)?.length ?? 0) - (code.match(/[)\]}]/g)?.length ?? 0);
3238
+ }
3239
+ var DANGLING_RE = /(?:,|\bwhen|\band|\bor|\bin|&&|\|\||[+\-*/<>=!|&])\s*$/;
3240
+ var DO_KEYWORD_RE = /(?:^|[\s,)])do:/;
3241
+ var DO_KEYWORD_AT_EOL_RE = /(?:^|[\s,)])do:$/;
3242
+ function indentOf2(line) {
3243
+ return line.length - line.trimStart().length;
3244
+ }
1806
3245
  function nearestDefName(stack) {
1807
3246
  for (let i = stack.length - 1; i >= 0; i--) {
1808
3247
  const frame = stack[i];
@@ -1822,6 +3261,30 @@ function extractElixir(content, filePath) {
1822
3261
  const lines = content.split(/\r?\n/);
1823
3262
  const moduleStack = [];
1824
3263
  let mlState = null;
3264
+ let pending;
3265
+ let keywordBody;
3266
+ const extendDefSpan = (symbolIndex, lineEnd) => {
3267
+ const open = symbols[symbolIndex];
3268
+ if (open !== void 0 && lineEnd > open.lineStart) {
3269
+ symbols[symbolIndex] = { ...open, lineEnd, body: lines.slice(open.lineStart - 1, lineEnd).join("\n") };
3270
+ }
3271
+ };
3272
+ const trackKeywordBody = (symbolIndex, stripped) => {
3273
+ const open = symbols[symbolIndex];
3274
+ if (open !== void 0 && DO_KEYWORD_AT_EOL_RE.test(stripped)) {
3275
+ keywordBody = { symbolIndex, headIndent: indentOf2(lines[open.lineStart - 1] ?? "") };
3276
+ }
3277
+ };
3278
+ const settleDefHead = (name, stripped) => {
3279
+ const symbolIndex = symbols.length - 1;
3280
+ if (/\bdo\s*$/.test(stripped)) {
3281
+ moduleStack.push({ name, endKeywordNeeded: true, isBlock: false, symbolIndex });
3282
+ } else if (!DO_KEYWORD_RE.test(stripped)) {
3283
+ pending = { name, symbolIndex, depth: bracketDelta(stripped), dangling: DANGLING_RE.test(stripped) };
3284
+ } else {
3285
+ trackKeywordBody(symbolIndex, stripped);
3286
+ }
3287
+ };
1825
3288
  for (let i = 0; i < lines.length; i++) {
1826
3289
  const rawLine = lines[i] ?? "";
1827
3290
  const lineNum = i + 1;
@@ -1829,9 +3292,37 @@ function extractElixir(content, filePath) {
1829
3292
  mlState = nextMlState;
1830
3293
  const line = stripLineComment(masked, ["#"]).trimEnd();
1831
3294
  const stripped = line.trim();
3295
+ if (keywordBody !== void 0) {
3296
+ if (rawLine.trim() === "") {
3297
+ keywordBody = void 0;
3298
+ } else if (stripped && indentOf2(masked) <= keywordBody.headIndent) {
3299
+ keywordBody = void 0;
3300
+ } else {
3301
+ if (stripped) extendDefSpan(keywordBody.symbolIndex, lineNum);
3302
+ continue;
3303
+ }
3304
+ }
1832
3305
  if (!stripped) {
1833
3306
  continue;
1834
3307
  }
3308
+ if (pending !== void 0) {
3309
+ const startsContinuation = /^(?:when\b|do\b|,|\|)/.test(stripped);
3310
+ if (pending.depth <= 0 && !pending.dangling && !startsContinuation) {
3311
+ pending = void 0;
3312
+ } else {
3313
+ pending.depth += bracketDelta(stripped);
3314
+ pending.dangling = DANGLING_RE.test(stripped);
3315
+ if (pending.depth <= 0 && /\bdo\s*$/.test(stripped)) {
3316
+ moduleStack.push({ name: pending.name, endKeywordNeeded: true, isBlock: false, symbolIndex: pending.symbolIndex });
3317
+ pending = void 0;
3318
+ } else if (pending.depth <= 0 && DO_KEYWORD_RE.test(stripped)) {
3319
+ extendDefSpan(pending.symbolIndex, lineNum);
3320
+ trackKeywordBody(pending.symbolIndex, stripped);
3321
+ pending = void 0;
3322
+ }
3323
+ continue;
3324
+ }
3325
+ }
1835
3326
  const opensDoBlock = /\bdo\s*$/.test(stripped);
1836
3327
  const opensFnBlock = /\bfn\b/.test(stripped) && !/\bend\b/.test(stripped) && /(?:fn|->)\s*$/.test(stripped);
1837
3328
  const modM = MODULE_RE.exec(stripped);
@@ -1868,9 +3359,7 @@ function extractElixir(content, filePath) {
1868
3359
  } else {
1869
3360
  symbols.push(makeLineSymbol(filePath, fname, "function", lineNum, stripped.slice(0, 200), void 0, lines, "hash"));
1870
3361
  }
1871
- if (opensDoBlock) {
1872
- moduleStack.push({ name: fname, endKeywordNeeded: true, isBlock: false, symbolIndex: symbols.length - 1 });
1873
- }
3362
+ settleDefHead(fname, stripped);
1874
3363
  continue;
1875
3364
  }
1876
3365
  const pfm = PRIVATE_FUNC_RE.exec(stripped);
@@ -1882,9 +3371,7 @@ function extractElixir(content, filePath) {
1882
3371
  } else {
1883
3372
  symbols.push(makeLineSymbol(filePath, fname, "function", lineNum, stripped.slice(0, 200), void 0, lines, "hash"));
1884
3373
  }
1885
- if (opensDoBlock) {
1886
- moduleStack.push({ name: fname, endKeywordNeeded: true, isBlock: false, symbolIndex: symbols.length - 1 });
1887
- }
3374
+ settleDefHead(fname, stripped);
1888
3375
  continue;
1889
3376
  }
1890
3377
  if (STRUCT_RE.test(stripped)) {
@@ -1915,12 +3402,14 @@ function extractElixir(content, filePath) {
1915
3402
 
1916
3403
  // src/languages/dart.ts
1917
3404
  init_define_import_meta_env();
3405
+ var DART_STRIP = { tripleQuotes: true, singleQuoteHoles: true };
1918
3406
  var CLASS_RE4 = /^(?:(?:abstract|base|interface|final|sealed|mixin)\s+)*class\s+([A-Za-z_][A-Za-z0-9_]*)/;
1919
3407
  var ENUM_RE2 = /^enum\s+([A-Za-z_][A-Za-z0-9_]*)/;
1920
3408
  var MIXIN_RE = /^(?:base\s+)?mixin\s+([A-Za-z_][A-Za-z0-9_]*)/;
1921
3409
  var EXTENSION_RE = new RegExp("^extension\\s+(?:([A-Za-z_][A-Za-z0-9_]*)\\s*(?:" + GENERIC_CLAUSE + ")?\\s+)?on\\s+");
1922
3410
  var EXTENSION_TYPE_RE = /^extension\s+type\s+([A-Za-z_][A-Za-z0-9_]*)/;
1923
3411
  var FUNC_RE5 = new RegExp("(?:^|\\s)(?:static\\s+)?(?:(?:void|Future|Stream|async|external)\\s+|[A-Za-z_][A-Za-z0-9_<>?]*(?:\\s*\\?)?\\s+)([A-Za-z_][A-Za-z0-9_]*)\\s*(?:" + GENERIC_CLAUSE + ")?\\s*\\(");
3412
+ var OPERATOR_RE3 = /(?:^|\s)(?:(?:external|abstract)\s+)*(?:[A-Za-z_][A-Za-z0-9_<>?,]*(?:\s*\?)?\s+)?operator\s*(\[\]=|\[\]|>>>|<<|>>|<=|>=|==|~\/|[-+*/%<>&|^~])\s*\(/;
1924
3413
  var GETTER_RE = /^(?:(?:static|external|abstract|covariant)\s+)*(?:[A-Za-z_][A-Za-z0-9_<>,?\s]*(?:\s*\?)?\s+)?get\s+([A-Za-z_][A-Za-z0-9_]*)/;
1925
3414
  var NAMED_CTOR_RE = /^(?:(?:const|factory|external)\s+)*([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)\s*\(/;
1926
3415
  var UNNAMED_CTOR_RE = /^(?:(?:const|factory|external)\s+)*([A-Za-z_][A-Za-z0-9_]*)\s*\(/;
@@ -1950,11 +3439,11 @@ function extractDart(content, filePath) {
1950
3439
  const line = stripLineComment(blockStripped).trimEnd();
1951
3440
  const stripped = line.trim();
1952
3441
  if (!stripped) {
1953
- const braceLine2 = stripStringLiterals(line, { tripleQuotes: true });
3442
+ const braceLine2 = stripStringLiterals(line, DART_STRIP);
1954
3443
  braceDepth += (braceLine2.match(/\{/g) ?? []).length - (braceLine2.match(/\}/g) ?? []).length;
1955
3444
  continue;
1956
3445
  }
1957
- const structural = stripStringLiterals(stripped, { tripleQuotes: true });
3446
+ const structural = stripStringLiterals(stripped, DART_STRIP);
1958
3447
  const isIndented = line[0] === " " || line[0] === " ";
1959
3448
  const outerFrame = typeStack.length > 0 ? typeStack[typeStack.length - 1] : null;
1960
3449
  const outerDepthInType = outerFrame !== null ? braceDepth - outerFrame.startDepth : 0;
@@ -2029,6 +3518,11 @@ function extractDart(content, filePath) {
2029
3518
  if (!member && FIELD_START_RE.test(stripped)) {
2030
3519
  member = true;
2031
3520
  }
3521
+ const om = !member ? OPERATOR_RE3.exec(structural) : null;
3522
+ if (om) {
3523
+ symbols.push(makeLineSymbol(filePath, om[1] ?? "", "function", lineNum, stripped.slice(0, 200), frame.name, lines, "c"));
3524
+ member = true;
3525
+ }
2032
3526
  const gm = !member ? GETTER_RE.exec(stripped) : null;
2033
3527
  if (gm) {
2034
3528
  symbols.push(makeLineSymbol(filePath, gm[1] ?? "", "function", lineNum, stripped.slice(0, 200), frame.name, lines, "c"));
@@ -2053,7 +3547,7 @@ function extractDart(content, filePath) {
2053
3547
  symbols.push(makeLineSymbol(filePath, fname, "function", lineNum, stripped.slice(0, 200), void 0, lines, "c"));
2054
3548
  }
2055
3549
  }
2056
- const braceLine = stripStringLiterals(line, { tripleQuotes: true });
3550
+ const braceLine = stripStringLiterals(line, DART_STRIP);
2057
3551
  for (const ch of braceLine) {
2058
3552
  if (ch === "{") {
2059
3553
  braceDepth++;
@@ -2470,7 +3964,7 @@ var DOMAIN_RE = makeCreateRe("DOMAIN");
2470
3964
  var AGGREGATE_RE = makeCreateRe("AGGREGATE", OR_REPLACE);
2471
3965
  var POLICY_RE = makeCreateRe("POLICY");
2472
3966
  var RULE_RE = makeCreateRe("RULE", OR_REPLACE);
2473
- var OPERATOR_RE2 = makeCreateRe("OPERATOR(?!\\s+(?:CLASS|FAMILY)\\b)", OR_REPLACE);
3967
+ var OPERATOR_RE4 = makeCreateRe("OPERATOR(?!\\s+(?:CLASS|FAMILY)\\b)", OR_REPLACE);
2474
3968
  var SYNONYM_RE = makeCreateRe("SYNONYM", `${OR_REPLACE}(?:PUBLIC\\s+)?`);
2475
3969
  var DATABASE_LINK_RE = makeCreateRe("DATABASE\\s+LINK", "(?:PUBLIC\\s+)?");
2476
3970
  var CLUSTER_RE = makeCreateRe("CLUSTER");
@@ -2496,7 +3990,7 @@ var PATTERNS = [
2496
3990
  [AGGREGATE_RE, "sql_aggregate"],
2497
3991
  [POLICY_RE, "sql_policy"],
2498
3992
  [RULE_RE, "sql_rule"],
2499
- [OPERATOR_RE2, "sql_operator"],
3993
+ [OPERATOR_RE4, "sql_operator"],
2500
3994
  [SYNONYM_RE, "sql_synonym"],
2501
3995
  [DATABASE_LINK_RE, "sql_database_link"],
2502
3996
  [CLUSTER_RE, "sql_cluster"],
@@ -2788,6 +4282,26 @@ function plsqlStructure(noStrings, lineIndex, units, createStarts, filePath, roo
2788
4282
  }
2789
4283
  return { ends, children };
2790
4284
  }
4285
+ var BODY_KINDS = /* @__PURE__ */ new Set([
4286
+ "sql_function",
4287
+ "sql_procedure",
4288
+ "sql_trigger",
4289
+ "sql_type",
4290
+ "sql_type_body",
4291
+ "sql_package",
4292
+ "sql_package_body",
4293
+ "sql_rule"
4294
+ ]);
4295
+ var BODY_OPENER_RE = /\b(?:BEGIN|DECLARE)\b|\$\w*\$|\bRETURN\s+[\w$#.%]+(?:\s+[\w$#.%=]+|\s*\([^()]*\)){0,16}?\s+(?:IS|AS)\b(?!\s+(?:NOT|NULL|TRUE|FALSE|DISTINCT|UNKNOWN)\b)/i;
4296
+ var QUOTED_IDENTIFIER_RE = /"[^"]*"|`[^`]*`|\[[^\]]*\]/g;
4297
+ function isBodylessFunction(kind, header) {
4298
+ return kind === "sql_function" && !BODY_OPENER_RE.test(header.replace(QUOTED_IDENTIFIER_RE, " "));
4299
+ }
4300
+ function trimBlankTail(lines, start, end) {
4301
+ let e = end;
4302
+ while (e > start && (lines[e - 1] ?? "").trim() === "") e--;
4303
+ return e;
4304
+ }
2791
4305
  function extractSql(content, filePath) {
2792
4306
  const symbols = [];
2793
4307
  const sections = [];
@@ -2809,8 +4323,8 @@ function extractSql(content, filePath) {
2809
4323
  const line = offsetToLine(lineIndex, m.index ?? 0);
2810
4324
  createStarts.push(m.index ?? 0);
2811
4325
  const semiIdx = findStatementTerminator(noStrings, m.index ?? 0);
2812
- if (semiIdx !== -1 && offsetToLine(lineIndex, semiIdx) === line) {
2813
- singleLineEndLines.set(`${name}\0${kind}\0${line}`, line);
4326
+ if (semiIdx !== -1 && (offsetToLine(lineIndex, semiIdx) === line || !BODY_KINDS.has(kind) || isBodylessFunction(kind, noStrings.slice(m.index ?? 0, semiIdx)))) {
4327
+ singleLineEndLines.set(`${name}\0${kind}\0${line}`, offsetToLine(lineIndex, semiIdx));
2814
4328
  } else if (PLSQL_UNIT_KINDS.has(kind)) {
2815
4329
  units.push({ name, kind, index: m.index ?? 0, matchEnd: (m.index ?? 0) + m[0].length, line });
2816
4330
  }
@@ -2824,10 +4338,13 @@ function extractSql(content, filePath) {
2824
4338
  sections.sort((a, b) => a.line - b.line);
2825
4339
  symbols.sort((a, b) => a.lineStart - b.lineStart);
2826
4340
  assignFlatEndLines(sections, totalLines);
4341
+ const noLines = noStrings.split("\n");
2827
4342
  const pinned = propagateEndLinesToSymbols(symbols, sections).map((sym) => {
2828
4343
  const key = `${sym.name}\0${sym.kind}\0${sym.lineStart}`;
2829
- const pinnedEndLine = singleLineEndLines.get(key) ?? plsql.ends.get(key);
2830
- return pinnedEndLine !== void 0 && pinnedEndLine !== sym.lineEnd ? { ...sym, lineEnd: pinnedEndLine } : sym;
4344
+ const semiEnd = singleLineEndLines.get(key);
4345
+ const pinnedEndLine = semiEnd !== void 0 ? Math.min(semiEnd, sym.lineEnd) : plsql.ends.get(key);
4346
+ const end = pinnedEndLine ?? trimBlankTail(noLines, sym.lineStart, sym.lineEnd);
4347
+ return end !== sym.lineEnd ? { ...sym, lineEnd: end } : sym;
2831
4348
  });
2832
4349
  if (plsql.children.length === 0) return pinned;
2833
4350
  return [...pinned, ...plsql.children].sort((a, b) => a.lineStart - b.lineStart);
@@ -3055,6 +4572,103 @@ var FUNC_NAME = "[A-Za-z_][A-Za-z0-9_.+:-]*";
3055
4572
  var FUNC_KEYWORD_RE = new RegExp(`^function\\s+(${FUNC_NAME})\\s*(?:\\(\\s*\\))?`);
3056
4573
  var FUNC_POSIX_RE = new RegExp(`^(${FUNC_NAME})\\s*\\(\\s*\\)`);
3057
4574
  var VAR_RE3 = /^(?:(?:export|declare|readonly)\s+(?:-\w+\s+)*)?([A-Za-z_]\w*)=/;
4575
+ var COMPOUND_OPENERS = /* @__PURE__ */ new Set(["if", "for", "while", "until", "select", "case"]);
4576
+ var COMPOUND_CLOSERS = /* @__PURE__ */ new Set(["fi", "done", "esac"]);
4577
+ var COMPOUND_PREFIX_WORDS = /* @__PURE__ */ new Set(["then", "do", "else", "!", "time"]);
4578
+ var COMPOUND_BODY_START_RE = /^(?:if|for|while|until|select|case)\b/;
4579
+ var COMPOUND_SEGMENT_SPLIT_RE = /;|&&|\|\||\||&|\(|\{|\)|\}/;
4580
+ function cleanForScan(line) {
4581
+ return stripStringLiterals(stripBashComment(line)).trim();
4582
+ }
4583
+ function compoundDelta(text) {
4584
+ let delta = 0;
4585
+ for (const segment of text.split(COMPOUND_SEGMENT_SPLIT_RE)) {
4586
+ const words = segment.trim().split(/\s+/);
4587
+ let w = 0;
4588
+ while (w < words.length && COMPOUND_PREFIX_WORDS.has(words[w] ?? "")) w++;
4589
+ const first = words[w] ?? "";
4590
+ if (COMPOUND_OPENERS.has(first)) delta++;
4591
+ else if (COMPOUND_CLOSERS.has(first)) delta--;
4592
+ }
4593
+ return delta;
4594
+ }
4595
+ var SUBSHELL_TOKEN_RE = /;;&|;;|;&|\|\||&&|[()]|[;&|]|[^\s()&;|]+/g;
4596
+ var CASE_ARM_ENDS = /* @__PURE__ */ new Set([";;", ";&", ";;&"]);
4597
+ var COMMAND_POSITION_WORDS = /* @__PURE__ */ new Set(["then", "do", "else", "elif", "!", "time", "{"]);
4598
+ var SubshellParenScanner = class {
4599
+ depth = 0;
4600
+ // One entry per open `case`: 'subject' until `in`, 'pattern' while reading an arm's pattern, 'body' inside an arm.
4601
+ cases = [];
4602
+ commandPosition = true;
4603
+ // Feeds one cleaned line; true once the body's opening `(` has been closed.
4604
+ closes(text) {
4605
+ for (const tok of text.match(SUBSHELL_TOKEN_RE) ?? []) {
4606
+ const top = this.cases.length - 1;
4607
+ const state = this.cases[top];
4608
+ if (state === "subject") {
4609
+ if (tok === "in") this.cases[top] = "pattern";
4610
+ continue;
4611
+ }
4612
+ if (state === "pattern") {
4613
+ if (tok === "esac") {
4614
+ this.cases.pop();
4615
+ this.commandPosition = false;
4616
+ } else if (tok === ")") {
4617
+ this.cases[top] = "body";
4618
+ this.commandPosition = true;
4619
+ }
4620
+ continue;
4621
+ }
4622
+ if (state === "body" && CASE_ARM_ENDS.has(tok)) {
4623
+ this.cases[top] = "pattern";
4624
+ continue;
4625
+ }
4626
+ if (tok === "(") {
4627
+ this.depth++;
4628
+ this.commandPosition = true;
4629
+ continue;
4630
+ }
4631
+ if (tok === ")") {
4632
+ this.depth--;
4633
+ if (this.depth <= 0) return true;
4634
+ this.commandPosition = false;
4635
+ continue;
4636
+ }
4637
+ if (this.commandPosition && tok === "case") this.cases.push("subject");
4638
+ else if (this.commandPosition && tok === "esac" && state === "body") this.cases.pop();
4639
+ this.commandPosition = /^[;&|]/.test(tok) || COMMAND_POSITION_WORDS.has(tok);
4640
+ }
4641
+ this.commandPosition = true;
4642
+ return false;
4643
+ }
4644
+ };
4645
+ function findCompoundBodyEnd(lines, headerIdx, rest) {
4646
+ let startIdx = headerIdx;
4647
+ let text = rest;
4648
+ if (text === "") {
4649
+ let j = headerIdx + 1;
4650
+ while (j < lines.length && cleanForScan(lines[j] ?? "") === "") j++;
4651
+ if (j >= lines.length) return null;
4652
+ startIdx = j;
4653
+ text = cleanForScan(lines[j] ?? "");
4654
+ }
4655
+ const kind = text.startsWith("(") ? "paren" : text.startsWith("[[") ? "test" : COMPOUND_BODY_START_RE.test(text) ? "keyword" : null;
4656
+ if (kind === null) return null;
4657
+ let depth = 0;
4658
+ const parens = kind === "paren" ? new SubshellParenScanner() : null;
4659
+ for (let k = startIdx; k < lines.length; k++) {
4660
+ const cur = k === startIdx ? text : cleanForScan(lines[k] ?? "");
4661
+ if (parens !== null) {
4662
+ if (parens.closes(cur)) return k + 1;
4663
+ } else if (kind === "test") {
4664
+ if (cur.includes("]]")) return k + 1;
4665
+ } else {
4666
+ depth += compoundDelta(cur);
4667
+ if (depth <= 0) return k + 1;
4668
+ }
4669
+ }
4670
+ return null;
4671
+ }
3058
4672
  function stripBashComment(line) {
3059
4673
  for (let i = 0; i < line.length; i++) {
3060
4674
  if (line[i] !== "#") continue;
@@ -3113,6 +4727,7 @@ function extractBash(content, filePath) {
3113
4727
  let awaitingFunctionBrace = false;
3114
4728
  let openFunctionIndex = null;
3115
4729
  let openHeadingIndex = null;
4730
+ let skipUntil = 0;
3116
4731
  for (let i = 0; i < lines.length; i++) {
3117
4732
  const rawLine = lines[i] ?? "";
3118
4733
  const lineNum = i + 1;
@@ -3120,7 +4735,7 @@ function extractBash(content, filePath) {
3120
4735
  if (rawLine.trim() === heredocs[0]) heredocs.shift();
3121
4736
  continue;
3122
4737
  }
3123
- if (!inFunction && braceDepth === 0) {
4738
+ if (!inFunction && braceDepth === 0 && lineNum > skipUntil) {
3124
4739
  const banner = extractShellBannerHeading(rawLine);
3125
4740
  if (banner !== null) {
3126
4741
  if (openHeadingIndex !== null) {
@@ -3155,6 +4770,7 @@ function extractBash(content, filePath) {
3155
4770
  const opened = findHeredocOpeners(noComment, arithmeticDepth);
3156
4771
  arithmeticDepth = opened.depth;
3157
4772
  heredocs.push(...opened.terminators);
4773
+ if (lineNum <= skipUntil) continue;
3158
4774
  if (!stripped) continue;
3159
4775
  if (!inFunction && !awaitingFunctionBrace && braceDepth === 0) {
3160
4776
  const kwMatch = FUNC_KEYWORD_RE.exec(stripped);
@@ -3178,7 +4794,18 @@ function extractBash(content, filePath) {
3178
4794
  pushedIndex = symbols.length;
3179
4795
  symbols.push(makeLineSymbol(filePath, fname, "function", lineNum, stripped.slice(0, 200), void 0, lines, "hash"));
3180
4796
  }
3181
- if (fname) {
4797
+ const rest = stripped.slice(funcMatch[0].length).trim();
4798
+ const compoundEnd = fname && !rest.startsWith("{") ? findCompoundBodyEnd(lines, i, rest) : null;
4799
+ if (compoundEnd !== null) {
4800
+ if (pushedIndex !== null) {
4801
+ const open = symbols[pushedIndex];
4802
+ if (open !== void 0 && compoundEnd > lineNum) {
4803
+ symbols[pushedIndex] = { ...open, lineEnd: compoundEnd, body: lines.slice(lineNum - 1, compoundEnd).join("\n") };
4804
+ }
4805
+ }
4806
+ skipUntil = compoundEnd;
4807
+ continue;
4808
+ } else if (fname) {
3182
4809
  if (stripped.includes("{")) {
3183
4810
  const braceLine2 = stripStringLiterals(stripped);
3184
4811
  const openCount = (braceLine2.match(/\{/g) ?? []).length;
@@ -3292,7 +4919,7 @@ function maskContinuationAndDefines(text) {
3292
4919
  }
3293
4920
  return { noContinuation: contLines.join("\n"), forTargets: targetLines.join("\n") };
3294
4921
  }
3295
- var TARGET_RE = /^((?:[^\t\n#:=]|:(?=[\\/])|\\#)(?:[^:\n#=]|:(?=[\\/])|\\#)*):{1,2}(?![:=])\s*(?:[^=\n]|$)/gm;
4922
+ var TARGET_RE = /^((?:[^\t\n#:=]|:(?=[\\/])|\\#)(?:[^:\n#=]|:(?=[\\/])|\\#)*):{1,2}(?![:=])(?![ \t]*(?:(?:override|export|private)[ \t]+)*[^\s:=#]+[ \t]*(?:[?+!]|:{0,3})=)\s*(?:[^=\n]|$)/gm;
3296
4923
  var DEFINE_RE2 = /^ *(?:(?:override|export|private)\s+)*define\s+([\w./%$()-]+)/gm;
3297
4924
  var SPECIAL_TARGETS = /* @__PURE__ */ new Set([
3298
4925
  ".PHONY",
@@ -4028,12 +5655,12 @@ function extractApex(content, filePath) {
4028
5655
  }
4029
5656
  const typeNamesLower = /* @__PURE__ */ new Set();
4030
5657
  for (const match of code.matchAll(TYPE_DECL_RE)) {
4031
- const typeKind = match[1] ?? "";
5658
+ const typeKind2 = match[1] ?? "";
4032
5659
  const name = match[2] ?? "";
4033
5660
  const startOffset = match.index ?? 0;
4034
5661
  const line = offsetToLine(lineIndex, startOffset);
4035
5662
  const bodyStartLine = annotationStartLine(codeLines, line);
4036
- const typeKindLower = typeKind.toLowerCase();
5663
+ const typeKindLower = typeKind2.toLowerCase();
4037
5664
  const kind = typeKindLower === "class" ? "apex_class" : `apex_${typeKindLower}`;
4038
5665
  typeNamesLower.add(name.toLowerCase());
4039
5666
  emit2(name, kind, spanForMatch(content, code, lineIndex, startOffset, bodyStartLine, match[0]));
@@ -4090,36 +5717,52 @@ var FLOW_TAG_KIND = {
4090
5717
  variables: "sf_flow_variable"
4091
5718
  };
4092
5719
  function xmlText(content, tag) {
4093
- const re = new RegExp(
4094
- `<(?:[A-Za-z_][\\w.-]*:)?${tag}(?:\\s[^>]*)?>([\\s\\S]*?)</(?:[A-Za-z_][\\w.-]*:)?${tag}\\s*>`,
4095
- "i"
4096
- );
4097
- const match = re.exec(content);
4098
- if (match?.[1] === void 0) return null;
4099
- 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);
4100
5729
  }
4101
5730
  function directChildText(content, tag) {
4102
- const candidateRe = new RegExp(
4103
- `<(?:[A-Za-z_][\\w.-]*:)?${tag}(?:\\s[^>]*)?>([\\s\\S]*?)</(?:[A-Za-z_][\\w.-]*:)?${tag}\\s*>`,
4104
- "gi"
4105
- );
4106
- const tagRe = /<(\/?)([A-Za-z_:][\w.:-]*)\b[^>]*?(\/?)>/g;
4107
- for (const cand of content.matchAll(candidateRe)) {
4108
- const idx = cand.index ?? 0;
4109
- let depth = 0;
4110
- tagRe.lastIndex = 0;
4111
- let t;
4112
- while ((t = tagRe.exec(content)) !== null) {
4113
- if (t.index >= idx) break;
4114
- const closing = t[1] === "/";
4115
- const selfClosing = t[3] === "/";
4116
- if (selfClosing) continue;
4117
- depth += closing ? -1 : 1;
4118
- }
4119
- 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());
4120
5737
  }
4121
5738
  return null;
4122
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
+ }
4123
5766
  function decodeXml(value) {
4124
5767
  return value.replace(/&apos;/g, "'").replace(/&quot;/g, '"').replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&amp;/g, "&");
4125
5768
  }
@@ -4139,8 +5782,7 @@ function wholeFileSpan(content) {
4139
5782
  return {
4140
5783
  startLine: 1,
4141
5784
  endLine: lines.length > 1 && lines[lines.length - 1] === "" ? lines.length - 1 : lines.length,
4142
- // File-level metadata symbols can be several megabytes (profiles are a common case).
4143
- // 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.
4144
5786
  body: ""
4145
5787
  };
4146
5788
  }
@@ -4154,11 +5796,13 @@ function spanFromOffsets(content, lineIndex, startOffset, endOffset) {
4154
5796
  };
4155
5797
  }
4156
5798
  function rootElement(content) {
4157
- 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);
4158
5800
  if (match === null) return null;
4159
5801
  const root = match[1];
4160
5802
  if (root === void 0) return null;
4161
- 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;
4162
5806
  const close = new RegExp(`</(?:[A-Za-z_][\\w.-]*:)?${escapeRegExp(root)}\\s*>`, "i");
4163
5807
  return close.test(content) ? root : null;
4164
5808
  }
@@ -4176,14 +5820,10 @@ function metadataArtifactName(filePath) {
4176
5820
  return match?.[1] ?? basenameWithout(filePath, "-meta.xml");
4177
5821
  }
4178
5822
  function elementBlocks(content, tag) {
4179
- const re = new RegExp(
4180
- `<(?:[A-Za-z_][\\w.-]*:)?${tag}(?:\\s[^>]*)?>([\\s\\S]*?)</(?:[A-Za-z_][\\w.-]*:)?${tag}\\s*>`,
4181
- "gi"
4182
- );
4183
- return [...content.matchAll(re)].map((match) => ({
4184
- inner: match[1] ?? "",
4185
- offset: match.index ?? 0,
4186
- 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)
4187
5827
  }));
4188
5828
  }
4189
5829
  function attributeValue(attributes, name) {
@@ -4191,11 +5831,33 @@ function attributeValue(attributes, name) {
4191
5831
  return match?.[2] === void 0 ? null : decodeXml(match[2]);
4192
5832
  }
4193
5833
  function propertyElements(content) {
4194
- 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);
4195
5837
  const out = [];
4196
- for (const match of content.matchAll(re)) {
4197
- const name = attributeValue(match[1] ?? "", "name");
4198
- 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;
4199
5861
  }
4200
5862
  return out;
4201
5863
  }
@@ -4227,15 +5889,35 @@ function metadataName(filePath, content, suffix) {
4227
5889
  function addFlowElements(symbols, seen, content, filePath, flowName) {
4228
5890
  const lineIndex = buildLineIndex(content);
4229
5891
  const tagAlternation = Object.keys(FLOW_TAG_KIND).join("|");
4230
- const re = new RegExp(`<(?:[A-Za-z_][\\w.-]*:)?(${tagAlternation})(?:\\s[^>]*)?>\\s*([\\s\\S]*?)\\s*</(?:[A-Za-z_][\\w.-]*:)?\\1\\s*>`, "g");
4231
- 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) {
4232
5898
  if (symbols.length >= MAX_SYMBOLS11) return;
4233
- const tag = match[1] ?? "";
4234
- 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();
4235
5919
  const name = directChildText(inner, "name");
4236
5920
  if (name === null || name === "") continue;
4237
- const startOffset = match.index ?? 0;
4238
- const endOffset = startOffset + match[0].length;
4239
5921
  const span = spanFromOffsets(content, lineIndex, startOffset, endOffset);
4240
5922
  const kind = FLOW_TAG_KIND[tag] ?? "sf_flow_element";
4241
5923
  emit(symbols, seen, makeSpanSymbol(filePath, name, kind, span, flowName));
@@ -4446,11 +6128,33 @@ function blankJsStringLiterals(content) {
4446
6128
  }
4447
6129
  var FUNC_DECL_RE = /^(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s*\*?\s+([A-Za-z_$][\w$]*)/;
4448
6130
  var CONST_DECL_RE = /^(?:export\s+)?const\s+([A-Za-z_$][\w$]*)\s*[:=]/;
4449
- 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*\()/;
6134
+ function declarationEndIdx(blanked, startIdx) {
6135
+ let depth = 0;
6136
+ for (let j = startIdx; j < blanked.length; j++) {
6137
+ const line = blanked[j] ?? "";
6138
+ for (const ch of line) {
6139
+ if (ch === "(" || ch === "[" || ch === "{") depth++;
6140
+ else if (ch === ")" || ch === "]" || ch === "}") depth--;
6141
+ }
6142
+ if (depth > 0) continue;
6143
+ let k = j + 1;
6144
+ while (k < blanked.length && (blanked[k] ?? "").trim() === "") k++;
6145
+ if (j === startIdx && (blanked[k] ?? "").trimStart().startsWith("{")) {
6146
+ j = k - 1;
6147
+ continue;
6148
+ }
6149
+ return j;
6150
+ }
6151
+ return startIdx;
6152
+ }
4450
6153
  function extractTopLevelDeclarations(scriptContent, filePath, startLine) {
4451
6154
  const symbols = [];
4452
6155
  const commentFree = stripJsComments(scriptContent);
4453
6156
  const lines = blankJsStringLiterals(commentFree).split("\n");
6157
+ const rawLines = scriptContent.split("\n");
4454
6158
  let depth = 0;
4455
6159
  for (let i = 0; i < lines.length; i++) {
4456
6160
  const rawLine = lines[i] ?? "";
@@ -4458,16 +6162,16 @@ function extractTopLevelDeclarations(scriptContent, filePath, startLine) {
4458
6162
  if (depth === 0 && trimmed) {
4459
6163
  const line = startLine + i;
4460
6164
  const fm = FUNC_DECL_RE.exec(trimmed);
4461
- if (fm?.[1]) {
4462
- symbols.push(makeLineSymbol(filePath, fm[1], "sfc_script_function", line));
4463
- } else {
4464
- const cm = CONST_DECL_RE.exec(trimmed);
4465
- if (cm?.[1]) {
4466
- symbols.push(makeLineSymbol(filePath, cm[1], "sfc_script_const", line));
4467
- } else {
4468
- const clm = CLASS_DECL_RE.exec(trimmed);
4469
- if (clm?.[1]) symbols.push(makeLineSymbol(filePath, clm[1], "sfc_script_class", line));
4470
- }
6165
+ const cm = fm ? null : CONST_DECL_RE.exec(trimmed);
6166
+ const clm = fm || cm ? null : CLASS_DECL_RE.exec(trimmed);
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);
6170
+ if (name) {
6171
+ const kind = fm || am && am[1] === void 0 ? "sfc_script_function" : cm || dm ? "sfc_script_const" : "sfc_script_class";
6172
+ const sym = makeLineSymbol(filePath, name, kind, line);
6173
+ const endIdx = declarationEndIdx(lines, i);
6174
+ symbols.push(endIdx > i ? { ...sym, lineEnd: startLine + endIdx, body: rawLines.slice(i, endIdx + 1).join("\n") } : sym);
4471
6175
  }
4472
6176
  }
4473
6177
  depth += (rawLine.match(/\{/g) ?? []).length - (rawLine.match(/\}/g) ?? []).length;
@@ -4495,19 +6199,14 @@ function extractComponentRefs(markup, filePath, startLine, allowKebab) {
4495
6199
  }
4496
6200
  function extractTagBlocks(content, lineIndex, tag) {
4497
6201
  const masked = blankJsStringLiterals(content);
4498
- const re = new RegExp(`<${tag}\\b([^>]*)>([\\s\\S]*?)<\\/${tag}\\s*>`, "gi");
4499
6202
  const blocks = [];
4500
- for (const m of masked.matchAll(re)) {
4501
- const matchStart = m.index ?? 0;
4502
- const attrs = m[1] ?? "";
4503
- const innerLen = (m[2] ?? "").length;
4504
- const openTagLen = 1 + tag.length + attrs.length + 1;
4505
- 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;
4506
6205
  blocks.push({
4507
- content: content.slice(innerStart, innerStart + innerLen),
6206
+ content: content.slice(innerStart, el.bodyEnd),
4508
6207
  contentStartLine: offsetToLine(lineIndex, innerStart),
4509
- matchStart,
4510
- matchEnd: matchStart + m[0].length
6208
+ matchStart: el.start,
6209
+ matchEnd: el.end
4511
6210
  });
4512
6211
  }
4513
6212
  return blocks;
@@ -5401,6 +7100,16 @@ function readToken4(masked, i) {
5401
7100
  if (p === start) return void 0;
5402
7101
  return { word: masked.slice(start, p), start, end: p };
5403
7102
  }
7103
+ function readNameToken(masked, i) {
7104
+ let p = i;
7105
+ for (; ; ) {
7106
+ while (isSpace4(masked[p])) p++;
7107
+ if (masked[p] === "#" && masked[p + 1] === "^") p++;
7108
+ if (masked[p] !== "^") break;
7109
+ p = datumEnd2(masked, p + 1);
7110
+ }
7111
+ return readToken4(masked, p);
7112
+ }
5404
7113
  function extractClojure(content, filePath) {
5405
7114
  if (content.includes("\0")) return { symbols: [], imports: [] };
5406
7115
  const rawLines = content.split(/\r?\n/);
@@ -5421,7 +7130,7 @@ function extractClojure(content, filePath) {
5421
7130
  if (tok !== void 0) {
5422
7131
  const kind = DEFINERS4.get(tok.word.toLowerCase());
5423
7132
  if (kind !== void 0) {
5424
- const nameTok = readToken4(masked, tok.end);
7133
+ const nameTok = readNameToken(masked, tok.end);
5425
7134
  const name = nameTok?.word.replace(/^:+/, "") ?? "";
5426
7135
  const idx = spans.open(name, kind, lineOf(i), owner());
5427
7136
  stack.push({ index: idx, depth });
@@ -5728,7 +7437,7 @@ function afterContext(rest) {
5728
7437
  const arrow = rest.indexOf("=>");
5729
7438
  return (arrow >= 0 ? rest.slice(arrow + 2) : rest).trimStart();
5730
7439
  }
5731
- function classify(line) {
7440
+ function classify(line, continued = false) {
5732
7441
  let m;
5733
7442
  if (m = /^module\s+([A-Za-z_][A-Za-z0-9_.']*)/.exec(line)) return [{ kind: "module", name: m[1] }];
5734
7443
  if (m = /^(?:data|newtype)\s+(?:instance\s+)?([A-Z][A-Za-z0-9_']*)/.exec(line)) return [{ kind: "type", name: m[1] }];
@@ -5748,11 +7457,11 @@ function classify(line) {
5748
7457
  if (m = /^\(([^()]+)\)\s*::/.exec(line)) return [{ kind: "function", name: m[1].trim() }];
5749
7458
  if (m = /^([a-z_][A-Za-z0-9_']*)\b/.exec(line)) {
5750
7459
  const name = m[1];
5751
- if (!RESERVED_TOP.has(name) && hasTopLevelEquals(line)) return [{ kind: "function", name }];
7460
+ if (!RESERVED_TOP.has(name) && (continued || hasTopLevelEquals(line))) return [{ kind: "function", name }];
5752
7461
  return void 0;
5753
7462
  }
5754
7463
  if (m = /^\(([^()]+)\)/.exec(line)) {
5755
- if (hasTopLevelEquals(line)) return [{ kind: "function", name: m[1].trim() }];
7464
+ if (continued || hasTopLevelEquals(line)) return [{ kind: "function", name: m[1].trim() }];
5756
7465
  }
5757
7466
  return void 0;
5758
7467
  }
@@ -5761,7 +7470,15 @@ function extractHaskell(content, filePath) {
5761
7470
  const rawLines = content.split(/\r?\n/);
5762
7471
  const masked = maskHaskell(content);
5763
7472
  const maskedLines = masked.split(/\r?\n/);
5764
- const n = rawLines.length;
7473
+ const n = rawLines.length > 1 && rawLines[rawLines.length - 1] === "" ? rawLines.length - 1 : rawLines.length;
7474
+ const headContinues = (idx) => {
7475
+ for (let j = idx + 1; j < n; j++) {
7476
+ if ((maskedLines[j] ?? "").trim() === "") continue;
7477
+ if (!/^\s/.test(rawLines[j] ?? "")) return false;
7478
+ return /^(?:\|(?!\|)|=(?![=>])|::)/.test((maskedLines[j] ?? "").trim());
7479
+ }
7480
+ return false;
7481
+ };
5765
7482
  const boundaries = [];
5766
7483
  for (let idx = 0; idx < n; idx++) {
5767
7484
  const raw = rawLines[idx] ?? "";
@@ -5769,7 +7486,7 @@ function extractHaskell(content, filePath) {
5769
7486
  const maskedLine = maskedLines[idx] ?? "";
5770
7487
  const trimmed = maskedLine.trim();
5771
7488
  if (trimmed === "") continue;
5772
- const defs = classify(trimmed);
7489
+ const defs = classify(trimmed) ?? classify(trimmed, headContinues(idx));
5773
7490
  if (defs === void 0) {
5774
7491
  boundaries.push({ num: idx + 1, consumed: false });
5775
7492
  continue;
@@ -5786,6 +7503,17 @@ function extractHaskell(content, filePath) {
5786
7503
  boundaries[endIdx + 1].consumed = true;
5787
7504
  endIdx++;
5788
7505
  }
7506
+ if (boundaries.some((o, k) => k !== i && o.num === b.num && o.def?.kind === "function")) {
7507
+ let k = endIdx + 1;
7508
+ while (k < boundaries.length && boundaries[k].def?.kind === "function" && boundaries[k].def?.name !== b.def.name) k++;
7509
+ if (k < boundaries.length && boundaries[k].def?.kind === "function" && !boundaries[k].consumed) {
7510
+ while (k < boundaries.length && boundaries[k].def?.kind === "function" && boundaries[k].def?.name === b.def.name) {
7511
+ boundaries[k].consumed = true;
7512
+ endIdx = k;
7513
+ k++;
7514
+ }
7515
+ }
7516
+ }
5789
7517
  }
5790
7518
  const next = boundaries[endIdx + 1];
5791
7519
  const lineEnd = Math.max(b.num, next !== void 0 ? next.num - 1 : n);
@@ -5935,7 +7663,7 @@ function extractOcaml(content, filePath) {
5935
7663
  const rawLines = content.split(/\r?\n/);
5936
7664
  const masked = maskOcaml(content);
5937
7665
  const maskedLines = masked.split(/\r?\n/);
5938
- const n = rawLines.length;
7666
+ const n = rawLines.length > 1 && rawLines[rawLines.length - 1] === "" ? rawLines.length - 1 : rawLines.length;
5939
7667
  const boundaries = [];
5940
7668
  for (let idx = 0; idx < n; idx++) {
5941
7669
  const raw = rawLines[idx] ?? "";
@@ -5943,6 +7671,7 @@ function extractOcaml(content, filePath) {
5943
7671
  const maskedLine = maskedLines[idx] ?? "";
5944
7672
  const trimmed = maskedLine.trim();
5945
7673
  if (trimmed === "") continue;
7674
+ if (/^end\b/.test(trimmed)) continue;
5946
7675
  const def = classify2(trimmed);
5947
7676
  boundaries.push(def === void 0 ? { num: idx + 1 } : { num: idx + 1, def });
5948
7677
  }
@@ -6296,12 +8025,17 @@ function sectionsToHeadingSymbols(sections, filePath) {
6296
8025
  parent: ""
6297
8026
  }));
6298
8027
  }
8028
+ var CSHARP_SPAN_OPTS = { lineComment: "//", stringEscapes: "csharp", rawStringQuotes: true, expressionBodies: true, interpolation: "csharp" };
6299
8029
  var ADAPTER_EXTRACTORS = {
6300
- csharp: (content, filePath) => assignBraceBlockSpans(extractCsharp(content, filePath).symbols, content, { lineComment: "//", stringEscapes: "csharp", rawStringQuotes: true }),
8030
+ csharp: (content, filePath) => {
8031
+ const { symbols, settled } = extractCsharp(content, filePath);
8032
+ return spanUnsettled(symbols, settled, (rest) => assignBraceBlockSpans(rest, content, CSHARP_SPAN_OPTS));
8033
+ },
6301
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.
6302
8035
  php: (content, filePath) => {
6303
8036
  const code = maskPhpInlineHtml(content);
6304
- 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" }));
6305
8039
  },
6306
8040
  html: (content, filePath) => {
6307
8041
  const r = extractHtml(content, filePath);
@@ -6311,9 +8045,7 @@ var ADAPTER_EXTRACTORS = {
6311
8045
  const r = extractLiquid(content, filePath);
6312
8046
  return [...r.symbols, ...sectionsToHeadingSymbols(r.sections, filePath)];
6313
8047
  },
6314
- // The six template dialects mask their own delimiters out and hand off to extractHtml, so they
6315
- // compose the same way html/liquid do above -- see templates_idx.ts's module doc for why this
6316
- // 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.
6317
8049
  jinja2: (content, filePath) => {
6318
8050
  const r = extractJinja2(content, filePath);
6319
8051
  return [...r.symbols, ...sectionsToHeadingSymbols(r.sections, filePath)];
@@ -6338,13 +8070,22 @@ var ADAPTER_EXTRACTORS = {
6338
8070
  const r = extractTwig(content, filePath);
6339
8071
  return [...r.symbols, ...sectionsToHeadingSymbols(r.sections, filePath)];
6340
8072
  },
6341
- kotlin: (content, filePath) => assignBraceBlockSpans(extractKotlin(content, filePath).symbols, content, { lineComment: "//", nestedBlockComments: true, tripleQuote: true, tripleQuoteRunClose: "last" }),
6342
- swift: (content, filePath) => assignBraceBlockSpans(extractSwift(content, filePath).symbols, content, { lineComment: "//", nestedBlockComments: true, tripleQuote: true, tripleQuoteRunClose: "last", multilineLang: "swift" }),
6343
- scala: (content, filePath) => assignBraceBlockSpans(extractScala(content, filePath).symbols, content, { lineComment: "//", nestedBlockComments: true, tripleQuote: true, tripleQuoteRunClose: "last" }),
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
+ },
6344
8085
  lua: (content, filePath) => extractLua(content, filePath).symbols,
6345
8086
  vb: (content, filePath) => extractVb(content, filePath).symbols,
6346
8087
  elixir: (content, filePath) => extractElixir(content, filePath).symbols,
6347
- dart: (content, filePath) => assignBraceBlockSpans(extractDart(content, filePath).symbols, content, { lineComment: "//", nestedBlockComments: true, tripleQuote: true, tripleSingleQuote: true, tripleQuoteRunClose: "first" }),
8088
+ dart: (content, filePath) => assignBraceBlockSpans(extractDart(content, filePath).symbols, content, { lineComment: "//", nestedBlockComments: true, tripleQuote: true, tripleSingleQuote: true, tripleQuoteRunClose: "first", interpolation: "dart" }),
6348
8089
  zig: (content, filePath) => assignBraceBlockSpans(extractZig(content, filePath).symbols, content, { lineComment: "//", blockComment: null, lineStringPrefix: "\\\\" }),
6349
8090
  r: (content, filePath) => extractR(content, filePath).symbols,
6350
8091
  graphql: (content, filePath) => extractGraphql(content, filePath).symbols,
@@ -6396,10 +8137,14 @@ var ADAPTER_EXTRACTORS = {
6396
8137
  };
6397
8138
  export {
6398
8139
  ADAPTER_EXTRACTORS,
8140
+ CSHARP_SPAN_OPTS,
8141
+ assignBraceBlockSpans,
6399
8142
  extractAstro,
6400
8143
  extractCobol,
8144
+ extractCsharp,
6401
8145
  extractNatural,
6402
8146
  extractSalesforceMetadata,
6403
8147
  extractSvelte,
6404
- extractVue
8148
+ extractVue,
8149
+ spanUnsettled
6405
8150
  };