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.
- package/README.md +53 -42
- package/SECURITY.md +37 -11
- package/THIRD_PARTY_NOTICES.md +41 -4
- package/dist/native/linux-arm64/tg-hook +0 -0
- package/dist/native/linux-x64/tg-hook +0 -0
- package/dist/native/win32-arm64/tg-hook.exe +0 -0
- package/dist/native/win32-x64/tg-hook.exe +0 -0
- package/dist/ort-wasm-simd-threaded.mjs +59 -0
- package/dist/{token-goat-chunk-SE6E4BKJ.mjs → token-goat-chunk-25TRAWET.mjs} +23 -6
- package/dist/token-goat-chunk-2KXO6V2B.mjs +203 -0
- package/dist/{token-goat-chunk-UXSXQQIY.mjs → token-goat-chunk-2M7E4PF7.mjs} +43 -14
- package/dist/token-goat-chunk-2UPZGKKY.mjs +188 -0
- package/dist/token-goat-chunk-2WLPWKHV.mjs +135 -0
- package/dist/token-goat-chunk-2XBMMDBD.mjs +126 -0
- package/dist/token-goat-chunk-32ZOY4N5.mjs +23 -0
- package/dist/token-goat-chunk-3EZRNKTK.mjs +188 -0
- package/dist/token-goat-chunk-4ADZHI7J.mjs +63 -0
- package/dist/token-goat-chunk-4GBVPH3D.mjs +242 -0
- package/dist/{token-goat-chunk-2WOUYWLM.mjs → token-goat-chunk-4GILLLWY.mjs} +34 -7
- package/dist/token-goat-chunk-4NAPX7BA.mjs +90 -0
- package/dist/{token-goat-chunk-NMBWLRHW.mjs → token-goat-chunk-4SC7UJYV.mjs} +9981 -11563
- package/dist/token-goat-chunk-4SMRO4TO.mjs +366 -0
- package/dist/{token-goat-chunk-O6I2XU4P.mjs → token-goat-chunk-4ZBFWLXF.mjs} +310 -441
- package/dist/token-goat-chunk-57BIAXJL.mjs +286 -0
- package/dist/token-goat-chunk-5AC66HNP.mjs +115 -0
- package/dist/token-goat-chunk-5IMLKSOP.mjs +145 -0
- package/dist/token-goat-chunk-5RG5SBL6.mjs +221 -0
- package/dist/{token-goat-chunk-RRNZMM3A.mjs → token-goat-chunk-5Y6ZYL6U.mjs} +21 -2
- package/dist/token-goat-chunk-646E6U44.mjs +398 -0
- package/dist/token-goat-chunk-65N4RHP4.mjs +33 -0
- package/dist/{token-goat-chunk-6AK46ZT7.mjs → token-goat-chunk-6DG6HWP3.mjs} +13 -3
- package/dist/token-goat-chunk-6ENQSNRZ.mjs +573 -0
- package/dist/token-goat-chunk-6ZY4GNF2.mjs +91 -0
- package/dist/{token-goat-chunk-E5TK5DNO.mjs → token-goat-chunk-76FGDLRO.mjs} +574 -340
- package/dist/{token-goat-chunk-TGOXNAHW.mjs → token-goat-chunk-7EZTZOMC.mjs} +780 -767
- package/dist/token-goat-chunk-7MAOA6X4.mjs +3647 -0
- package/dist/token-goat-chunk-7R2ZVVAX.mjs +218 -0
- package/dist/{token-goat-chunk-TCQANXYC.mjs → token-goat-chunk-AM5V6GSX.mjs} +18 -2
- package/dist/token-goat-chunk-AUNGYYQX.mjs +184 -0
- package/dist/token-goat-chunk-AUQYRMMH.mjs +2985 -0
- package/dist/token-goat-chunk-B3PEKBYG.mjs +128 -0
- package/dist/{token-goat-chunk-KOPIR3KZ.mjs → token-goat-chunk-BA4HI6BW.mjs} +1910 -165
- package/dist/{token-goat-chunk-52NSDWYY.mjs → token-goat-chunk-BFCWY73P.mjs} +58 -20
- package/dist/token-goat-chunk-BPGCUMR7.mjs +30 -0
- package/dist/token-goat-chunk-BWGFUZZE.mjs +25 -0
- package/dist/token-goat-chunk-C75NA7PL.mjs +322 -0
- package/dist/token-goat-chunk-CBIQ7WTD.mjs +87 -0
- package/dist/token-goat-chunk-CETM74KC.mjs +307 -0
- package/dist/token-goat-chunk-CIMQ2BB3.mjs +233 -0
- package/dist/{token-goat-chunk-DNSPXQXQ.mjs → token-goat-chunk-CJLS3CDL.mjs} +70 -18
- package/dist/{token-goat-chunk-MELOKFDJ.mjs → token-goat-chunk-CO3UYX6G.mjs} +7 -1
- package/dist/token-goat-chunk-COPNXRJM.mjs +154 -0
- package/dist/token-goat-chunk-CSJ5L3NL.mjs +479 -0
- package/dist/token-goat-chunk-CVCEVUGK.mjs +315 -0
- package/dist/token-goat-chunk-CXHOFN7R.mjs +371 -0
- package/dist/token-goat-chunk-D735C4QM.mjs +603 -0
- package/dist/{token-goat-chunk-E4ZOJIZK.mjs → token-goat-chunk-DGS2LVNA.mjs} +70 -160
- package/dist/{token-goat-chunk-L7H3U27L.mjs → token-goat-chunk-DOWRSMWO.mjs} +1 -1
- package/dist/token-goat-chunk-E45INMY3.mjs +71 -0
- package/dist/token-goat-chunk-EC5F37F4.mjs +244 -0
- package/dist/{token-goat-chunk-XTQAOTSO.mjs → token-goat-chunk-EDBDRVH5.mjs} +4 -1
- package/dist/token-goat-chunk-EELTBKDM.mjs +613 -0
- package/dist/token-goat-chunk-EVMZJ27Z.mjs +147 -0
- package/dist/token-goat-chunk-EXKGNHEG.mjs +2096 -0
- package/dist/{token-goat-chunk-YOOVFPTP.mjs → token-goat-chunk-F4HYL64R.mjs} +12 -2
- package/dist/token-goat-chunk-F6PAUIEK.mjs +624 -0
- package/dist/token-goat-chunk-FDSREWLX.mjs +692 -0
- package/dist/{token-goat-chunk-NMTKNYGF.mjs → token-goat-chunk-FNFBKLRD.mjs} +74 -9
- package/dist/token-goat-chunk-G5PJ7AGM.mjs +36 -0
- package/dist/token-goat-chunk-GGGG7RWB.mjs +236 -0
- package/dist/{token-goat-chunk-TDUT2CL6.mjs → token-goat-chunk-GL3ETKSC.mjs} +276 -19
- package/dist/{token-goat-chunk-7CPMDFGB.mjs → token-goat-chunk-GVB2MUST.mjs} +265 -1567
- package/dist/token-goat-chunk-GWFLAUMQ.mjs +307 -0
- package/dist/token-goat-chunk-HAVAOB3S.mjs +87 -0
- package/dist/token-goat-chunk-HLPW63A7.mjs +48 -0
- package/dist/token-goat-chunk-HU4TORC5.mjs +1377 -0
- package/dist/token-goat-chunk-I7VKZZAW.mjs +35 -0
- package/dist/token-goat-chunk-IA6XSPE3.mjs +218 -0
- package/dist/token-goat-chunk-IAGXMHIK.mjs +863 -0
- package/dist/{token-goat-chunk-435UQTKD.mjs → token-goat-chunk-IK2DRMFX.mjs} +129 -74
- package/dist/{token-goat-chunk-ZER6EAXZ.mjs → token-goat-chunk-INNPTRUX.mjs} +2954 -2783
- package/dist/token-goat-chunk-JJ5BX4F4.mjs +129 -0
- package/dist/token-goat-chunk-JVFSHVFJ.mjs +129 -0
- package/dist/token-goat-chunk-KGEFFSHD.mjs +50 -0
- package/dist/token-goat-chunk-KKUFXAPD.mjs +25 -0
- package/dist/token-goat-chunk-KQBLRPBN.mjs +433 -0
- package/dist/token-goat-chunk-LCNQ2CNN.mjs +497 -0
- package/dist/token-goat-chunk-M3LFJDPU.mjs +58 -0
- package/dist/token-goat-chunk-M52KPT3C.mjs +87 -0
- package/dist/token-goat-chunk-MBEG42H7.mjs +150 -0
- package/dist/{token-goat-chunk-EVC4TOLE.mjs → token-goat-chunk-METECDOH.mjs} +3 -12
- package/dist/{token-goat-chunk-2AWQ2R5X.mjs → token-goat-chunk-MHX7XCC3.mjs} +3 -2
- package/dist/token-goat-chunk-MNWKPRAL.mjs +13 -0
- package/dist/token-goat-chunk-N5LSOVSU.mjs +137 -0
- package/dist/{token-goat-chunk-DPNLUJWB.mjs → token-goat-chunk-N5MMR2IW.mjs} +30 -8
- package/dist/token-goat-chunk-N7B3JQ2C.mjs +160 -0
- package/dist/{token-goat-chunk-VMFWNHGR.mjs → token-goat-chunk-NISNMD7T.mjs} +2545 -2953
- package/dist/token-goat-chunk-NMD42SFQ.mjs +434 -0
- package/dist/token-goat-chunk-NOSS5VWY.mjs +174 -0
- package/dist/token-goat-chunk-NSNSPPBG.mjs +69 -0
- package/dist/token-goat-chunk-OBOFIHKN.mjs +38 -0
- package/dist/token-goat-chunk-OBRFJ5O5.mjs +76 -0
- package/dist/token-goat-chunk-ODBT2USM.mjs +800 -0
- package/dist/token-goat-chunk-OS5EM5PP.mjs +107 -0
- package/dist/token-goat-chunk-OUKDTVNU.mjs +1178 -0
- package/dist/token-goat-chunk-OXFMP75N.mjs +566 -0
- package/dist/{token-goat-chunk-ASLWOQ3I.mjs → token-goat-chunk-OYIYKDDT.mjs} +2 -1
- package/dist/{token-goat-chunk-67BNIKKO.mjs → token-goat-chunk-P6HQSWQ3.mjs} +55 -47
- package/dist/token-goat-chunk-P6VGNTQT.mjs +71 -0
- package/dist/token-goat-chunk-PFWIMH2E.mjs +261 -0
- package/dist/token-goat-chunk-PJZXIS3G.mjs +39 -0
- package/dist/token-goat-chunk-PUO5INXP.mjs +606 -0
- package/dist/token-goat-chunk-PX5PQWTY.mjs +462 -0
- package/dist/token-goat-chunk-Q5QDBC6O.mjs +111 -0
- package/dist/token-goat-chunk-QFNQXSDT.mjs +40 -0
- package/dist/token-goat-chunk-QH7YVYOY.mjs +3957 -0
- package/dist/token-goat-chunk-QLMUHEPB.mjs +43 -0
- package/dist/{token-goat-chunk-PYSUADX4.mjs → token-goat-chunk-QQOJIHL3.mjs} +50 -14
- package/dist/token-goat-chunk-QQTWJY2O.mjs +85 -0
- package/dist/token-goat-chunk-QYHO5CPH.mjs +93 -0
- package/dist/token-goat-chunk-RELAVWAD.mjs +27 -0
- package/dist/token-goat-chunk-RSLPOBKQ.mjs +339 -0
- package/dist/token-goat-chunk-SAMFDIS2.mjs +712 -0
- package/dist/token-goat-chunk-SDELXLDM.mjs +48 -0
- package/dist/{token-goat-chunk-PGTH2U4C.mjs → token-goat-chunk-SOAFZNNZ.mjs} +164 -40
- package/dist/{token-goat-chunk-G23DWHV4.mjs → token-goat-chunk-SRTHT7KV.mjs} +33 -15
- package/dist/token-goat-chunk-T5P5ACNQ.mjs +212 -0
- package/dist/token-goat-chunk-T5YGG4V3.mjs +45 -0
- package/dist/token-goat-chunk-TAUZ4OFS.mjs +110 -0
- package/dist/token-goat-chunk-TM6MC754.mjs +40 -0
- package/dist/token-goat-chunk-TWUKBOMP.mjs +72 -0
- package/dist/token-goat-chunk-U2KSB4SG.mjs +56 -0
- package/dist/token-goat-chunk-U4WHMG6Y.mjs +898 -0
- package/dist/token-goat-chunk-UA5V6P3P.mjs +122 -0
- package/dist/token-goat-chunk-UGJHGR5A.mjs +52 -0
- package/dist/{token-goat-chunk-RQGGMPCR.mjs → token-goat-chunk-UOUDVA5U.mjs} +76 -16
- package/dist/{token-goat-chunk-HNFZZHFW.mjs → token-goat-chunk-URRJ33GR.mjs} +22 -4
- package/dist/token-goat-chunk-UZOROKIS.mjs +165 -0
- package/dist/token-goat-chunk-VIHGGGEI.mjs +4234 -0
- package/dist/token-goat-chunk-VTJLAA7P.mjs +21 -0
- package/dist/token-goat-chunk-VWDXLT4F.mjs +678 -0
- package/dist/token-goat-chunk-VWZA2H4P.mjs +368 -0
- package/dist/{token-goat-chunk-QO3LXVVR.mjs → token-goat-chunk-VXEXMJDL.mjs} +2964 -3153
- package/dist/token-goat-chunk-WBA5SKT4.mjs +547 -0
- package/dist/{token-goat-chunk-ONXH6NZ5.mjs → token-goat-chunk-WDH44VAU.mjs} +19 -22
- package/dist/token-goat-chunk-X2SUP3EI.mjs +107 -0
- package/dist/token-goat-chunk-X3BELZSJ.mjs +125 -0
- package/dist/{token-goat-chunk-RLP6J7WR.mjs → token-goat-chunk-XLRBNZCC.mjs} +40 -21
- package/dist/{token-goat-chunk-S4VSXURL.mjs → token-goat-chunk-XRKUX6CM.mjs} +4 -0
- package/dist/token-goat-chunk-XX6O25RN.mjs +82 -0
- package/dist/token-goat-chunk-XZSUHBVS.mjs +65 -0
- package/dist/token-goat-chunk-Y2ZTQOCL.mjs +35 -0
- package/dist/{token-goat-chunk-UA5BKWWQ.mjs → token-goat-chunk-YB4VMGK2.mjs} +15 -4
- package/dist/token-goat-chunk-YBIIY3HR.mjs +51 -0
- package/dist/{token-goat-chunk-PKRWMHVP.mjs → token-goat-chunk-YHVDKQBR.mjs} +389 -221
- package/dist/token-goat-chunk-YJB5XLWI.mjs +26 -0
- package/dist/{token-goat-chunk-PQ53BSCF.mjs → token-goat-chunk-YKB6AQG3.mjs} +53 -31
- package/dist/token-goat-chunk-YMTG2YA5.mjs +35 -0
- package/dist/token-goat-chunk-YPBZYQRV.mjs +40 -0
- package/dist/{token-goat-chunk-HUYUHODZ.mjs → token-goat-chunk-YY6AVUFL.mjs} +13246 -12247
- package/dist/token-goat-chunk-Z7N5OMMP.mjs +98 -0
- package/dist/{token-goat-chunk-BGHSSJUA.mjs → token-goat-chunk-ZFOBKUWH.mjs} +1 -1
- package/dist/token-goat-chunk-ZMBL6UVV.mjs +110 -0
- package/dist/token-goat-chunk-ZNMNUPAZ.mjs +938 -0
- package/dist/token-goat-hook-client.cjs +87 -23
- package/dist/token-goat-hook-client.mjs +3 -3
- package/dist/token-goat-hook.mjs +76 -31
- package/dist/token-goat.core.mjs +6 -6
- package/docs/C4_RUNTIME_ARCHITECTURE.md +2 -2
- package/docs/cli.md +113 -60
- package/docs/install.md +63 -20
- package/docs/security.md +10 -8
- package/package.json +18 -7
- package/scripts/verify-native-dist.mjs +386 -0
- package/dist/token-goat-chunk-2NNUA2LR.mjs +0 -143
- package/dist/token-goat-chunk-44BM7DDQ.mjs +0 -294
- package/dist/token-goat-chunk-BGYOZ6DO.mjs +0 -24
- package/dist/token-goat-chunk-C5YPNZKQ.mjs +0 -318
- package/dist/token-goat-chunk-CIQ2FTY3.mjs +0 -1990
- package/dist/token-goat-chunk-D4ETHJD6.mjs +0 -246
- package/dist/token-goat-chunk-DNRPXHYH.mjs +0 -1062
- package/dist/token-goat-chunk-EUSDXRXU.mjs +0 -1429
- package/dist/token-goat-chunk-FTP4U4QA.mjs +0 -64
- package/dist/token-goat-chunk-G7IWXCFF.mjs +0 -456
- package/dist/token-goat-chunk-GLXRTTLE.mjs +0 -36
- package/dist/token-goat-chunk-H5J3C56Q.mjs +0 -1511
- package/dist/token-goat-chunk-IVWI2OCK.mjs +0 -368
- package/dist/token-goat-chunk-JTKCQMQA.mjs +0 -418
- package/dist/token-goat-chunk-LZNBQTDK.mjs +0 -26
- package/dist/token-goat-chunk-ORNFMIER.mjs +0 -295
- package/dist/token-goat-chunk-RTMVLHWX.mjs +0 -7113
- package/dist/token-goat-chunk-VQ6F6T7X.mjs +0 -36
- package/dist/token-goat-chunk-VZQEWRVH.mjs +0 -312
- package/dist/token-goat-chunk-XYWPOSCN.mjs +0 -807
- package/dist/token-goat-chunk-YAGLESS3.mjs +0 -23
- package/dist/token-goat-chunk-YKSRAWUU.mjs +0 -33
- package/dist/token-goat-chunk-Z6KBMOBI.mjs +0 -53
|
@@ -3,1461 +3,37 @@ const require = __cjsRequire(import.meta.url);
|
|
|
3
3
|
import {
|
|
4
4
|
Database
|
|
5
5
|
} from "./token-goat-chunk-XB5KKOCG.mjs";
|
|
6
|
+
import {
|
|
7
|
+
assignFlatEndLines,
|
|
8
|
+
makeLineSymbol,
|
|
9
|
+
propagateEndLinesToSymbols
|
|
10
|
+
} from "./token-goat-chunk-OUKDTVNU.mjs";
|
|
6
11
|
import {
|
|
7
12
|
registerReset
|
|
8
13
|
} from "./token-goat-chunk-YZAAZU2S.mjs";
|
|
9
14
|
import {
|
|
10
15
|
countContentLines,
|
|
11
|
-
ensureDirSync
|
|
12
|
-
|
|
13
|
-
} from "./token-goat-chunk-XYWPOSCN.mjs";
|
|
16
|
+
ensureDirSync
|
|
17
|
+
} from "./token-goat-chunk-HU4TORC5.mjs";
|
|
14
18
|
import {
|
|
15
19
|
foldCase,
|
|
16
20
|
foldPath,
|
|
21
|
+
isCaseInsensitiveFs,
|
|
17
22
|
sleepSync
|
|
18
|
-
} from "./token-goat-chunk-
|
|
23
|
+
} from "./token-goat-chunk-AM5V6GSX.mjs";
|
|
19
24
|
import {
|
|
25
|
+
normalizePath,
|
|
20
26
|
safeJoin
|
|
21
|
-
} from "./token-goat-chunk-
|
|
27
|
+
} from "./token-goat-chunk-FNFBKLRD.mjs";
|
|
22
28
|
import {
|
|
23
29
|
SYMBOL_BODY_CHAR_CAP,
|
|
24
|
-
dataDir
|
|
25
|
-
|
|
30
|
+
dataDir,
|
|
31
|
+
globalDbPath
|
|
32
|
+
} from "./token-goat-chunk-CO3UYX6G.mjs";
|
|
26
33
|
import {
|
|
27
34
|
init_define_import_meta_env
|
|
28
35
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
29
36
|
|
|
30
|
-
// src/languages/common.ts
|
|
31
|
-
init_define_import_meta_env();
|
|
32
|
-
|
|
33
|
-
// src/doc_comment.ts
|
|
34
|
-
init_define_import_meta_env();
|
|
35
|
-
function precedingDocComment(lines, lineStart, style) {
|
|
36
|
-
const aboveIdx = lineStart - 2;
|
|
37
|
-
if (aboveIdx < 0 || aboveIdx >= lines.length) return "";
|
|
38
|
-
const aboveLine = lines[aboveIdx];
|
|
39
|
-
if (aboveLine === void 0) return "";
|
|
40
|
-
const aboveTrimmed = aboveLine.trim();
|
|
41
|
-
if (style === "vb") {
|
|
42
|
-
if (!aboveTrimmed.startsWith("'''")) return "";
|
|
43
|
-
const collected = [];
|
|
44
|
-
for (let i = aboveIdx; i >= 0; i--) {
|
|
45
|
-
const trimmed = (lines[i] ?? "").trim();
|
|
46
|
-
if (!trimmed.startsWith("'''")) break;
|
|
47
|
-
collected.unshift(trimmed.replace(/^'''\s?/, ""));
|
|
48
|
-
}
|
|
49
|
-
return collected.join("\n").trim();
|
|
50
|
-
}
|
|
51
|
-
if (style === "hash") {
|
|
52
|
-
if (!aboveTrimmed.startsWith("#")) return "";
|
|
53
|
-
const collected = [];
|
|
54
|
-
let i = aboveIdx;
|
|
55
|
-
while (i >= 0) {
|
|
56
|
-
const line = lines[i];
|
|
57
|
-
if (line === void 0) break;
|
|
58
|
-
const trimmed = line.trim();
|
|
59
|
-
if (!trimmed.startsWith("#")) break;
|
|
60
|
-
collected.unshift(trimmed.replace(/^#+\s?/, ""));
|
|
61
|
-
i--;
|
|
62
|
-
}
|
|
63
|
-
return collected.join("\n").trim();
|
|
64
|
-
}
|
|
65
|
-
if (aboveTrimmed.endsWith("*/")) {
|
|
66
|
-
let blockStart = aboveIdx;
|
|
67
|
-
while (blockStart >= 0) {
|
|
68
|
-
const l = lines[blockStart];
|
|
69
|
-
if (l === void 0) break;
|
|
70
|
-
if (l.trim().startsWith("/*")) break;
|
|
71
|
-
blockStart--;
|
|
72
|
-
}
|
|
73
|
-
if (blockStart < 0) return "";
|
|
74
|
-
const opener = lines[blockStart];
|
|
75
|
-
if (opener === void 0 || !opener.trim().startsWith("/*")) return "";
|
|
76
|
-
const region = lines.slice(blockStart, aboveIdx + 1);
|
|
77
|
-
const joined = region.join("\n").trimEnd();
|
|
78
|
-
if (joined.indexOf("*/") !== joined.length - 2) return "";
|
|
79
|
-
return region.map(
|
|
80
|
-
(l) => l.trim().replace(/^\/\*+/, "").replace(/\*+\/$/, "").replace(/^\*\s?/, "").trim()
|
|
81
|
-
).filter((l) => l !== "").join("\n");
|
|
82
|
-
}
|
|
83
|
-
if (aboveTrimmed.startsWith("//")) {
|
|
84
|
-
const collected = [];
|
|
85
|
-
let i = aboveIdx;
|
|
86
|
-
while (i >= 0) {
|
|
87
|
-
const line = lines[i];
|
|
88
|
-
if (line === void 0) break;
|
|
89
|
-
const trimmed = line.trim();
|
|
90
|
-
if (!trimmed.startsWith("//")) break;
|
|
91
|
-
collected.unshift(trimmed.replace(/^\/\/[/!]?\s?/, ""));
|
|
92
|
-
i--;
|
|
93
|
-
}
|
|
94
|
-
return collected.join("\n").trim();
|
|
95
|
-
}
|
|
96
|
-
return "";
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// src/languages/common.ts
|
|
100
|
-
function buildLineIndex(text) {
|
|
101
|
-
const idx = [0];
|
|
102
|
-
for (let i = 0; i < text.length; i++) {
|
|
103
|
-
if (text[i] === "\n") idx.push(i + 1);
|
|
104
|
-
}
|
|
105
|
-
return idx;
|
|
106
|
-
}
|
|
107
|
-
function offsetToLine(lineIndex, offset) {
|
|
108
|
-
let lo = 0;
|
|
109
|
-
let hi = lineIndex.length - 1;
|
|
110
|
-
while (lo < hi) {
|
|
111
|
-
const mid = lo + hi + 1 >> 1;
|
|
112
|
-
const lineStart = lineIndex[mid];
|
|
113
|
-
if (lineStart === void 0 || lineStart > offset) {
|
|
114
|
-
hi = mid - 1;
|
|
115
|
-
} else {
|
|
116
|
-
lo = mid;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return lo + 1;
|
|
120
|
-
}
|
|
121
|
-
function lineTextAt(content, lineIndex, line) {
|
|
122
|
-
const start = lineIndex[line - 1];
|
|
123
|
-
if (start === void 0) return "";
|
|
124
|
-
const next = lineIndex[line];
|
|
125
|
-
return content.slice(start, next === void 0 ? content.length : next - 1).trim();
|
|
126
|
-
}
|
|
127
|
-
function stripCstyleComments(text, lineCommentRe) {
|
|
128
|
-
const lines = text.split("\n");
|
|
129
|
-
let inComment = false;
|
|
130
|
-
const outLines = [];
|
|
131
|
-
for (const line of lines) {
|
|
132
|
-
const { code, inComment: nextInComment } = stripBlockCommentSpan(line, inComment);
|
|
133
|
-
outLines.push(code);
|
|
134
|
-
inComment = nextInComment;
|
|
135
|
-
}
|
|
136
|
-
let out = outLines.join("\n");
|
|
137
|
-
if (lineCommentRe !== void 0) {
|
|
138
|
-
out = out.replace(lineCommentRe, (m) => " ".repeat(m.length));
|
|
139
|
-
}
|
|
140
|
-
return out;
|
|
141
|
-
}
|
|
142
|
-
function stripXmlComments(text) {
|
|
143
|
-
const lines = text.split("\n");
|
|
144
|
-
let inComment = false;
|
|
145
|
-
const outLines = [];
|
|
146
|
-
for (const line of lines) {
|
|
147
|
-
let result = "";
|
|
148
|
-
let j = 0;
|
|
149
|
-
while (j < line.length) {
|
|
150
|
-
if (!inComment) {
|
|
151
|
-
const open = line.indexOf("<!--", j);
|
|
152
|
-
if (open === -1) {
|
|
153
|
-
result += line.slice(j);
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
result += line.slice(j, open);
|
|
157
|
-
const close = line.indexOf("-->", open + 4);
|
|
158
|
-
if (close === -1) {
|
|
159
|
-
result += " ".repeat(line.length - open);
|
|
160
|
-
inComment = true;
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
result += " ".repeat(close + 3 - open);
|
|
164
|
-
j = close + 3;
|
|
165
|
-
inComment = false;
|
|
166
|
-
} else {
|
|
167
|
-
const close = line.indexOf("-->", j);
|
|
168
|
-
if (close === -1) {
|
|
169
|
-
result += " ".repeat(line.length - j);
|
|
170
|
-
break;
|
|
171
|
-
}
|
|
172
|
-
result += " ".repeat(close + 3 - j);
|
|
173
|
-
j = close + 3;
|
|
174
|
-
inComment = false;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
outLines.push(result);
|
|
178
|
-
}
|
|
179
|
-
return outLines.join("\n");
|
|
180
|
-
}
|
|
181
|
-
function scanQuotedStringEnd(content, start) {
|
|
182
|
-
const quote = content[start];
|
|
183
|
-
const n = content.length;
|
|
184
|
-
let j = start + 1;
|
|
185
|
-
while (j < n) {
|
|
186
|
-
if (content[j] === "\\" && j + 1 < n) {
|
|
187
|
-
j += 2;
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
if (content[j] === quote) {
|
|
191
|
-
j++;
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
194
|
-
if (quote !== "`" && content[j] === "\n") {
|
|
195
|
-
j++;
|
|
196
|
-
break;
|
|
197
|
-
}
|
|
198
|
-
j++;
|
|
199
|
-
}
|
|
200
|
-
return j;
|
|
201
|
-
}
|
|
202
|
-
function stripJsComments(content) {
|
|
203
|
-
let out = "";
|
|
204
|
-
let i = 0;
|
|
205
|
-
const n = content.length;
|
|
206
|
-
while (i < n) {
|
|
207
|
-
const ch = content[i];
|
|
208
|
-
if (ch === "/" && content[i + 1] === "/") {
|
|
209
|
-
let j = i;
|
|
210
|
-
while (j < n && content[j] !== "\n") j++;
|
|
211
|
-
out += " ".repeat(j - i);
|
|
212
|
-
i = j;
|
|
213
|
-
continue;
|
|
214
|
-
}
|
|
215
|
-
if (ch === "/" && content[i + 1] === "*") {
|
|
216
|
-
let j = i + 2;
|
|
217
|
-
while (j < n && !(content[j] === "*" && content[j + 1] === "/")) j++;
|
|
218
|
-
const end = j < n ? j + 2 : n;
|
|
219
|
-
out += content.slice(i, end).replace(/[^\n]/g, " ");
|
|
220
|
-
i = end;
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
|
-
if (ch === '"' || ch === "'" || ch === "`") {
|
|
224
|
-
const j = scanQuotedStringEnd(content, i);
|
|
225
|
-
out += content.slice(i, j);
|
|
226
|
-
i = j;
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
|
-
out += ch;
|
|
230
|
-
i++;
|
|
231
|
-
}
|
|
232
|
-
return out;
|
|
233
|
-
}
|
|
234
|
-
function stripHashComments(text) {
|
|
235
|
-
return text.split("\n").map((line) => {
|
|
236
|
-
for (let i = 0; i < line.length; i++) {
|
|
237
|
-
if (line[i] === "#" && !isInsideStringLiteral(line, i)) {
|
|
238
|
-
return line.slice(0, i) + " ".repeat(line.length - i);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
return line;
|
|
242
|
-
}).join("\n");
|
|
243
|
-
}
|
|
244
|
-
var HTML_COMMENT_RE = /<!--[\s\S]*?-->/g;
|
|
245
|
-
var HTML_SCRIPT_BODY_RE = /(<script\b[^>]*>)([\s\S]*?)(<\/script\s*>)/gi;
|
|
246
|
-
var HTML_CDATA_RE = /<!\[CDATA\[[\s\S]*?\]\]>/g;
|
|
247
|
-
var LIQUID_COMMENT_RE = /{%-?\s*comment\s*-?%}[\s\S]*?{%-?\s*endcomment\s*-?%}/gi;
|
|
248
|
-
function maskHtmlNoise(text) {
|
|
249
|
-
let out = text.replace(
|
|
250
|
-
HTML_SCRIPT_BODY_RE,
|
|
251
|
-
(_m, open, body, close) => open + body.replace(/[^\n]/g, " ") + close
|
|
252
|
-
);
|
|
253
|
-
out = out.replace(HTML_COMMENT_RE, (m) => m.replace(/[^\n]/g, " "));
|
|
254
|
-
out = out.replace(LIQUID_COMMENT_RE, (m) => m.replace(/[^\n]/g, " "));
|
|
255
|
-
out = out.replace(HTML_CDATA_RE, (m) => m.replace(/[^\n]/g, " "));
|
|
256
|
-
return out;
|
|
257
|
-
}
|
|
258
|
-
var HTML_HEADING_RE = /<h([1-6])[^>]*>(.*?)<\/h\1>/gis;
|
|
259
|
-
var HTML_HEADING_TAG_STRIP_RE = /<[^>]+>/g;
|
|
260
|
-
function findHtmlHeadingMatches(content) {
|
|
261
|
-
const masked = maskHtmlNoise(content);
|
|
262
|
-
const matches = [];
|
|
263
|
-
for (const m of masked.matchAll(HTML_HEADING_RE)) {
|
|
264
|
-
const level = parseInt(m[1] ?? "1", 10);
|
|
265
|
-
const raw = m[2] ?? "";
|
|
266
|
-
const heading = raw.replace(HTML_HEADING_TAG_STRIP_RE, "").trim();
|
|
267
|
-
matches.push({ level, heading, offset: m.index ?? 0, tag: m[0] ?? "" });
|
|
268
|
-
}
|
|
269
|
-
return matches;
|
|
270
|
-
}
|
|
271
|
-
function isInsideStringLiteral(line, index, from = 0, opts = {}) {
|
|
272
|
-
let openQuote = null;
|
|
273
|
-
let i = from;
|
|
274
|
-
while (i < index) {
|
|
275
|
-
const ch = line[i];
|
|
276
|
-
if (opts.symbolLiterals === true && openQuote === null && ch === "'") {
|
|
277
|
-
const len = scalaCharLiteralLength(line, i);
|
|
278
|
-
i += len === 0 ? 1 : len;
|
|
279
|
-
continue;
|
|
280
|
-
}
|
|
281
|
-
if (openQuote !== null && ch === "\\" && i + 1 < line.length) {
|
|
282
|
-
i += 2;
|
|
283
|
-
continue;
|
|
284
|
-
}
|
|
285
|
-
if (ch === '"' || ch === "'") {
|
|
286
|
-
if (openQuote === null) {
|
|
287
|
-
openQuote = ch;
|
|
288
|
-
} else if (openQuote === ch) {
|
|
289
|
-
openQuote = null;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
i++;
|
|
293
|
-
}
|
|
294
|
-
return openQuote !== null;
|
|
295
|
-
}
|
|
296
|
-
function nextBlockCommentOpen(line, from) {
|
|
297
|
-
const lineCommentIdx = lineCommentStartIndex(line, ["//"], from);
|
|
298
|
-
let open = line.indexOf("/*", from);
|
|
299
|
-
while (open !== -1 && (isInsideStringLiteral(line, open, from) || lineCommentIdx !== -1 && open >= lineCommentIdx)) {
|
|
300
|
-
open = line.indexOf("/*", open + 1);
|
|
301
|
-
}
|
|
302
|
-
return open;
|
|
303
|
-
}
|
|
304
|
-
function stripBlockCommentSpan(line, inComment) {
|
|
305
|
-
let code = "";
|
|
306
|
-
let j = 0;
|
|
307
|
-
let comment = inComment;
|
|
308
|
-
while (j < line.length) {
|
|
309
|
-
if (!comment) {
|
|
310
|
-
const open = nextBlockCommentOpen(line, j);
|
|
311
|
-
if (open === -1) {
|
|
312
|
-
code += line.slice(j);
|
|
313
|
-
break;
|
|
314
|
-
}
|
|
315
|
-
code += line.slice(j, open);
|
|
316
|
-
const close = line.indexOf("*/", open + 2);
|
|
317
|
-
if (close === -1) {
|
|
318
|
-
code += " ".repeat(line.length - open);
|
|
319
|
-
comment = true;
|
|
320
|
-
break;
|
|
321
|
-
}
|
|
322
|
-
code += " ".repeat(close + 2 - open);
|
|
323
|
-
j = close + 2;
|
|
324
|
-
comment = false;
|
|
325
|
-
} else {
|
|
326
|
-
const close = line.indexOf("*/", j);
|
|
327
|
-
if (close === -1) {
|
|
328
|
-
code += " ".repeat(line.length - j);
|
|
329
|
-
break;
|
|
330
|
-
}
|
|
331
|
-
code += " ".repeat(close + 2 - j);
|
|
332
|
-
j = close + 2;
|
|
333
|
-
comment = false;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
return { code, inComment: comment };
|
|
337
|
-
}
|
|
338
|
-
function stripNestedBlockCommentSpan(line, depth) {
|
|
339
|
-
let code = "";
|
|
340
|
-
let j = 0;
|
|
341
|
-
let d = depth;
|
|
342
|
-
while (j < line.length) {
|
|
343
|
-
if (d === 0) {
|
|
344
|
-
const open = nextBlockCommentOpen(line, j);
|
|
345
|
-
if (open === -1) {
|
|
346
|
-
code += line.slice(j);
|
|
347
|
-
break;
|
|
348
|
-
}
|
|
349
|
-
code += line.slice(j, open);
|
|
350
|
-
code += " ";
|
|
351
|
-
j = open + 2;
|
|
352
|
-
d = 1;
|
|
353
|
-
} else {
|
|
354
|
-
const open = line.indexOf("/*", j);
|
|
355
|
-
const close = line.indexOf("*/", j);
|
|
356
|
-
if (close === -1 && open === -1) {
|
|
357
|
-
code += " ".repeat(line.length - j);
|
|
358
|
-
break;
|
|
359
|
-
}
|
|
360
|
-
const next = close === -1 ? open : open === -1 ? close : Math.min(open, close);
|
|
361
|
-
code += " ".repeat(next + 2 - j);
|
|
362
|
-
d = Math.max(0, d + (next === open ? 1 : -1));
|
|
363
|
-
j = next + 2;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
return { code, depth: d };
|
|
367
|
-
}
|
|
368
|
-
function stripLineComment(line, markers = ["//"], opts = {}) {
|
|
369
|
-
const cutIdx = lineCommentStartIndex(line, markers, 0, opts);
|
|
370
|
-
return cutIdx === -1 ? line : line.slice(0, cutIdx);
|
|
371
|
-
}
|
|
372
|
-
function lineCommentStartIndex(line, markers, from = 0, opts = {}) {
|
|
373
|
-
let cutIdx = -1;
|
|
374
|
-
for (const marker of markers) {
|
|
375
|
-
let idx = line.indexOf(marker, from);
|
|
376
|
-
while (idx !== -1 && isInsideStringLiteral(line, idx, from, opts)) {
|
|
377
|
-
idx = line.indexOf(marker, idx + 1);
|
|
378
|
-
}
|
|
379
|
-
if (idx !== -1 && (cutIdx === -1 || idx < cutIdx)) cutIdx = idx;
|
|
380
|
-
}
|
|
381
|
-
return cutIdx;
|
|
382
|
-
}
|
|
383
|
-
function scalaCharLiteralLength(line, index) {
|
|
384
|
-
if (line[index] !== "'") return 0;
|
|
385
|
-
if (line[index + 1] === "\\") {
|
|
386
|
-
if (line[index + 2] === "u") {
|
|
387
|
-
let i = index + 3;
|
|
388
|
-
while (line[i] === "u") i++;
|
|
389
|
-
return /^[0-9a-fA-F]{4}$/.test(line.slice(i, i + 4)) && line[i + 4] === "'" ? i + 5 - index : 0;
|
|
390
|
-
}
|
|
391
|
-
return line[index + 2] !== void 0 && line[index + 3] === "'" ? 4 : 0;
|
|
392
|
-
}
|
|
393
|
-
return line[index + 1] !== void 0 && line[index + 1] !== "'" && line[index + 2] === "'" ? 3 : 0;
|
|
394
|
-
}
|
|
395
|
-
function stripStringLiterals(line, opts = {}) {
|
|
396
|
-
const openDelim = (idx) => {
|
|
397
|
-
const q = line[idx];
|
|
398
|
-
if (opts.tripleQuotes && line[idx + 1] === q && line[idx + 2] === q) return q + q + q;
|
|
399
|
-
return q;
|
|
400
|
-
};
|
|
401
|
-
let out = "";
|
|
402
|
-
let i = 0;
|
|
403
|
-
const stack = [];
|
|
404
|
-
while (i < line.length) {
|
|
405
|
-
const ch = line[i];
|
|
406
|
-
if (ch === "\n") {
|
|
407
|
-
out += ch;
|
|
408
|
-
i++;
|
|
409
|
-
stack.length = 0;
|
|
410
|
-
continue;
|
|
411
|
-
}
|
|
412
|
-
const top = stack[stack.length - 1];
|
|
413
|
-
if (top === void 0) {
|
|
414
|
-
if (opts.symbolLiterals === true && ch === "'" && scalaCharLiteralLength(line, i) === 0) {
|
|
415
|
-
out += ch;
|
|
416
|
-
i++;
|
|
417
|
-
continue;
|
|
418
|
-
}
|
|
419
|
-
if (ch === '"' || ch === "'") {
|
|
420
|
-
const bareBraceHole = ch === '"' && i > 0 && line[i - 1] === "$";
|
|
421
|
-
const delim = openDelim(i);
|
|
422
|
-
stack.push({ kind: "string", quote: delim, bareBraceHole });
|
|
423
|
-
out += delim;
|
|
424
|
-
i += delim.length;
|
|
425
|
-
continue;
|
|
426
|
-
}
|
|
427
|
-
out += ch;
|
|
428
|
-
i++;
|
|
429
|
-
continue;
|
|
430
|
-
}
|
|
431
|
-
if (top.kind === "hole") {
|
|
432
|
-
if (opts.symbolLiterals === true && ch === "'" && scalaCharLiteralLength(line, i) === 0) {
|
|
433
|
-
out += ch;
|
|
434
|
-
i++;
|
|
435
|
-
continue;
|
|
436
|
-
}
|
|
437
|
-
if (ch === '"' || ch === "'") {
|
|
438
|
-
const bareBraceHole = ch === '"' && i > 0 && line[i - 1] === "$";
|
|
439
|
-
const delim = openDelim(i);
|
|
440
|
-
stack.push({ kind: "string", quote: delim, bareBraceHole });
|
|
441
|
-
out += delim;
|
|
442
|
-
i += delim.length;
|
|
443
|
-
continue;
|
|
444
|
-
}
|
|
445
|
-
if (ch === "{") {
|
|
446
|
-
top.depth++;
|
|
447
|
-
out += ch;
|
|
448
|
-
i++;
|
|
449
|
-
continue;
|
|
450
|
-
}
|
|
451
|
-
if (ch === "}") {
|
|
452
|
-
if (top.depth > 0) {
|
|
453
|
-
top.depth--;
|
|
454
|
-
} else {
|
|
455
|
-
stack.pop();
|
|
456
|
-
}
|
|
457
|
-
out += ch;
|
|
458
|
-
i++;
|
|
459
|
-
continue;
|
|
460
|
-
}
|
|
461
|
-
out += ch;
|
|
462
|
-
i++;
|
|
463
|
-
continue;
|
|
464
|
-
}
|
|
465
|
-
if (ch === "\\" && i + 1 < line.length && line[i + 1] !== "\n") {
|
|
466
|
-
out += " ";
|
|
467
|
-
i += 2;
|
|
468
|
-
continue;
|
|
469
|
-
}
|
|
470
|
-
if (ch === top.quote[0] && (top.quote.length === 1 || line.startsWith(top.quote, i))) {
|
|
471
|
-
stack.pop();
|
|
472
|
-
out += top.quote;
|
|
473
|
-
i += top.quote.length;
|
|
474
|
-
continue;
|
|
475
|
-
}
|
|
476
|
-
if (top.quote === '"') {
|
|
477
|
-
if (top.bareBraceHole && ch === "{") {
|
|
478
|
-
if (line[i + 1] === "{") {
|
|
479
|
-
out += " ";
|
|
480
|
-
i += 2;
|
|
481
|
-
continue;
|
|
482
|
-
}
|
|
483
|
-
stack.push({ kind: "hole", depth: 0 });
|
|
484
|
-
out += ch;
|
|
485
|
-
i++;
|
|
486
|
-
continue;
|
|
487
|
-
}
|
|
488
|
-
if (!top.bareBraceHole && ch === "$" && line[i + 1] === "{") {
|
|
489
|
-
stack.push({ kind: "hole", depth: 0 });
|
|
490
|
-
out += line.slice(i, i + 2);
|
|
491
|
-
i += 2;
|
|
492
|
-
continue;
|
|
493
|
-
}
|
|
494
|
-
if (!top.bareBraceHole && ch === "{" && line[i + 1] === "$") {
|
|
495
|
-
stack.push({ kind: "hole", depth: 0 });
|
|
496
|
-
out += ch;
|
|
497
|
-
i++;
|
|
498
|
-
continue;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
out += " ";
|
|
502
|
-
i++;
|
|
503
|
-
}
|
|
504
|
-
return out;
|
|
505
|
-
}
|
|
506
|
-
function closingQuoteRunEnd(text, from, quote, len, runClose) {
|
|
507
|
-
for (let i = from; i < text.length; i++) {
|
|
508
|
-
if (text[i] !== quote) continue;
|
|
509
|
-
let run = 0;
|
|
510
|
-
while (text[i + run] === quote) run++;
|
|
511
|
-
if (run >= len) return runClose === "last" ? i + run : i + len;
|
|
512
|
-
i += run - 1;
|
|
513
|
-
}
|
|
514
|
-
return -1;
|
|
515
|
-
}
|
|
516
|
-
var MULTILINE_CLOSER_ANCHOR = {
|
|
517
|
-
// An Elixir heredoc is terminated only by a delimiter run that begins its own line, preceded by nothing but the whitespace that also sets the indentation stripped from the body (Elixir syntax reference, section "Strings", heredocs). A run appearing mid-line inside the body is content.
|
|
518
|
-
elixir: "lineStart",
|
|
519
|
-
// The closing delimiter of a Swift multi-line string literal has to appear on a line of its own, and its indentation sets what is stripped from each body line (The Swift Programming Language, "Strings and Characters", section "Multiline String Literals"). The same section's rules apply to the extended-delimiter multi-line form (`#"""`), whose only reachable state here is the cross-line one.
|
|
520
|
-
swift: "lineStart",
|
|
521
|
-
// A PHP heredoc or nowdoc closes on its identifier at the start of a line; PHP 7.3 allowed that identifier to be indented and to be followed by other characters (PHP language reference, "Strings", section "Heredoc text"). Read by the heredoc/nowdoc branch, which builds its anchor regex from this value.
|
|
522
|
-
php: "lineStart",
|
|
523
|
-
// A PowerShell here-string terminator (`"@` / `'@`) must be the first characters on its line, with no leading whitespace at all, which is the one language here that is stricter than `'lineStart'` (about_Quoting_Rules, "Here-Strings").
|
|
524
|
-
powershell: "column0",
|
|
525
|
-
// Kotlin's raw string is terminated by the next `"""` wherever it falls, so `val s = """a"""` on one line is a complete literal (Kotlin language specification, "Expressions", section "String literals").
|
|
526
|
-
kotlin: "anywhere",
|
|
527
|
-
// Scala's multi-line string literal is likewise terminated by the next run of three quotes on any line (Scala language specification, section 1.3.5 "Character Literals and String Literals").
|
|
528
|
-
scala: "anywhere",
|
|
529
|
-
// Dart's multi-line string production is a delimiter, content, then the delimiter, with no rule about where on a line the closing delimiter falls (Dart Programming Language Specification, section "Strings").
|
|
530
|
-
dart: "anywhere",
|
|
531
|
-
// A GraphQL block string closes at the next `"""` wherever it sits: the spec's BlockString production places no positional rule on the closing delimiter, and a one-line description such as `"""A user."""` is the ordinary form (GraphQL specification, section 2.9.4 "String Value").
|
|
532
|
-
graphql: "anywhere",
|
|
533
|
-
// C# has two cross-line forms and they disagree, so the language-level value is the permissive one. A verbatim string (`@"..."`) closes on the next non-doubled quote wherever it sits and has no positional rule (C# language reference, "String literals"). A multi-line raw string literal does require its closing run to begin its own line (C# language reference, "Raw string literals"), but that rule is unreachable as a mis-pairing here: the same section forbids the content from holding a quote run as long as the delimiter, so no run inside the body can be mistaken for the closer in the first place, and the run-length rule already in `closingQuoteRunEnd` is what enforces it.
|
|
534
|
-
csharp: "anywhere",
|
|
535
|
-
// R has no fixed-delimiter multi-line form and no positional rule: an ordinary character constant runs to its next unescaped quote (R Language Definition, section 10.3.1 "Literal constants") and a raw constant to its mirrored closing punctuation (R base help page `?Quotes`, "Raw character constants"), on whatever line either lands.
|
|
536
|
-
r: "anywhere"
|
|
537
|
-
};
|
|
538
|
-
function closerSearchStart(line, from, anchor) {
|
|
539
|
-
if (anchor === "anywhere") return from;
|
|
540
|
-
const indent = anchor === "column0" ? 0 : /^[ \t]*/.exec(line)?.[0].length ?? 0;
|
|
541
|
-
return from <= indent ? indent : -1;
|
|
542
|
-
}
|
|
543
|
-
var TRIPLE_QUOTE_RUN_CLOSE = {
|
|
544
|
-
kotlin: "last",
|
|
545
|
-
scala: "last",
|
|
546
|
-
// A GraphQL block string ends at the first `"""` run, because its grammar excludes that sequence from the body outright rather than letting the longest run win (GraphQL specification, section 2.9.4 "String Value", the BlockString production).
|
|
547
|
-
graphql: "first",
|
|
548
|
-
// Swift's closing delimiter has to stand alone on its own line (The Swift Programming Language, "Strings and Characters", section "Multiline String Literals"), so no run longer than three ever terminates a valid Swift literal; it is grouped with Kotlin and Scala so that the same-line and cross-line paths agree, not to assert a rule Swift itself defines.
|
|
549
|
-
swift: "last",
|
|
550
|
-
csharp: "last",
|
|
551
|
-
// An Elixir heredoc cannot open and close on one line, because its opening `"""` must be followed by a newline, so only the cross-line closer is reachable for valid Elixir and that path has always consumed the whole run.
|
|
552
|
-
elixir: "last",
|
|
553
|
-
dart: "first",
|
|
554
|
-
// No triple-quoted literal at all: PHP uses heredoc/nowdoc, PowerShell `@"`/`@'` here-strings, R ordinary and raw character constants. Present only because the Record is exhaustive; the value is never read for these three.
|
|
555
|
-
php: "last",
|
|
556
|
-
powershell: "last",
|
|
557
|
-
r: "last"
|
|
558
|
-
};
|
|
559
|
-
function quoteRunCloser(line, from, quote, len, state) {
|
|
560
|
-
const anchor = state.closerAnchor ?? "anywhere";
|
|
561
|
-
const start = closerSearchStart(line, from, anchor);
|
|
562
|
-
if (start === -1) return null;
|
|
563
|
-
if (anchor !== "anywhere") {
|
|
564
|
-
let run = 0;
|
|
565
|
-
while (line[start + run] === quote) run++;
|
|
566
|
-
if (run < len) return null;
|
|
567
|
-
}
|
|
568
|
-
const end = closingQuoteRunEnd(line, start, quote, len, state.runClose ?? "last");
|
|
569
|
-
return end === -1 ? null : { maskEnd: end };
|
|
570
|
-
}
|
|
571
|
-
function findMultilineCloser(line, from, state) {
|
|
572
|
-
switch (state.kind) {
|
|
573
|
-
case "heredoc":
|
|
574
|
-
case "nowdoc": {
|
|
575
|
-
const indent = (state.closerAnchor ?? "anywhere") === "column0" ? "" : "[ \\t]*";
|
|
576
|
-
const re = new RegExp(`^${indent}${escapeRegExp(state.identifier)}\\b`);
|
|
577
|
-
const m = re.exec(line);
|
|
578
|
-
return m ? { maskEnd: m[0].length } : null;
|
|
579
|
-
}
|
|
580
|
-
case "sigil": {
|
|
581
|
-
const end = elixirSigilEnd(line, from, state);
|
|
582
|
-
return end === -1 ? null : { maskEnd: end };
|
|
583
|
-
}
|
|
584
|
-
case "tripleSingleQuote": {
|
|
585
|
-
return quoteRunCloser(line, from, "'", 3, state);
|
|
586
|
-
}
|
|
587
|
-
case "tripleQuote": {
|
|
588
|
-
const n = state.identifier !== "" ? parseInt(state.identifier, 10) : 3;
|
|
589
|
-
return quoteRunCloser(line, from, '"', n, state);
|
|
590
|
-
}
|
|
591
|
-
case "rRaw":
|
|
592
|
-
case "swiftExtended": {
|
|
593
|
-
const anchor = state.closerAnchor ?? "anywhere";
|
|
594
|
-
if (anchor !== "anywhere") {
|
|
595
|
-
const start = closerSearchStart(line, from, anchor);
|
|
596
|
-
if (start === -1 || !line.startsWith(state.identifier, start)) return null;
|
|
597
|
-
return { maskEnd: start + state.identifier.length };
|
|
598
|
-
}
|
|
599
|
-
const idx = line.indexOf(state.identifier, from);
|
|
600
|
-
return idx === -1 ? null : { maskEnd: idx + state.identifier.length };
|
|
601
|
-
}
|
|
602
|
-
case "rString": {
|
|
603
|
-
const idx = findRQuoteEnd(line, from, state.identifier);
|
|
604
|
-
return idx === -1 ? null : { maskEnd: idx + 1 };
|
|
605
|
-
}
|
|
606
|
-
case "verbatim": {
|
|
607
|
-
if (!state.interpolated) {
|
|
608
|
-
let j2 = from;
|
|
609
|
-
while (j2 < line.length) {
|
|
610
|
-
if (line[j2] === '"') {
|
|
611
|
-
if (line[j2 + 1] === '"') {
|
|
612
|
-
j2 += 2;
|
|
613
|
-
continue;
|
|
614
|
-
}
|
|
615
|
-
return { maskEnd: j2 + 1 };
|
|
616
|
-
}
|
|
617
|
-
j2++;
|
|
618
|
-
}
|
|
619
|
-
return null;
|
|
620
|
-
}
|
|
621
|
-
let j = from;
|
|
622
|
-
let holeDepth = 0;
|
|
623
|
-
let nestedQuote = null;
|
|
624
|
-
while (j < line.length) {
|
|
625
|
-
const c = line[j];
|
|
626
|
-
if (nestedQuote !== null) {
|
|
627
|
-
if (c === "\\" && j + 1 < line.length) {
|
|
628
|
-
j += 2;
|
|
629
|
-
continue;
|
|
630
|
-
}
|
|
631
|
-
if (c === nestedQuote) {
|
|
632
|
-
nestedQuote = null;
|
|
633
|
-
}
|
|
634
|
-
j++;
|
|
635
|
-
continue;
|
|
636
|
-
}
|
|
637
|
-
if (holeDepth > 0) {
|
|
638
|
-
if (c === '"' || c === "'") {
|
|
639
|
-
nestedQuote = c;
|
|
640
|
-
j++;
|
|
641
|
-
continue;
|
|
642
|
-
}
|
|
643
|
-
if (c === "{") holeDepth++;
|
|
644
|
-
else if (c === "}") holeDepth--;
|
|
645
|
-
j++;
|
|
646
|
-
continue;
|
|
647
|
-
}
|
|
648
|
-
if (c === "{") {
|
|
649
|
-
holeDepth = 1;
|
|
650
|
-
j++;
|
|
651
|
-
continue;
|
|
652
|
-
}
|
|
653
|
-
if (c === '"') {
|
|
654
|
-
if (line[j + 1] === '"') {
|
|
655
|
-
j += 2;
|
|
656
|
-
continue;
|
|
657
|
-
}
|
|
658
|
-
return { maskEnd: j + 1 };
|
|
659
|
-
}
|
|
660
|
-
j++;
|
|
661
|
-
}
|
|
662
|
-
return null;
|
|
663
|
-
}
|
|
664
|
-
case "psHereDouble":
|
|
665
|
-
case "psHereSingle": {
|
|
666
|
-
const start = closerSearchStart(line, from, state.closerAnchor ?? "anywhere");
|
|
667
|
-
const terminator = state.kind === "psHereDouble" ? '"@' : "'@";
|
|
668
|
-
if (start === -1 || !line.startsWith(terminator, start)) return null;
|
|
669
|
-
return { maskEnd: start + terminator.length };
|
|
670
|
-
}
|
|
671
|
-
default:
|
|
672
|
-
return null;
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
var MULTILINE_OPENER_COMMENT_MARKERS = {
|
|
676
|
-
php: ["//", "#"],
|
|
677
|
-
kotlin: ["//"],
|
|
678
|
-
graphql: ["#"],
|
|
679
|
-
csharp: ["//"],
|
|
680
|
-
powershell: ["#"],
|
|
681
|
-
swift: ["//"],
|
|
682
|
-
elixir: ["#"],
|
|
683
|
-
scala: ["//"],
|
|
684
|
-
dart: ["//"],
|
|
685
|
-
r: ["#"]
|
|
686
|
-
};
|
|
687
|
-
var MULTILINE_OPENER_BLOCK_COMMENT_LANGS = /* @__PURE__ */ new Set(["php", "kotlin", "csharp", "swift", "scala", "dart"]);
|
|
688
|
-
var R_RAW_OPENER_RE = /[rR](["'])(-*)([([{])/y;
|
|
689
|
-
var R_RAW_CLOSE_BRACKET = { "(": ")", "[": "]", "{": "}" };
|
|
690
|
-
var R_IDENT_CHAR_RE = /[A-Za-z0-9._]/;
|
|
691
|
-
function matchRRawOpener(text, index) {
|
|
692
|
-
const ch = text[index];
|
|
693
|
-
if (ch !== "r" && ch !== "R") return null;
|
|
694
|
-
if (R_IDENT_CHAR_RE.test(text[index - 1] ?? "")) return null;
|
|
695
|
-
R_RAW_OPENER_RE.lastIndex = index;
|
|
696
|
-
const m = R_RAW_OPENER_RE.exec(text);
|
|
697
|
-
if (m === null) return null;
|
|
698
|
-
const close = R_RAW_CLOSE_BRACKET[m[3] ?? ""];
|
|
699
|
-
if (close === void 0) return null;
|
|
700
|
-
return { openerEnd: index + m[0].length, closer: `${close}${m[2] ?? ""}${m[1] ?? ""}` };
|
|
701
|
-
}
|
|
702
|
-
var GROOVY_OPERAND_BEFORE = /* @__PURE__ */ new Set([..."([{,;=+-*/%<>!&|^~?:"]);
|
|
703
|
-
var MAX_GROOVY_SLASHY_BODY = 1024;
|
|
704
|
-
var GROOVY_OPERAND_KEYWORDS = /* @__PURE__ */ new Set(["return", "case", "in", "new", "assert", "instanceof"]);
|
|
705
|
-
function groovyOperandPosition(text, index) {
|
|
706
|
-
let i = index - 1;
|
|
707
|
-
while (i >= 0 && (text[i] === " " || text[i] === " ")) i--;
|
|
708
|
-
if (i < 0) return true;
|
|
709
|
-
const ch = text[i];
|
|
710
|
-
if (ch === "\n" || ch === "\r") return true;
|
|
711
|
-
if (GROOVY_OPERAND_BEFORE.has(ch)) return true;
|
|
712
|
-
if (!/[\w$]/.test(ch)) return false;
|
|
713
|
-
let j = i;
|
|
714
|
-
while (j >= 0 && /[\w$]/.test(text[j])) j--;
|
|
715
|
-
return GROOVY_OPERAND_KEYWORDS.has(text.slice(j + 1, i + 1));
|
|
716
|
-
}
|
|
717
|
-
function matchGroovySlashy(text, index) {
|
|
718
|
-
const dollar = text[index] === "$" && text[index + 1] === "/";
|
|
719
|
-
if (!dollar) {
|
|
720
|
-
if (text[index] !== "/") return null;
|
|
721
|
-
const next = text[index + 1];
|
|
722
|
-
if (next === "/" || next === "*") return null;
|
|
723
|
-
if (!groovyOperandPosition(text, index)) return null;
|
|
724
|
-
}
|
|
725
|
-
const bodyStart = index + (dollar ? 2 : 1);
|
|
726
|
-
const limit = Math.min(text.length, bodyStart + MAX_GROOVY_SLASHY_BODY);
|
|
727
|
-
for (let i = bodyStart; i < limit; i++) {
|
|
728
|
-
const ch = text[i];
|
|
729
|
-
if (dollar) {
|
|
730
|
-
if (ch === "$" && (text[i + 1] === "$" || text[i + 1] === "/")) {
|
|
731
|
-
i++;
|
|
732
|
-
continue;
|
|
733
|
-
}
|
|
734
|
-
if (ch === "/" && text[i + 1] === "$") return { bodyStart, bodyEnd: i, end: i + 2 };
|
|
735
|
-
continue;
|
|
736
|
-
}
|
|
737
|
-
if (ch === "\\" && text[i + 1] === "/") {
|
|
738
|
-
i++;
|
|
739
|
-
continue;
|
|
740
|
-
}
|
|
741
|
-
if (ch === "\n") return null;
|
|
742
|
-
if (ch === "/") return { bodyStart, bodyEnd: i, end: i + 1 };
|
|
743
|
-
}
|
|
744
|
-
return null;
|
|
745
|
-
}
|
|
746
|
-
var ELIXIR_SIGIL_CLOSER = { "(": ")", "[": "]", "{": "}", "<": ">", "/": "/", "|": "|", '"': '"', "'": "'" };
|
|
747
|
-
var ELIXIR_SIGIL_OPENER = { ")": "(", "]": "[", "}": "{", ">": "<" };
|
|
748
|
-
function matchElixirSigilOpener(line, index) {
|
|
749
|
-
if (line[index] !== "~") return null;
|
|
750
|
-
let i = index + 1;
|
|
751
|
-
const first = line[i] ?? "";
|
|
752
|
-
let escapes;
|
|
753
|
-
if (first >= "a" && first <= "z") {
|
|
754
|
-
escapes = true;
|
|
755
|
-
i++;
|
|
756
|
-
} else if (first >= "A" && first <= "Z") {
|
|
757
|
-
escapes = false;
|
|
758
|
-
while (i < line.length && (line[i] ?? "") >= "A" && (line[i] ?? "") <= "Z") i++;
|
|
759
|
-
} else {
|
|
760
|
-
return null;
|
|
761
|
-
}
|
|
762
|
-
const delim = line[i] ?? "";
|
|
763
|
-
const closer = ELIXIR_SIGIL_CLOSER[delim];
|
|
764
|
-
if (closer === void 0) return null;
|
|
765
|
-
if ((delim === '"' || delim === "'") && line[i + 1] === delim && line[i + 2] === delim) return null;
|
|
766
|
-
return { openerEnd: i + 1, closer, escapes };
|
|
767
|
-
}
|
|
768
|
-
function elixirSigilEnd(line, from, state) {
|
|
769
|
-
const closer = state.identifier;
|
|
770
|
-
const opener = ELIXIR_SIGIL_OPENER[closer];
|
|
771
|
-
for (let i = from; i < line.length; i++) {
|
|
772
|
-
const ch = line[i];
|
|
773
|
-
if (state.escapes === true && ch === "\\") {
|
|
774
|
-
i++;
|
|
775
|
-
continue;
|
|
776
|
-
}
|
|
777
|
-
if (opener !== void 0 && ch === opener) {
|
|
778
|
-
state.depth = (state.depth ?? 0) + 1;
|
|
779
|
-
continue;
|
|
780
|
-
}
|
|
781
|
-
if (ch === closer) {
|
|
782
|
-
if ((state.depth ?? 0) > 0) {
|
|
783
|
-
state.depth = (state.depth ?? 0) - 1;
|
|
784
|
-
continue;
|
|
785
|
-
}
|
|
786
|
-
return i + 1;
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
return -1;
|
|
790
|
-
}
|
|
791
|
-
var SWIFT_EXTENDED_OPENER_RE = /(#+)("""|")/y;
|
|
792
|
-
function matchSwiftExtendedOpener(text, index) {
|
|
793
|
-
if (text[index] !== "#") return null;
|
|
794
|
-
SWIFT_EXTENDED_OPENER_RE.lastIndex = index;
|
|
795
|
-
const m = SWIFT_EXTENDED_OPENER_RE.exec(text);
|
|
796
|
-
if (m === null) return null;
|
|
797
|
-
const hashes = m[1] ?? "";
|
|
798
|
-
const multiline = m[2] === '"""';
|
|
799
|
-
return { openerEnd: index + m[0].length, multiline, closer: `${multiline ? '"""' : '"'}${hashes}` };
|
|
800
|
-
}
|
|
801
|
-
var BASH_WORD_TERMINATORS = /* @__PURE__ */ new Set([" ", " ", "\n", "|", "&", ";", "(", ")", "<", ">"]);
|
|
802
|
-
function matchBashHeredocOpener(text, index) {
|
|
803
|
-
if (text[index] !== "<" || text[index + 1] !== "<") return null;
|
|
804
|
-
if (text[index - 1] === "<" || text[index + 2] === "<") return null;
|
|
805
|
-
let i = index + 2;
|
|
806
|
-
if (text[i] === "-") i++;
|
|
807
|
-
while (text[i] === " " || text[i] === " ") i++;
|
|
808
|
-
let terminator = "";
|
|
809
|
-
while (i < text.length) {
|
|
810
|
-
const ch = text[i];
|
|
811
|
-
if (ch === "'") {
|
|
812
|
-
const close = text.indexOf("'", i + 1);
|
|
813
|
-
if (close === -1) return null;
|
|
814
|
-
terminator += text.slice(i + 1, close);
|
|
815
|
-
i = close + 1;
|
|
816
|
-
continue;
|
|
817
|
-
}
|
|
818
|
-
if (ch === '"') {
|
|
819
|
-
let j = i + 1;
|
|
820
|
-
for (; j < text.length; j++) {
|
|
821
|
-
if (text[j] === "\\") {
|
|
822
|
-
terminator += text[j + 1] ?? "";
|
|
823
|
-
j++;
|
|
824
|
-
continue;
|
|
825
|
-
}
|
|
826
|
-
if (text[j] === '"') break;
|
|
827
|
-
terminator += text[j];
|
|
828
|
-
}
|
|
829
|
-
if (j >= text.length) return null;
|
|
830
|
-
i = j + 1;
|
|
831
|
-
continue;
|
|
832
|
-
}
|
|
833
|
-
if (ch === "\\") {
|
|
834
|
-
if (i + 1 >= text.length) break;
|
|
835
|
-
terminator += text[i + 1];
|
|
836
|
-
i += 2;
|
|
837
|
-
continue;
|
|
838
|
-
}
|
|
839
|
-
if (ch === void 0 || BASH_WORD_TERMINATORS.has(ch)) break;
|
|
840
|
-
terminator += ch;
|
|
841
|
-
i++;
|
|
842
|
-
}
|
|
843
|
-
if (terminator === "") return null;
|
|
844
|
-
return { openerEnd: i, terminator };
|
|
845
|
-
}
|
|
846
|
-
function findRQuoteEnd(line, start, quote) {
|
|
847
|
-
for (let j = start; j < line.length; j++) {
|
|
848
|
-
const c = line[j];
|
|
849
|
-
if (c === "\\") {
|
|
850
|
-
j++;
|
|
851
|
-
continue;
|
|
852
|
-
}
|
|
853
|
-
if (c === quote) return j;
|
|
854
|
-
}
|
|
855
|
-
return -1;
|
|
856
|
-
}
|
|
857
|
-
function isInsideSameLineBlockComment(line, idx, from = 0) {
|
|
858
|
-
let comment = false;
|
|
859
|
-
let j = from;
|
|
860
|
-
while (j < idx) {
|
|
861
|
-
if (!comment) {
|
|
862
|
-
const open = line.indexOf("/*", j);
|
|
863
|
-
if (open === -1 || open >= idx) return false;
|
|
864
|
-
if (isInsideStringLiteral(line, open, from)) {
|
|
865
|
-
j = open + 2;
|
|
866
|
-
continue;
|
|
867
|
-
}
|
|
868
|
-
comment = true;
|
|
869
|
-
j = open + 2;
|
|
870
|
-
} else {
|
|
871
|
-
const close = line.indexOf("*/", j);
|
|
872
|
-
if (close === -1 || close >= idx) return true;
|
|
873
|
-
comment = false;
|
|
874
|
-
j = close + 2;
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
return comment;
|
|
878
|
-
}
|
|
879
|
-
function findMultilineOpener(line, from, lang) {
|
|
880
|
-
const commentIdx = lineCommentStartIndex(line, MULTILINE_OPENER_COMMENT_MARKERS[lang], from);
|
|
881
|
-
const isCommented = (idx) => commentIdx !== -1 && idx >= commentIdx || MULTILINE_OPENER_BLOCK_COMMENT_LANGS.has(lang) && isInsideSameLineBlockComment(line, idx, from);
|
|
882
|
-
if (lang === "php") {
|
|
883
|
-
const re = /<<<\s*(['"]?)([A-Za-z_]\w*)\1/g;
|
|
884
|
-
re.lastIndex = from;
|
|
885
|
-
const m = re.exec(line);
|
|
886
|
-
if (!m || isInsideStringLiteral(line, m.index, from) || isCommented(m.index)) return null;
|
|
887
|
-
const identifier = m[2] ?? "";
|
|
888
|
-
const kind = m[1] === "'" ? "nowdoc" : "heredoc";
|
|
889
|
-
return { openStart: m.index, closesSameLine: null, state: { kind, identifier, closerAnchor: MULTILINE_CLOSER_ANCHOR[lang] } };
|
|
890
|
-
}
|
|
891
|
-
if (lang === "kotlin" || lang === "swift" || lang === "scala" || lang === "graphql") {
|
|
892
|
-
let swiftExt = null;
|
|
893
|
-
if (lang === "swift") {
|
|
894
|
-
for (let h = line.indexOf("#", from); h !== -1; h = line.indexOf("#", h + 1)) {
|
|
895
|
-
const ext = matchSwiftExtendedOpener(line, h);
|
|
896
|
-
if (ext === null || isInsideStringLiteral(line, h, from) || isCommented(h)) continue;
|
|
897
|
-
const extClose = line.indexOf(ext.closer, ext.openerEnd);
|
|
898
|
-
const extState = { kind: "swiftExtended", identifier: ext.closer, closerAnchor: MULTILINE_CLOSER_ANCHOR[lang] };
|
|
899
|
-
if (extClose !== -1) {
|
|
900
|
-
swiftExt = { openStart: h, closesSameLine: extClose + ext.closer.length, state: extState };
|
|
901
|
-
break;
|
|
902
|
-
}
|
|
903
|
-
if (ext.multiline) {
|
|
904
|
-
swiftExt = { openStart: h, closesSameLine: null, state: extState };
|
|
905
|
-
break;
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
const idx = line.indexOf('"""', from);
|
|
910
|
-
if (swiftExt !== null && (idx === -1 || swiftExt.openStart < idx)) return swiftExt;
|
|
911
|
-
if (idx === -1 || isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
|
|
912
|
-
const runClose = TRIPLE_QUOTE_RUN_CLOSE[lang];
|
|
913
|
-
const tripleState = { kind: "tripleQuote", identifier: "3", runClose, closerAnchor: MULTILINE_CLOSER_ANCHOR[lang] };
|
|
914
|
-
const closeEnd = closingQuoteRunEnd(line, idx + 3, '"', 3, runClose);
|
|
915
|
-
if (closeEnd !== -1) {
|
|
916
|
-
return { openStart: idx, closesSameLine: closeEnd, state: tripleState };
|
|
917
|
-
}
|
|
918
|
-
return { openStart: idx, closesSameLine: null, state: tripleState };
|
|
919
|
-
}
|
|
920
|
-
if (lang === "elixir" || lang === "dart") {
|
|
921
|
-
const candidates = [];
|
|
922
|
-
const dq = line.indexOf('"""', from);
|
|
923
|
-
if (dq !== -1) candidates.push([dq, "tripleQuote", '"""']);
|
|
924
|
-
const sq = line.indexOf("'''", from);
|
|
925
|
-
if (sq !== -1) candidates.push([sq, "tripleSingleQuote", "'''"]);
|
|
926
|
-
candidates.sort((a, b) => a[0] - b[0]);
|
|
927
|
-
const first = candidates[0];
|
|
928
|
-
if (lang === "elixir") {
|
|
929
|
-
for (let t = line.indexOf("~", from); t !== -1; t = line.indexOf("~", t + 1)) {
|
|
930
|
-
if (first !== void 0 && first[0] < t) break;
|
|
931
|
-
const open = matchElixirSigilOpener(line, t);
|
|
932
|
-
if (open === null || isInsideStringLiteral(line, t, from) || isCommented(t)) continue;
|
|
933
|
-
const state2 = { kind: "sigil", identifier: open.closer, depth: 0, escapes: open.escapes };
|
|
934
|
-
const end = elixirSigilEnd(line, open.openerEnd, state2);
|
|
935
|
-
return { openStart: t, closesSameLine: end === -1 ? null : end, state: state2 };
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
if (first === void 0) return null;
|
|
939
|
-
const [idx, kind, delim] = first;
|
|
940
|
-
if (isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
|
|
941
|
-
const runClose = TRIPLE_QUOTE_RUN_CLOSE[lang];
|
|
942
|
-
const state = { kind, identifier: "3", runClose, closerAnchor: MULTILINE_CLOSER_ANCHOR[lang] };
|
|
943
|
-
const closeEnd = closingQuoteRunEnd(line, idx + 3, delim[0] ?? '"', 3, runClose);
|
|
944
|
-
if (closeEnd !== -1) return { openStart: idx, closesSameLine: closeEnd, state };
|
|
945
|
-
return { openStart: idx, closesSameLine: null, state };
|
|
946
|
-
}
|
|
947
|
-
if (lang === "r") {
|
|
948
|
-
const limit = commentIdx === -1 ? line.length : commentIdx;
|
|
949
|
-
let i = from;
|
|
950
|
-
while (i < limit) {
|
|
951
|
-
const ch = line[i] ?? "";
|
|
952
|
-
if (ch === "`") {
|
|
953
|
-
const end = line.indexOf("`", i + 1);
|
|
954
|
-
if (end === -1 || end >= limit) return null;
|
|
955
|
-
i = end + 1;
|
|
956
|
-
continue;
|
|
957
|
-
}
|
|
958
|
-
const raw = matchRRawOpener(line, i);
|
|
959
|
-
if (raw !== null) {
|
|
960
|
-
const closeIdx = line.indexOf(raw.closer, raw.openerEnd);
|
|
961
|
-
if (closeIdx === -1) return { openStart: i, closesSameLine: null, state: { kind: "rRaw", identifier: raw.closer, closerAnchor: MULTILINE_CLOSER_ANCHOR[lang] } };
|
|
962
|
-
i = closeIdx + raw.closer.length;
|
|
963
|
-
continue;
|
|
964
|
-
}
|
|
965
|
-
if (ch === '"' || ch === "'") {
|
|
966
|
-
const closeIdx = findRQuoteEnd(line, i + 1, ch);
|
|
967
|
-
if (closeIdx === -1) return { openStart: i, closesSameLine: null, state: { kind: "rString", identifier: ch, closerAnchor: MULTILINE_CLOSER_ANCHOR[lang] } };
|
|
968
|
-
i = closeIdx + 1;
|
|
969
|
-
continue;
|
|
970
|
-
}
|
|
971
|
-
i++;
|
|
972
|
-
}
|
|
973
|
-
return null;
|
|
974
|
-
}
|
|
975
|
-
if (lang === "csharp") {
|
|
976
|
-
const tripleRe = /"{3,}/g;
|
|
977
|
-
tripleRe.lastIndex = from;
|
|
978
|
-
const tripleM = tripleRe.exec(line);
|
|
979
|
-
let tripleIdx = tripleM ? tripleM.index : -1;
|
|
980
|
-
const tripleLen = tripleM ? tripleM[0].length : 0;
|
|
981
|
-
if (tripleIdx !== -1 && (isInsideStringLiteral(line, tripleIdx, from) || isCommented(tripleIdx))) tripleIdx = -1;
|
|
982
|
-
const verbRe = /\$?@\$?"/g;
|
|
983
|
-
verbRe.lastIndex = from;
|
|
984
|
-
const verbM = verbRe.exec(line);
|
|
985
|
-
let verbIdx = verbM ? verbM.index : -1;
|
|
986
|
-
if (verbIdx !== -1 && isCommented(verbIdx)) verbIdx = -1;
|
|
987
|
-
if (verbIdx !== -1 && isInsideStringLiteral(line, verbIdx, from)) verbIdx = -1;
|
|
988
|
-
if (tripleIdx === -1 && verbIdx === -1) return null;
|
|
989
|
-
const useTriple = tripleIdx !== -1 && (verbIdx === -1 || tripleIdx < verbIdx);
|
|
990
|
-
if (useTriple) {
|
|
991
|
-
const rawState = { kind: "tripleQuote", identifier: String(tripleLen), runClose: TRIPLE_QUOTE_RUN_CLOSE.csharp, closerAnchor: MULTILINE_CLOSER_ANCHOR[lang] };
|
|
992
|
-
const closeEnd = closingQuoteRunEnd(line, tripleIdx + tripleLen, '"', tripleLen, rawState.runClose ?? "last");
|
|
993
|
-
if (closeEnd !== -1) {
|
|
994
|
-
return { openStart: tripleIdx, closesSameLine: closeEnd, state: rawState };
|
|
995
|
-
}
|
|
996
|
-
return { openStart: tripleIdx, closesSameLine: null, state: rawState };
|
|
997
|
-
}
|
|
998
|
-
const quoteIdx = verbIdx + (verbM?.[0].length ?? 1) - 1;
|
|
999
|
-
const interpolated = (verbM?.[0] ?? "").includes("$");
|
|
1000
|
-
const closer = findMultilineCloser(line, quoteIdx + 1, { kind: "verbatim", identifier: "", interpolated });
|
|
1001
|
-
if (closer !== null) {
|
|
1002
|
-
return { openStart: verbIdx, closesSameLine: closer.maskEnd, state: { kind: "verbatim", identifier: "", interpolated } };
|
|
1003
|
-
}
|
|
1004
|
-
return { openStart: verbIdx, closesSameLine: null, state: { kind: "verbatim", identifier: "", interpolated } };
|
|
1005
|
-
}
|
|
1006
|
-
if (lang === "powershell") {
|
|
1007
|
-
const re = /@("|')\s*$/;
|
|
1008
|
-
const tail = line.slice(from);
|
|
1009
|
-
const m = re.exec(tail);
|
|
1010
|
-
if (!m) return null;
|
|
1011
|
-
const openStart = from + m.index;
|
|
1012
|
-
if (isCommented(openStart)) return null;
|
|
1013
|
-
if (isInsideStringLiteral(line, openStart, from)) return null;
|
|
1014
|
-
const kind = m[1] === '"' ? "psHereDouble" : "psHereSingle";
|
|
1015
|
-
return { openStart, closesSameLine: null, state: { kind, identifier: "", closerAnchor: MULTILINE_CLOSER_ANCHOR[lang] } };
|
|
1016
|
-
}
|
|
1017
|
-
return null;
|
|
1018
|
-
}
|
|
1019
|
-
function stripMultilineStringSpan(line, state, lang) {
|
|
1020
|
-
let code = "";
|
|
1021
|
-
let i = 0;
|
|
1022
|
-
let cur = state;
|
|
1023
|
-
while (i < line.length) {
|
|
1024
|
-
if (cur !== null) {
|
|
1025
|
-
const closed = findMultilineCloser(line, i, cur);
|
|
1026
|
-
if (closed === null) {
|
|
1027
|
-
code += " ".repeat(line.length - i);
|
|
1028
|
-
i = line.length;
|
|
1029
|
-
continue;
|
|
1030
|
-
}
|
|
1031
|
-
code += " ".repeat(closed.maskEnd - i);
|
|
1032
|
-
i = closed.maskEnd;
|
|
1033
|
-
cur = null;
|
|
1034
|
-
continue;
|
|
1035
|
-
}
|
|
1036
|
-
const opened = findMultilineOpener(line, i, lang);
|
|
1037
|
-
if (opened === null) {
|
|
1038
|
-
code += line.slice(i);
|
|
1039
|
-
break;
|
|
1040
|
-
}
|
|
1041
|
-
code += line.slice(i, opened.openStart);
|
|
1042
|
-
if (opened.closesSameLine !== null) {
|
|
1043
|
-
code += " ".repeat(opened.closesSameLine - opened.openStart);
|
|
1044
|
-
i = opened.closesSameLine;
|
|
1045
|
-
cur = null;
|
|
1046
|
-
} else {
|
|
1047
|
-
code += " ".repeat(line.length - opened.openStart);
|
|
1048
|
-
i = line.length;
|
|
1049
|
-
cur = opened.state;
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
return { code, state: cur };
|
|
1053
|
-
}
|
|
1054
|
-
function makeSpanSymbol(filePath, name, kind, span, parent = "", lines, style) {
|
|
1055
|
-
return {
|
|
1056
|
-
filePath,
|
|
1057
|
-
name,
|
|
1058
|
-
kind,
|
|
1059
|
-
lineStart: span.startLine,
|
|
1060
|
-
lineEnd: span.endLine,
|
|
1061
|
-
body: span.body,
|
|
1062
|
-
docstring: lines !== void 0 && style !== void 0 ? precedingDocComment(lines, span.startLine, style) : "",
|
|
1063
|
-
parent
|
|
1064
|
-
};
|
|
1065
|
-
}
|
|
1066
|
-
function makeLineSymbol(filePath, name, kind, line, sig, parent, lines, style) {
|
|
1067
|
-
return {
|
|
1068
|
-
filePath,
|
|
1069
|
-
name,
|
|
1070
|
-
kind,
|
|
1071
|
-
lineStart: line,
|
|
1072
|
-
lineEnd: line,
|
|
1073
|
-
body: sig ?? "",
|
|
1074
|
-
docstring: lines !== void 0 && style !== void 0 ? precedingDocComment(lines, line, style) : "",
|
|
1075
|
-
parent: parent ?? ""
|
|
1076
|
-
};
|
|
1077
|
-
}
|
|
1078
|
-
function makeSymbolEmitter(symbols, sections, seen, filePath, maxSymbols = 1e4, maxHeadingLen = 120) {
|
|
1079
|
-
return function emit(name, kind, line) {
|
|
1080
|
-
if (!name || name.length > maxHeadingLen) return;
|
|
1081
|
-
if (symbols.length >= maxSymbols) return;
|
|
1082
|
-
const key = `${name}\0${kind}\0${line}`;
|
|
1083
|
-
if (seen.has(key)) return;
|
|
1084
|
-
seen.add(key);
|
|
1085
|
-
symbols.push({
|
|
1086
|
-
filePath,
|
|
1087
|
-
name,
|
|
1088
|
-
kind,
|
|
1089
|
-
lineStart: line,
|
|
1090
|
-
lineEnd: line,
|
|
1091
|
-
body: "",
|
|
1092
|
-
docstring: "",
|
|
1093
|
-
parent: ""
|
|
1094
|
-
});
|
|
1095
|
-
sections.push({ heading: name, level: 1, line, endLine: line });
|
|
1096
|
-
};
|
|
1097
|
-
}
|
|
1098
|
-
function assignFlatEndLines(sections, totalLines) {
|
|
1099
|
-
for (let i = 0; i < sections.length; i++) {
|
|
1100
|
-
const s = sections[i];
|
|
1101
|
-
if (s === void 0) continue;
|
|
1102
|
-
let j = i + 1;
|
|
1103
|
-
while (j < sections.length && (sections[j]?.line ?? 0) <= s.line) j++;
|
|
1104
|
-
const next = sections[j];
|
|
1105
|
-
const end = next !== void 0 ? next.line - 1 : totalLines;
|
|
1106
|
-
s.endLine = end < s.line ? s.line : end;
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
function propagateEndLinesToSymbols(symbols, sections) {
|
|
1110
|
-
const sectionMap = /* @__PURE__ */ new Map();
|
|
1111
|
-
for (const sec of sections) {
|
|
1112
|
-
const key = `${sec.heading}\0${sec.line}`;
|
|
1113
|
-
const queue = sectionMap.get(key);
|
|
1114
|
-
if (queue !== void 0) queue.push(sec.endLine);
|
|
1115
|
-
else sectionMap.set(key, [sec.endLine]);
|
|
1116
|
-
}
|
|
1117
|
-
return symbols.map((sym) => {
|
|
1118
|
-
const key = `${sym.name}\0${sym.lineStart}`;
|
|
1119
|
-
const endLine = sectionMap.get(key)?.shift();
|
|
1120
|
-
if (endLine !== void 0 && endLine !== sym.lineEnd) {
|
|
1121
|
-
return { ...sym, lineEnd: endLine };
|
|
1122
|
-
}
|
|
1123
|
-
return sym;
|
|
1124
|
-
});
|
|
1125
|
-
}
|
|
1126
|
-
function tripleQuoteDelimiters(opts) {
|
|
1127
|
-
const delims = [];
|
|
1128
|
-
if (opts?.tripleQuote === true) delims.push('"""');
|
|
1129
|
-
if (opts?.tripleSingleQuote === true) delims.push("'''");
|
|
1130
|
-
return delims;
|
|
1131
|
-
}
|
|
1132
|
-
function quoteRunLength(content, i) {
|
|
1133
|
-
let n = 0;
|
|
1134
|
-
while (content[i + n] === '"') n++;
|
|
1135
|
-
return n;
|
|
1136
|
-
}
|
|
1137
|
-
function skipRawStringQuotes(content, from, min) {
|
|
1138
|
-
return closingQuoteRunEnd(content, from, '"', min, "last");
|
|
1139
|
-
}
|
|
1140
|
-
function stepPowershellString(content, i, quote) {
|
|
1141
|
-
const ch = content[i];
|
|
1142
|
-
if (quote === '"' && ch === "`") return { next: i + 1, open: true };
|
|
1143
|
-
return { next: i, open: ch !== quote };
|
|
1144
|
-
}
|
|
1145
|
-
function opensCsharpVerbatimString(content, i) {
|
|
1146
|
-
const prev = content[i - 1];
|
|
1147
|
-
return prev === "@" || prev === "$" && content[i - 2] === "@";
|
|
1148
|
-
}
|
|
1149
|
-
function toLineCommentPrefixes(prefix) {
|
|
1150
|
-
if (prefix === void 0) return [];
|
|
1151
|
-
return typeof prefix === "string" ? [prefix] : prefix;
|
|
1152
|
-
}
|
|
1153
|
-
function atLineComment(content, i, prefixes, exceptions) {
|
|
1154
|
-
if (exceptions.some((e) => content.startsWith(e, i))) return false;
|
|
1155
|
-
return prefixes.some((prefix) => content.startsWith(prefix, i));
|
|
1156
|
-
}
|
|
1157
|
-
function skipBlockComment(content, start, block, nested) {
|
|
1158
|
-
let i = start + block[0].length;
|
|
1159
|
-
let depth = 1;
|
|
1160
|
-
while (i < content.length) {
|
|
1161
|
-
if (nested && content.startsWith(block[0], i)) {
|
|
1162
|
-
depth++;
|
|
1163
|
-
i += block[0].length;
|
|
1164
|
-
continue;
|
|
1165
|
-
}
|
|
1166
|
-
if (content.startsWith(block[1], i)) {
|
|
1167
|
-
depth--;
|
|
1168
|
-
i += block[1].length;
|
|
1169
|
-
if (depth === 0) return i;
|
|
1170
|
-
continue;
|
|
1171
|
-
}
|
|
1172
|
-
i++;
|
|
1173
|
-
}
|
|
1174
|
-
return -1;
|
|
1175
|
-
}
|
|
1176
|
-
function findMatchingBraceEndLine(content, openBraceIndex, totalLines, lineIndex, lineCommentPrefix, opts) {
|
|
1177
|
-
const linePrefixes = toLineCommentPrefixes(lineCommentPrefix);
|
|
1178
|
-
const lineExceptions = opts?.lineCommentExceptions ?? [];
|
|
1179
|
-
const block = opts?.blockComment;
|
|
1180
|
-
const backtick = opts?.backtickQuote === true;
|
|
1181
|
-
const escapes = opts?.stringEscapes ?? "backslash";
|
|
1182
|
-
const nestedBlock = opts?.nestedBlockComments === true;
|
|
1183
|
-
const rawString = opts?.rawStringQuotes === true;
|
|
1184
|
-
const rRaw = opts?.rRawStrings === true;
|
|
1185
|
-
const tripleDelims = tripleQuoteDelimiters(opts);
|
|
1186
|
-
const lineString = opts?.lineStringPrefix;
|
|
1187
|
-
let depth = 0;
|
|
1188
|
-
let quote = null;
|
|
1189
|
-
let verbatim = false;
|
|
1190
|
-
for (let i = openBraceIndex; i < content.length; i++) {
|
|
1191
|
-
const ch = content[i];
|
|
1192
|
-
if (quote !== null) {
|
|
1193
|
-
if (verbatim) {
|
|
1194
|
-
if (ch === quote) {
|
|
1195
|
-
if (content[i + 1] === quote) {
|
|
1196
|
-
i++;
|
|
1197
|
-
continue;
|
|
1198
|
-
}
|
|
1199
|
-
quote = null;
|
|
1200
|
-
verbatim = false;
|
|
1201
|
-
}
|
|
1202
|
-
continue;
|
|
1203
|
-
}
|
|
1204
|
-
if (escapes === "powershell") {
|
|
1205
|
-
const step = stepPowershellString(content, i, quote);
|
|
1206
|
-
i = step.next;
|
|
1207
|
-
if (!step.open) quote = null;
|
|
1208
|
-
continue;
|
|
1209
|
-
}
|
|
1210
|
-
if (ch === "\\") {
|
|
1211
|
-
i++;
|
|
1212
|
-
continue;
|
|
1213
|
-
}
|
|
1214
|
-
if (ch === quote) quote = null;
|
|
1215
|
-
continue;
|
|
1216
|
-
}
|
|
1217
|
-
if (block !== void 0 && content.startsWith(block[0], i)) {
|
|
1218
|
-
const end = skipBlockComment(content, i, block, nestedBlock);
|
|
1219
|
-
i = end === -1 ? content.length : end - 1;
|
|
1220
|
-
continue;
|
|
1221
|
-
}
|
|
1222
|
-
if (atLineComment(content, i, linePrefixes, lineExceptions)) {
|
|
1223
|
-
while (i < content.length && content[i] !== "\n") i++;
|
|
1224
|
-
continue;
|
|
1225
|
-
}
|
|
1226
|
-
if (lineString !== void 0 && content.startsWith(lineString, i)) {
|
|
1227
|
-
while (i < content.length && content[i] !== "\n") i++;
|
|
1228
|
-
continue;
|
|
1229
|
-
}
|
|
1230
|
-
if (rRaw) {
|
|
1231
|
-
const rOpen = matchRRawOpener(content, i);
|
|
1232
|
-
if (rOpen !== null) {
|
|
1233
|
-
const end = content.indexOf(rOpen.closer, rOpen.openerEnd);
|
|
1234
|
-
i = end === -1 ? content.length : end + rOpen.closer.length - 1;
|
|
1235
|
-
continue;
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
if (rawString && ch === '"') {
|
|
1239
|
-
const run = quoteRunLength(content, i);
|
|
1240
|
-
if (run >= 3) {
|
|
1241
|
-
const end = skipRawStringQuotes(content, i + run, run);
|
|
1242
|
-
i = end === -1 ? content.length : end - 1;
|
|
1243
|
-
continue;
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
const tripleAt = tripleDelims.find((t) => content.startsWith(t, i));
|
|
1247
|
-
if (tripleAt !== void 0) {
|
|
1248
|
-
const end = closingQuoteRunEnd(content, i + 3, tripleAt[0] ?? '"', 3, opts?.tripleQuoteRunClose ?? "last");
|
|
1249
|
-
i = end === -1 ? content.length : end - 1;
|
|
1250
|
-
continue;
|
|
1251
|
-
}
|
|
1252
|
-
if (ch === '"' || ch === "'" || backtick && ch === "`") {
|
|
1253
|
-
quote = ch;
|
|
1254
|
-
verbatim = escapes === "csharp" && ch === '"' && opensCsharpVerbatimString(content, i);
|
|
1255
|
-
continue;
|
|
1256
|
-
}
|
|
1257
|
-
if (ch === "{") depth++;
|
|
1258
|
-
else if (ch === "}") {
|
|
1259
|
-
depth--;
|
|
1260
|
-
if (depth === 0) {
|
|
1261
|
-
return offsetToLine(lineIndex, i);
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
return opts?.noMatchValue ?? totalLines;
|
|
1266
|
-
}
|
|
1267
|
-
function assignBraceBlockSpans(symbols, content, opts = {}) {
|
|
1268
|
-
const lineCommentPrefix = opts.lineComment;
|
|
1269
|
-
const stringEscapes = opts.stringEscapes ?? "backslash";
|
|
1270
|
-
const nestedBlockComments = opts.nestedBlockComments ?? false;
|
|
1271
|
-
const tripleQuote = opts.tripleQuote ?? false;
|
|
1272
|
-
const lineStringPrefix = opts.lineStringPrefix;
|
|
1273
|
-
const firstLinePrefix = toLineCommentPrefixes(lineCommentPrefix)[0];
|
|
1274
|
-
if (symbols.length === 0) return [...symbols];
|
|
1275
|
-
const lines = content.split("\n");
|
|
1276
|
-
const totalLines = lines.length;
|
|
1277
|
-
const lineIndex = buildLineIndex(content);
|
|
1278
|
-
const starts = [...new Set(symbols.map((s) => s.lineStart))].sort((a, b) => a - b);
|
|
1279
|
-
const scanContent = opts.multilineLang === void 0 ? content : maskMultilineStrings(content, opts.multilineLang);
|
|
1280
|
-
const blockComment = opts.blockComment !== void 0 ? opts.blockComment ?? void 0 : firstLinePrefix === "//" ? ["/*", "*/"] : firstLinePrefix === "#" ? ["<#", "#>"] : void 0;
|
|
1281
|
-
const scanOpts = {
|
|
1282
|
-
noMatchValue: -1,
|
|
1283
|
-
stringEscapes,
|
|
1284
|
-
tripleQuote,
|
|
1285
|
-
rawStringQuotes: opts.rawStringQuotes ?? false,
|
|
1286
|
-
tripleSingleQuote: opts.tripleSingleQuote ?? false,
|
|
1287
|
-
tripleQuoteRunClose: opts.tripleQuoteRunClose ?? "last",
|
|
1288
|
-
...blockComment === void 0 ? {} : { blockComment, nestedBlockComments },
|
|
1289
|
-
...lineStringPrefix === void 0 ? {} : { lineStringPrefix },
|
|
1290
|
-
...opts.lineCommentExceptions === void 0 ? {} : { lineCommentExceptions: opts.lineCommentExceptions }
|
|
1291
|
-
};
|
|
1292
|
-
return symbols.map((sym) => {
|
|
1293
|
-
if (sym.lineEnd !== sym.lineStart) return sym;
|
|
1294
|
-
const nextStart = starts.find((s) => s > sym.lineStart);
|
|
1295
|
-
const lastSearchLine = Math.min(nextStart !== void 0 ? nextStart - 1 : totalLines, sym.lineStart + BRACE_SEARCH_MAX_LINES);
|
|
1296
|
-
const openIndex = findBlockOpenBrace(scanContent, lineIndex, sym.lineStart, lastSearchLine, lineCommentPrefix, scanOpts);
|
|
1297
|
-
if (openIndex === null) return sym;
|
|
1298
|
-
const endLine = findMatchingBraceEndLine(
|
|
1299
|
-
scanContent,
|
|
1300
|
-
openIndex,
|
|
1301
|
-
totalLines,
|
|
1302
|
-
lineIndex,
|
|
1303
|
-
lineCommentPrefix,
|
|
1304
|
-
scanOpts
|
|
1305
|
-
);
|
|
1306
|
-
if (endLine <= sym.lineStart) return sym;
|
|
1307
|
-
return { ...sym, lineEnd: endLine, body: lines.slice(sym.lineStart - 1, endLine).join("\n") };
|
|
1308
|
-
});
|
|
1309
|
-
}
|
|
1310
|
-
var BRACE_SEARCH_MAX_LINES = 10;
|
|
1311
|
-
function maskMultilineStrings(content, lang) {
|
|
1312
|
-
let state = null;
|
|
1313
|
-
const parts = [];
|
|
1314
|
-
let pos = 0;
|
|
1315
|
-
for (; ; ) {
|
|
1316
|
-
const nl = content.indexOf("\n", pos);
|
|
1317
|
-
const end = nl === -1 ? content.length : nl;
|
|
1318
|
-
const lineEnd = end > pos && content[end - 1] === "\r" ? end - 1 : end;
|
|
1319
|
-
const masked = stripMultilineStringSpan(content.slice(pos, lineEnd), state, lang);
|
|
1320
|
-
state = masked.state;
|
|
1321
|
-
parts.push(masked.code, content.slice(lineEnd, end));
|
|
1322
|
-
if (nl === -1) break;
|
|
1323
|
-
parts.push("\n");
|
|
1324
|
-
pos = nl + 1;
|
|
1325
|
-
}
|
|
1326
|
-
return parts.join("");
|
|
1327
|
-
}
|
|
1328
|
-
function findBlockOpenBrace(content, lineIndex, startLine, lastSearchLine, lineCommentPrefix, opts) {
|
|
1329
|
-
const blockComment = opts?.blockComment;
|
|
1330
|
-
const stringEscapes = opts?.stringEscapes ?? "backslash";
|
|
1331
|
-
const nestedBlockComments = opts?.nestedBlockComments === true;
|
|
1332
|
-
const rawString = opts?.rawStringQuotes === true;
|
|
1333
|
-
const tripleDelims = tripleQuoteDelimiters(opts);
|
|
1334
|
-
const lineString = opts?.lineStringPrefix;
|
|
1335
|
-
const linePrefixes = toLineCommentPrefixes(lineCommentPrefix);
|
|
1336
|
-
const lineExceptions = opts?.lineCommentExceptions ?? [];
|
|
1337
|
-
const from = lineIndex[startLine - 1];
|
|
1338
|
-
if (from === void 0) return null;
|
|
1339
|
-
const to = lineIndex[lastSearchLine] ?? content.length;
|
|
1340
|
-
let quote = null;
|
|
1341
|
-
let parenDepth = 0;
|
|
1342
|
-
let linesSeen = 0;
|
|
1343
|
-
let atLineStart = false;
|
|
1344
|
-
let verbatim = false;
|
|
1345
|
-
for (let i = from; i < to; i++) {
|
|
1346
|
-
const ch = content[i];
|
|
1347
|
-
if (ch === void 0) break;
|
|
1348
|
-
if (quote !== null) {
|
|
1349
|
-
if (verbatim) {
|
|
1350
|
-
if (ch === quote) {
|
|
1351
|
-
if (content[i + 1] === quote) {
|
|
1352
|
-
i++;
|
|
1353
|
-
continue;
|
|
1354
|
-
}
|
|
1355
|
-
quote = null;
|
|
1356
|
-
verbatim = false;
|
|
1357
|
-
}
|
|
1358
|
-
continue;
|
|
1359
|
-
}
|
|
1360
|
-
if (stringEscapes === "powershell") {
|
|
1361
|
-
const step = stepPowershellString(content, i, quote);
|
|
1362
|
-
i = step.next;
|
|
1363
|
-
if (!step.open) quote = null;
|
|
1364
|
-
continue;
|
|
1365
|
-
}
|
|
1366
|
-
if (ch === "\\") {
|
|
1367
|
-
i++;
|
|
1368
|
-
continue;
|
|
1369
|
-
}
|
|
1370
|
-
if (ch === quote) quote = null;
|
|
1371
|
-
continue;
|
|
1372
|
-
}
|
|
1373
|
-
if (ch === "\n") {
|
|
1374
|
-
linesSeen++;
|
|
1375
|
-
atLineStart = true;
|
|
1376
|
-
continue;
|
|
1377
|
-
}
|
|
1378
|
-
if (blockComment !== void 0 && content.startsWith(blockComment[0], i)) {
|
|
1379
|
-
const end = skipBlockComment(content, i, blockComment, nestedBlockComments);
|
|
1380
|
-
if (end === -1) return null;
|
|
1381
|
-
i = end - 1;
|
|
1382
|
-
continue;
|
|
1383
|
-
}
|
|
1384
|
-
if (atLineComment(content, i, linePrefixes, lineExceptions)) {
|
|
1385
|
-
while (i + 1 < to && content[i + 1] !== "\n") i++;
|
|
1386
|
-
continue;
|
|
1387
|
-
}
|
|
1388
|
-
if (atLineStart && !/\s/.test(ch)) {
|
|
1389
|
-
atLineStart = false;
|
|
1390
|
-
if (parenDepth === 0 && linesSeen >= 1 && startsWithBlockKeyword(content, i, to)) return null;
|
|
1391
|
-
}
|
|
1392
|
-
if (lineString !== void 0 && content.startsWith(lineString, i)) {
|
|
1393
|
-
while (i + 1 < to && content[i + 1] !== "\n") i++;
|
|
1394
|
-
continue;
|
|
1395
|
-
}
|
|
1396
|
-
if (rawString && ch === '"') {
|
|
1397
|
-
const run = quoteRunLength(content, i);
|
|
1398
|
-
if (run >= 3) {
|
|
1399
|
-
const end = skipRawStringQuotes(content, i + run, run);
|
|
1400
|
-
if (end === -1) return null;
|
|
1401
|
-
i = end - 1;
|
|
1402
|
-
continue;
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
const tripleAt = tripleDelims.find((t) => content.startsWith(t, i));
|
|
1406
|
-
if (tripleAt !== void 0) {
|
|
1407
|
-
const end = closingQuoteRunEnd(content, i + 3, tripleAt[0] ?? '"', 3, opts?.tripleQuoteRunClose ?? "last");
|
|
1408
|
-
if (end === -1) return null;
|
|
1409
|
-
i = end - 1;
|
|
1410
|
-
continue;
|
|
1411
|
-
}
|
|
1412
|
-
if (ch === '"' || ch === "'") {
|
|
1413
|
-
quote = ch;
|
|
1414
|
-
verbatim = stringEscapes === "csharp" && ch === '"' && opensCsharpVerbatimString(content, i);
|
|
1415
|
-
continue;
|
|
1416
|
-
}
|
|
1417
|
-
if (ch === "(" || ch === "[") parenDepth++;
|
|
1418
|
-
else if (ch === ")" || ch === "]") {
|
|
1419
|
-
if (parenDepth > 0) parenDepth--;
|
|
1420
|
-
} else if (ch === ";") return null;
|
|
1421
|
-
else if (ch === "}" && parenDepth === 0) return null;
|
|
1422
|
-
else if (ch === "{") return i;
|
|
1423
|
-
}
|
|
1424
|
-
return null;
|
|
1425
|
-
}
|
|
1426
|
-
var BLOCK_OPENING_KEYWORDS = /* @__PURE__ */ new Set([
|
|
1427
|
-
"if",
|
|
1428
|
-
"for",
|
|
1429
|
-
"while",
|
|
1430
|
-
"do",
|
|
1431
|
-
"switch",
|
|
1432
|
-
"when",
|
|
1433
|
-
"match",
|
|
1434
|
-
"try",
|
|
1435
|
-
"foreach",
|
|
1436
|
-
"loop",
|
|
1437
|
-
"guard",
|
|
1438
|
-
"repeat",
|
|
1439
|
-
"unless",
|
|
1440
|
-
"until"
|
|
1441
|
-
]);
|
|
1442
|
-
function startsWithBlockKeyword(content, i, to) {
|
|
1443
|
-
const first = content[i];
|
|
1444
|
-
if (first === void 0 || !/[A-Za-z_]/.test(first)) return false;
|
|
1445
|
-
let j = i + 1;
|
|
1446
|
-
while (j < to && /[A-Za-z0-9_]/.test(content[j])) j++;
|
|
1447
|
-
return BLOCK_OPENING_KEYWORDS.has(content.slice(i, j));
|
|
1448
|
-
}
|
|
1449
|
-
function lastContentLine(rawLines) {
|
|
1450
|
-
let n = rawLines.length;
|
|
1451
|
-
while (n > 0 && rawLines[n - 1].trim() === "") n--;
|
|
1452
|
-
return Math.max(1, n);
|
|
1453
|
-
}
|
|
1454
|
-
function nestedAngleClause(depth) {
|
|
1455
|
-
let inner = "[^<>]*";
|
|
1456
|
-
for (let i = 0; i < depth; i++) inner = "[^<>]*(?:<" + inner + ">[^<>]*)*";
|
|
1457
|
-
return "<" + inner + ">";
|
|
1458
|
-
}
|
|
1459
|
-
var GENERIC_CLAUSE = nestedAngleClause(4);
|
|
1460
|
-
|
|
1461
37
|
// src/languages/ini_idx.ts
|
|
1462
38
|
init_define_import_meta_env();
|
|
1463
39
|
var MAX_SECTIONS = 200;
|
|
@@ -1541,90 +117,6 @@ function extractEnv(content, filePath) {
|
|
|
1541
117
|
return symbols;
|
|
1542
118
|
}
|
|
1543
119
|
|
|
1544
|
-
// src/parser_types.ts
|
|
1545
|
-
init_define_import_meta_env();
|
|
1546
|
-
import * as fs from "node:fs";
|
|
1547
|
-
import * as path from "node:path";
|
|
1548
|
-
|
|
1549
|
-
// src/languages/sniff.ts
|
|
1550
|
-
init_define_import_meta_env();
|
|
1551
|
-
var SNIFF_CHARS = 8192;
|
|
1552
|
-
var ABL_MARKER_RES = [
|
|
1553
|
-
/^&ANALYZE-SUSPEND\b/i,
|
|
1554
|
-
/^&(?:SCOPED|GLOBAL)-DEFINE\s/i,
|
|
1555
|
-
/^(?:ROUTINE|BLOCK)-LEVEL\s+ON\s+ERROR\s+UNDO\b/i,
|
|
1556
|
-
/^DEF(?:INE)?\s+(?:NEW\s+)?(?:GLOBAL\s+)?(?:SHARED\s+)?(?:VAR|VARIABLE|TEMP-TABLE|BUFFER|QUERY|STREAM|DATASET|FRAME|(?:INPUT|OUTPUT|INPUT-OUTPUT)\s+PARAM(?:ETER)?)\s/i,
|
|
1557
|
-
/^FUNCTION\s+[\w-]+\s+RETURNS\s/i,
|
|
1558
|
-
/^FOR\s+EACH\s/i,
|
|
1559
|
-
/^END\s+(?:PROCEDURE|FUNCTION|CLASS|INTERFACE|METHOD|CONSTRUCTOR)\s*\.$/i,
|
|
1560
|
-
/^USING\s+[\w.*-]+(?:\s+FROM\s+(?:ASSEMBLY|PROPATH))?\s*\.$/i
|
|
1561
|
-
];
|
|
1562
|
-
var ABL_HEADER_RE = /^(?:PROCEDURE\s+[\w-]+|(?:CLASS|INTERFACE)\s+[\w.-]+)(?:\s|:)/i;
|
|
1563
|
-
var ABL_SNIFF_CHARS = SNIFF_CHARS;
|
|
1564
|
-
function isAblSource(content) {
|
|
1565
|
-
const head = content.slice(0, ABL_SNIFF_CHARS);
|
|
1566
|
-
if (head.includes("\0")) return false;
|
|
1567
|
-
for (const raw of head.split(/\r?\n/)) {
|
|
1568
|
-
const line = raw.trim();
|
|
1569
|
-
if (line === "") continue;
|
|
1570
|
-
if (ABL_MARKER_RES.some((re) => re.test(line))) return true;
|
|
1571
|
-
if (ABL_HEADER_RE.test(line) && line.endsWith(":")) return true;
|
|
1572
|
-
}
|
|
1573
|
-
return false;
|
|
1574
|
-
}
|
|
1575
|
-
var SNIFF_FUNCTION_RE = /^function\b\s*(?:(?:\[[\w\s,~]*\]|[A-Za-z]\w*)\s*=\s*)?[A-Za-z]\w*(?:\.[A-Za-z]\w*)?\s*(?:\(|[%#;,]|$)/;
|
|
1576
|
-
var SNIFF_CLASSDEF_RE = /^classdef\b\s*(?:\([^)]*\)\s*)?[A-Za-z]\w*\s*(?:<|[%#]|$)/;
|
|
1577
|
-
function isMatlabSource(content) {
|
|
1578
|
-
for (const raw of content.slice(0, SNIFF_CHARS).split("\n")) {
|
|
1579
|
-
const line = raw.trim();
|
|
1580
|
-
if (SNIFF_FUNCTION_RE.test(line) || SNIFF_CLASSDEF_RE.test(line)) return true;
|
|
1581
|
-
}
|
|
1582
|
-
return false;
|
|
1583
|
-
}
|
|
1584
|
-
function isObjcSource(content) {
|
|
1585
|
-
return /^[ \t]*(?:#[ \t]*import[ \t]*[<"]|@(?:interface|implementation|protocol)\b)/m.test(content.slice(0, SNIFF_CHARS));
|
|
1586
|
-
}
|
|
1587
|
-
function isObjcHeader(content) {
|
|
1588
|
-
return /^[ \t]*@(?:interface|protocol)\b/m.test(content.slice(0, SNIFF_CHARS));
|
|
1589
|
-
}
|
|
1590
|
-
function isPascalSource(content) {
|
|
1591
|
-
const head = content.slice(0, SNIFF_CHARS);
|
|
1592
|
-
let i = 0;
|
|
1593
|
-
for (; ; ) {
|
|
1594
|
-
while (i < head.length && /\s/.test(head[i])) i++;
|
|
1595
|
-
if (head[i] === "{") {
|
|
1596
|
-
const end = head.indexOf("}", i);
|
|
1597
|
-
if (end < 0) return false;
|
|
1598
|
-
i = end + 1;
|
|
1599
|
-
} else if (head.startsWith("(*", i)) {
|
|
1600
|
-
const end = head.indexOf("*)", i);
|
|
1601
|
-
if (end < 0) return false;
|
|
1602
|
-
i = end + 2;
|
|
1603
|
-
} else if (head.startsWith("//", i)) {
|
|
1604
|
-
const end = head.indexOf("\n", i);
|
|
1605
|
-
if (end < 0) return false;
|
|
1606
|
-
i = end + 1;
|
|
1607
|
-
} else {
|
|
1608
|
-
break;
|
|
1609
|
-
}
|
|
1610
|
-
}
|
|
1611
|
-
return /^(?:unit|program|library)[ \t\r\n]+[A-Za-z_][\w.]*[ \t\r\n]*[;(]/i.test(head.slice(i, i + 300));
|
|
1612
|
-
}
|
|
1613
|
-
var PERL_MARKER_RE = /^(?:#!.*\bperl\b|[ \t]*use[ \t]+(?:strict|warnings|Test::More|Test2::V0|Test::Simple)\b|[ \t]*package[ \t]+[\w:]+[ \t]*;|[ \t]*my[ \t]+[$@%]|[ \t]*sub[ \t]+\w+[ \t]*\{)/m;
|
|
1614
|
-
function isPerlSource(content) {
|
|
1615
|
-
const head = content.slice(0, SNIFF_CHARS);
|
|
1616
|
-
return PERL_MARKER_RE.test(head) && !/^[ \t]*use[ \t]+v6\b/m.test(head);
|
|
1617
|
-
}
|
|
1618
|
-
function isPrologSource(content) {
|
|
1619
|
-
const head = content.slice(0, SNIFF_CHARS);
|
|
1620
|
-
if (PERL_MARKER_RE.test(head)) return false;
|
|
1621
|
-
return /^:-/m.test(head) || /^[a-z]\w*(?:\([^()\n]*\))?[ \t]*:-/m.test(head);
|
|
1622
|
-
}
|
|
1623
|
-
var LATEX_CLASS_MARKER_RE = /\\(?:ProvidesClass|documentclass)\b/;
|
|
1624
|
-
function isLatexClassFile(content) {
|
|
1625
|
-
return LATEX_CLASS_MARKER_RE.test(content.slice(0, SNIFF_CHARS));
|
|
1626
|
-
}
|
|
1627
|
-
|
|
1628
120
|
// src/language_specs.ts
|
|
1629
121
|
init_define_import_meta_env();
|
|
1630
122
|
var CODE = { symbolBearing: true, sourceHints: true, grepSource: true, diffable: true };
|
|
@@ -1656,8 +148,7 @@ var LANGUAGE_SPECS = [
|
|
|
1656
148
|
{ id: "php", extraction: "regex", extensions: [".php"], label: "PHP", ...CODE, fence: "php" },
|
|
1657
149
|
{ id: "html", extraction: "regex", extensions: [".html", ".htm"], label: "HTML", ...DATA, fence: "html" },
|
|
1658
150
|
{ id: "liquid", extraction: "regex", extensions: [".liquid"], ...DATA, fence: "liquid" },
|
|
1659
|
-
// Six template dialects, each masking its own delimiters out then handing off to the HTML
|
|
1660
|
-
// extractor (src/languages/templates_idx.ts) -- markup formats, so DATA defaults like html/liquid.
|
|
151
|
+
// Six template dialects, each masking its own delimiters out then handing off to the HTML extractor (src/languages/templates_idx.ts) -- markup formats, so DATA defaults like html/liquid.
|
|
1661
152
|
{ id: "jinja2", extraction: "regex", extensions: [".j2", ".jinja", ".jinja2"], label: "Jinja2", ...DATA, fence: "jinja" },
|
|
1662
153
|
{ id: "handlebars", extraction: "regex", extensions: [".hbs", ".handlebars"], label: "Handlebars", ...DATA, fence: "handlebars" },
|
|
1663
154
|
{ id: "erb", extraction: "regex", extensions: [".erb"], label: "ERB", ...DATA, fence: "erb" },
|
|
@@ -1739,8 +230,7 @@ var LANGUAGE_SPECS = [
|
|
|
1739
230
|
{ id: "batch", extraction: "regex", extensions: [".bat", ".cmd"], label: "Windows batch", ...CODE, fence: "batch" },
|
|
1740
231
|
{ id: "erlang", extraction: "regex", extensions: [".erl", ".hrl"], label: "Erlang", ...CODE, fence: "erlang" },
|
|
1741
232
|
{ id: "vhdl", extraction: "regex", extensions: [".vhd", ".vhdl"], label: "VHDL", ...CODE, fence: "vhdl" },
|
|
1742
|
-
// Five Lisp-family dialects, each its own row: none shares an extractor (see common_lisp.ts's
|
|
1743
|
-
// module doc for why their lexical rules stay separate rather than a single Lisp masker).
|
|
233
|
+
// Five Lisp-family dialects, each its own row: none shares an extractor (see common_lisp.ts's module doc for why their lexical rules stay separate rather than a single Lisp masker).
|
|
1744
234
|
{ id: "common_lisp", extraction: "regex", extensions: [".lisp", ".lsp", ".cl"], label: "Common Lisp", ...CODE, fence: "lisp" },
|
|
1745
235
|
{ id: "scheme", extraction: "regex", extensions: [".scm", ".ss"], label: "Scheme", ...CODE, fence: "scheme" },
|
|
1746
236
|
{ id: "racket", extraction: "regex", extensions: [".rkt", ".rktl"], label: "Racket", ...CODE, fence: "racket" },
|
|
@@ -1798,6 +288,90 @@ function partialRefsReason(language) {
|
|
|
1798
288
|
return SPEC_BY_ID.get(language)?.partialRefsReason;
|
|
1799
289
|
}
|
|
1800
290
|
|
|
291
|
+
// src/parser_types.ts
|
|
292
|
+
init_define_import_meta_env();
|
|
293
|
+
import * as fs from "node:fs";
|
|
294
|
+
import * as path from "node:path";
|
|
295
|
+
|
|
296
|
+
// src/languages/sniff.ts
|
|
297
|
+
init_define_import_meta_env();
|
|
298
|
+
var SNIFF_CHARS = 8192;
|
|
299
|
+
var ABL_MARKER_RES = [
|
|
300
|
+
/^&ANALYZE-SUSPEND\b/i,
|
|
301
|
+
/^&(?:SCOPED|GLOBAL)-DEFINE\s/i,
|
|
302
|
+
/^(?:ROUTINE|BLOCK)-LEVEL\s+ON\s+ERROR\s+UNDO\b/i,
|
|
303
|
+
/^DEF(?:INE)?\s+(?:NEW\s+)?(?:GLOBAL\s+)?(?:SHARED\s+)?(?:VAR|VARIABLE|TEMP-TABLE|BUFFER|QUERY|STREAM|DATASET|FRAME|(?:INPUT|OUTPUT|INPUT-OUTPUT)\s+PARAM(?:ETER)?)\s/i,
|
|
304
|
+
/^FUNCTION\s+[\w-]+\s+RETURNS\s/i,
|
|
305
|
+
/^FOR\s+EACH\s/i,
|
|
306
|
+
/^END\s+(?:PROCEDURE|FUNCTION|CLASS|INTERFACE|METHOD|CONSTRUCTOR)\s*\.$/i,
|
|
307
|
+
/^USING\s+[\w.*-]+(?:\s+FROM\s+(?:ASSEMBLY|PROPATH))?\s*\.$/i
|
|
308
|
+
];
|
|
309
|
+
var ABL_HEADER_RE = /^(?:PROCEDURE\s+[\w-]+|(?:CLASS|INTERFACE)\s+[\w.-]+)(?:\s|:)/i;
|
|
310
|
+
var ABL_SNIFF_CHARS = SNIFF_CHARS;
|
|
311
|
+
function isAblSource(content) {
|
|
312
|
+
const head = content.slice(0, ABL_SNIFF_CHARS);
|
|
313
|
+
if (head.includes("\0")) return false;
|
|
314
|
+
for (const raw of head.split(/\r?\n/)) {
|
|
315
|
+
const line = raw.trim();
|
|
316
|
+
if (line === "") continue;
|
|
317
|
+
if (ABL_MARKER_RES.some((re) => re.test(line))) return true;
|
|
318
|
+
if (ABL_HEADER_RE.test(line) && line.endsWith(":")) return true;
|
|
319
|
+
}
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
var SNIFF_FUNCTION_RE = /^function\b\s*(?:(?:\[[\w\s,~]*\]|[A-Za-z]\w*)\s*=\s*)?[A-Za-z]\w*(?:\.[A-Za-z]\w*)?\s*(?:\(|[%#;,]|$)/;
|
|
323
|
+
var SNIFF_CLASSDEF_RE = /^classdef\b\s*(?:\([^)]*\)\s*)?[A-Za-z]\w*\s*(?:<|[%#]|$)/;
|
|
324
|
+
function isMatlabSource(content) {
|
|
325
|
+
for (const raw of content.slice(0, SNIFF_CHARS).split("\n")) {
|
|
326
|
+
const line = raw.trim();
|
|
327
|
+
if (SNIFF_FUNCTION_RE.test(line) || SNIFF_CLASSDEF_RE.test(line)) return true;
|
|
328
|
+
}
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
function isObjcSource(content) {
|
|
332
|
+
return /^[ \t]*(?:#[ \t]*import[ \t]*[<"]|@(?:interface|implementation|protocol)\b)/m.test(content.slice(0, SNIFF_CHARS));
|
|
333
|
+
}
|
|
334
|
+
function isObjcHeader(content) {
|
|
335
|
+
return /^[ \t]*@(?:interface|protocol)\b/m.test(content.slice(0, SNIFF_CHARS));
|
|
336
|
+
}
|
|
337
|
+
function isPascalSource(content) {
|
|
338
|
+
const head = content.slice(0, SNIFF_CHARS);
|
|
339
|
+
let i = 0;
|
|
340
|
+
for (; ; ) {
|
|
341
|
+
while (i < head.length && /\s/.test(head[i])) i++;
|
|
342
|
+
if (head[i] === "{") {
|
|
343
|
+
const end = head.indexOf("}", i);
|
|
344
|
+
if (end < 0) return false;
|
|
345
|
+
i = end + 1;
|
|
346
|
+
} else if (head.startsWith("(*", i)) {
|
|
347
|
+
const end = head.indexOf("*)", i);
|
|
348
|
+
if (end < 0) return false;
|
|
349
|
+
i = end + 2;
|
|
350
|
+
} else if (head.startsWith("//", i)) {
|
|
351
|
+
const end = head.indexOf("\n", i);
|
|
352
|
+
if (end < 0) return false;
|
|
353
|
+
i = end + 1;
|
|
354
|
+
} else {
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return /^(?:unit|program|library)[ \t\r\n]+[A-Za-z_][\w.]*[ \t\r\n]*[;(]/i.test(head.slice(i, i + 300));
|
|
359
|
+
}
|
|
360
|
+
var PERL_MARKER_RE = /^(?:#!.*\bperl\b|[ \t]*use[ \t]+(?:strict|warnings|Test::More|Test2::V0|Test::Simple)\b|[ \t]*package[ \t]+[\w:]+[ \t]*;|[ \t]*my[ \t]+[$@%]|[ \t]*sub[ \t]+\w+[ \t]*\{)/m;
|
|
361
|
+
function isPerlSource(content) {
|
|
362
|
+
const head = content.slice(0, SNIFF_CHARS);
|
|
363
|
+
return PERL_MARKER_RE.test(head) && !/^[ \t]*use[ \t]+v6\b/m.test(head);
|
|
364
|
+
}
|
|
365
|
+
function isPrologSource(content) {
|
|
366
|
+
const head = content.slice(0, SNIFF_CHARS);
|
|
367
|
+
if (PERL_MARKER_RE.test(head)) return false;
|
|
368
|
+
return /^:-/m.test(head) || /^[a-z]\w*(?:\([^()\n]*\))?[ \t]*:-/m.test(head);
|
|
369
|
+
}
|
|
370
|
+
var LATEX_CLASS_MARKER_RE = /\\(?:ProvidesClass|documentclass)\b/;
|
|
371
|
+
function isLatexClassFile(content) {
|
|
372
|
+
return LATEX_CLASS_MARKER_RE.test(content.slice(0, SNIFF_CHARS));
|
|
373
|
+
}
|
|
374
|
+
|
|
1801
375
|
// src/parser_types.ts
|
|
1802
376
|
var DOTENV_VARIANT_RE = /^\.env(\..+)?$/;
|
|
1803
377
|
var VB6_HEADER_SCAN_LINES = 40;
|
|
@@ -1923,6 +497,56 @@ function redactIfDotenv(filePath, text) {
|
|
|
1923
497
|
return isDotenvPath(filePath) ? redactDotenvValues(text) : text;
|
|
1924
498
|
}
|
|
1925
499
|
|
|
500
|
+
// src/sql_path.ts
|
|
501
|
+
init_define_import_meta_env();
|
|
502
|
+
function pathEqClause(column) {
|
|
503
|
+
return isCaseInsensitiveFs() ? `TG_LOWER(${column}) = ?` : `${column} = ?`;
|
|
504
|
+
}
|
|
505
|
+
function pathSuffixClause(column) {
|
|
506
|
+
const col = isCaseInsensitiveFs() ? `TG_LOWER(${column})` : column;
|
|
507
|
+
return {
|
|
508
|
+
// Both separators are accepted because not every writer into `symbols` stores a normalizePath'd (forward-slash) file_path, and the JS-side path-boundary test this narrowing feeds treats `/` and `\` alike.
|
|
509
|
+
clause: `(${col} = ? OR substr(${col}, -length(?)) = ? OR substr(${col}, -length(?)) = ?)`,
|
|
510
|
+
params: (baseName) => {
|
|
511
|
+
const folded = foldPath(baseName);
|
|
512
|
+
return [folded, `/${folded}`, `/${folded}`, `\\${folded}`, `\\${folded}`];
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
function projectScopeClause(column) {
|
|
517
|
+
const caseInsensitive = isCaseInsensitiveFs();
|
|
518
|
+
const col = caseInsensitive ? `TG_LOWER(${column})` : column;
|
|
519
|
+
return {
|
|
520
|
+
// Parenthesised so an OR anywhere in the surrounding WHERE cannot bind tighter than the pair.
|
|
521
|
+
clause: `(${col} >= ? AND ${col} < ?)`,
|
|
522
|
+
params: (root) => {
|
|
523
|
+
const folded = caseInsensitive ? foldPath(normalizePath(root)) : normalizePath(root);
|
|
524
|
+
const lower = folded.endsWith("/") ? folded : `${folded}/`;
|
|
525
|
+
const upper = `${lower.slice(0, -1)}0`;
|
|
526
|
+
return [lower, upper];
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
function pathSpellings(filePath) {
|
|
531
|
+
const key = normalizePath(filePath);
|
|
532
|
+
if (!key.includes("/") && !key.includes("\\")) return [key];
|
|
533
|
+
const alt = key.includes("/") ? key.replace(/\//g, "\\") : key.replace(/\\/g, "/");
|
|
534
|
+
return [key, alt];
|
|
535
|
+
}
|
|
536
|
+
function filePathSpellingsClause(column, filePath) {
|
|
537
|
+
const params = pathSpellings(filePath).map(foldPath);
|
|
538
|
+
const clause = params.map(() => pathEqClause(column)).join(" OR ");
|
|
539
|
+
return { clause: params.length > 1 ? `(${clause})` : clause, params };
|
|
540
|
+
}
|
|
541
|
+
function fileRowByIndexKey(db, filePath, columns) {
|
|
542
|
+
const statement = db.prepare(`SELECT ${columns} FROM files WHERE ${pathEqClause("path")}`);
|
|
543
|
+
for (const spelling of pathSpellings(filePath)) {
|
|
544
|
+
const row = statement.get(foldPath(spelling));
|
|
545
|
+
if (row !== void 0) return row;
|
|
546
|
+
}
|
|
547
|
+
return void 0;
|
|
548
|
+
}
|
|
549
|
+
|
|
1926
550
|
// src/db.ts
|
|
1927
551
|
init_define_import_meta_env();
|
|
1928
552
|
import * as fs2 from "node:fs";
|
|
@@ -1976,7 +600,7 @@ CREATE INDEX IF NOT EXISTS idx_symbols_file ON symbols(file_path);
|
|
|
1976
600
|
CREATE INDEX IF NOT EXISTS idx_symbols_name_kind ON symbols(name, kind);
|
|
1977
601
|
CREATE INDEX IF NOT EXISTS idx_symbols_file_folded ON symbols(TG_LOWER(file_path));
|
|
1978
602
|
CREATE INDEX IF NOT EXISTS idx_symbols_file_name_folded ON symbols(TG_LOWER(file_path), name);
|
|
1979
|
-
-- Partial index backing checkSymbolBodySize (
|
|
603
|
+
-- Partial index backing checkSymbolBodySize (symbol_body_probe.ts), which every SessionStart hook runs.
|
|
1980
604
|
-- Its predicate cannot be served by any index above, so the check had to read the whole symbols
|
|
1981
605
|
-- table -- 226 MB / 231324 rows here, 229 ms per session start, and the early-exit LIMIT 1 never
|
|
1982
606
|
-- fires on a healthy index because there is nothing to find. Indexing the *violating* rows only
|
|
@@ -1984,7 +608,7 @@ CREATE INDEX IF NOT EXISTS idx_symbols_file_name_folded ON symbols(TG_LOWER(file
|
|
|
1984
608
|
-- ms, 4 KB on disk, and no measurable insert cost (-0.2%, within noise, over 40000 real rows),
|
|
1985
609
|
-- because SQLite evaluates the predicate and skips the b-tree write for every row under the cap.
|
|
1986
610
|
-- SQLite uses a partial index only where the query's WHERE implies the index's, so the probe in
|
|
1987
|
-
--
|
|
611
|
+
-- symbol_body_probe.ts spells its comparison the same way and against the same constant. That makes the
|
|
1988
612
|
-- threshold part of the stored schema -- see SYMBOL_BODY_CHAR_CAP in constants.ts for what
|
|
1989
613
|
-- changing it requires. A query with a lower threshold correctly gets a full scan instead, so no
|
|
1990
614
|
-- other reader can be served stale rows by this index.
|
|
@@ -2042,6 +666,12 @@ CREATE TABLE IF NOT EXISTS reconcile_cursor (
|
|
|
2042
666
|
updated_at REAL NOT NULL
|
|
2043
667
|
);
|
|
2044
668
|
|
|
669
|
+
-- Projects indexed on purpose, see indexed_roots.ts.
|
|
670
|
+
CREATE TABLE IF NOT EXISTS indexed_roots (
|
|
671
|
+
root TEXT PRIMARY KEY,
|
|
672
|
+
indexed_ms REAL NOT NULL
|
|
673
|
+
);
|
|
674
|
+
|
|
2045
675
|
-- Cross-cache full-text search index for 'token-goat recall' (recall_index.ts). One row
|
|
2046
676
|
-- per bash-output/web-output/mcp-output blob-store entry (see disk_cache.ts), refreshed
|
|
2047
677
|
-- in place (ON CONFLICT DO UPDATE) whenever storeBashOutput/storeWebOutput/storeMcpOutput
|
|
@@ -2080,7 +710,11 @@ CREATE INDEX IF NOT EXISTS idx_cache_recall_type ON cache_recall(cache_type);
|
|
|
2080
710
|
-- picked and averaging fabrications into a measured rate is how 174 of bash_redirect's 698 rows
|
|
2081
711
|
-- came to hold its efficacy down to 0.86% when the observed figure was 1.15%. calls_remaining is
|
|
2082
712
|
-- the countdown of subsequent tool-use events still eligible to resolve this row before it is
|
|
2083
|
-
-- considered timed out. displayed
|
|
713
|
+
-- considered timed out. A displayed, observable row with resolved=0 is pending: nothing has
|
|
714
|
+
-- scored it yet. Nothing sweeps these on a clock, so a session that ends mid-window leaves its
|
|
715
|
+
-- rows pending for good, and efficacy and suppression count only resolved rows -- counting a
|
|
716
|
+
-- pending one as not acted on is what muted bash_redirect at 1 in 11 when its scored rows stood
|
|
717
|
+
-- at 1 in 6. displayed=0 marks a detection that never reached the agent -- auto-
|
|
2084
718
|
-- suppressed, or declined by a hint's own net-benefit gate -- recorded so the ledger can answer
|
|
2085
719
|
-- how often a hint fired at all, which it previously could not: a suppressed detection left no
|
|
2086
720
|
-- trace, so a fully-muted category was indistinguishable from one that had stopped triggering.
|
|
@@ -2246,7 +880,7 @@ CREATE TRIGGER IF NOT EXISTS cache_recall_au AFTER UPDATE ON cache_recall BEGIN
|
|
|
2246
880
|
VALUES (new.row_id, new.label, new.content);
|
|
2247
881
|
END;
|
|
2248
882
|
`;
|
|
2249
|
-
var SCHEMA_VERSION =
|
|
883
|
+
var SCHEMA_VERSION = 17;
|
|
2250
884
|
function alterTableIdempotent(conn, sql) {
|
|
2251
885
|
try {
|
|
2252
886
|
conn.exec(sql);
|
|
@@ -2309,8 +943,19 @@ var MIGRATIONS = {
|
|
|
2309
943
|
conn.prepare("UPDATE hint_emissions SET observable = 0 WHERE correlator IS NULL").run();
|
|
2310
944
|
},
|
|
2311
945
|
// v15 -> v16: adds hint_emissions.displayed (see the SCHEMA_VERSION comment above for why). A pre-existing v15 database's `hint_emissions` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has it from SCHEMA_SQL's CREATE TABLE above, so the ALTER TABLE would fail with "duplicate column name" there -- swallow exactly that error and rethrow anything else, same pattern as v8 -> v9 / v9 -> v10 / v12 -> v13 / v14 -> v15 above. No backfill, unlike v14 -> v15: until this version a row was only ever written when a hint was actually shown, so the column's own DEFAULT 1 is already the truth for every existing row, and an UPDATE would be a no-op dressed up as a migration step.
|
|
2312
|
-
15: (conn) => alterTableIdempotent(conn, "ALTER TABLE hint_emissions ADD COLUMN displayed INTEGER NOT NULL DEFAULT 1")
|
|
946
|
+
15: (conn) => alterTableIdempotent(conn, "ALTER TABLE hint_emissions ADD COLUMN displayed INTEGER NOT NULL DEFAULT 1"),
|
|
947
|
+
// v16 -> v17: backfills indexed_roots.
|
|
948
|
+
16: backfillIndexedRoots
|
|
2313
949
|
};
|
|
950
|
+
function backfillIndexedRoots(conn) {
|
|
951
|
+
const scope = projectScopeClause("file_path");
|
|
952
|
+
const hasSymbols = conn.prepare(`SELECT 1 FROM symbols WHERE ${scope.clause} LIMIT 1`);
|
|
953
|
+
const insert = conn.prepare("INSERT OR IGNORE INTO indexed_roots (root, indexed_ms) VALUES (?, ?)");
|
|
954
|
+
const roots = conn.prepare("SELECT root, last_seen_ms FROM known_roots").all();
|
|
955
|
+
for (const { root, last_seen_ms } of roots) {
|
|
956
|
+
if (hasSymbols.get(...scope.params(root)) !== void 0) insert.run(normalizePath(root), last_seen_ms);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
2314
959
|
function runMigrations(conn, fromVersion, toVersion) {
|
|
2315
960
|
for (let v = fromVersion; v < toVersion; v++) {
|
|
2316
961
|
MIGRATIONS[v]?.(conn);
|
|
@@ -2344,9 +989,18 @@ function isDamagedDatabaseError(e) {
|
|
|
2344
989
|
function walSwitchError(lastError) {
|
|
2345
990
|
return new Error(`db: failed to enable WAL mode (${lastError instanceof Error ? lastError.message : String(lastError)})`, { cause: lastError });
|
|
2346
991
|
}
|
|
992
|
+
var HOOK_DB_WAIT_MS = 250;
|
|
993
|
+
var _hookWaits = false;
|
|
994
|
+
function limitDbWaitsForHook(on = true) {
|
|
995
|
+
_hookWaits = on;
|
|
996
|
+
}
|
|
997
|
+
function connectionWaitBudgets() {
|
|
998
|
+
return _hookWaits ? { busyMs: HOOK_DB_WAIT_MS, walSwitchMs: HOOK_DB_WAIT_MS } : { busyMs: 15e3, walSwitchMs: WAL_SWITCH_DEADLINE_MS };
|
|
999
|
+
}
|
|
2347
1000
|
function initConnection(conn, walStopOn) {
|
|
2348
|
-
|
|
2349
|
-
|
|
1001
|
+
const waits = connectionWaitBudgets();
|
|
1002
|
+
conn.pragma(`busy_timeout = ${waits.busyMs}`);
|
|
1003
|
+
enableWalWithRetry(conn, waits.walSwitchMs, walStopOn);
|
|
2350
1004
|
conn.pragma("synchronous = NORMAL");
|
|
2351
1005
|
conn.pragma("cache_size = -32000");
|
|
2352
1006
|
conn.pragma("temp_store = MEMORY");
|
|
@@ -2403,7 +1057,7 @@ function allowReadOnlyIndex(onFirstUse) {
|
|
|
2403
1057
|
function isReadOnlyDb(dbPath) {
|
|
2404
1058
|
if (_readOnlyFallback === void 0) return false;
|
|
2405
1059
|
try {
|
|
2406
|
-
getDb(dbPath);
|
|
1060
|
+
getDb(dbPath, { create: false });
|
|
2407
1061
|
} catch {
|
|
2408
1062
|
return false;
|
|
2409
1063
|
}
|
|
@@ -2428,10 +1082,10 @@ function writeRefusal(resolved) {
|
|
|
2428
1082
|
fs2.closeSync(fd);
|
|
2429
1083
|
return void 0;
|
|
2430
1084
|
}
|
|
2431
|
-
function openReadOnlyAt(resolved, immutable) {
|
|
1085
|
+
function openReadOnlyAt(resolved, immutable, busyTimeoutMs = 15e3) {
|
|
2432
1086
|
const conn = new Database(resolved, { readonly: true, fileMustExist: true, immutable });
|
|
2433
1087
|
try {
|
|
2434
|
-
conn.pragma(
|
|
1088
|
+
conn.pragma(`busy_timeout = ${busyTimeoutMs}`);
|
|
2435
1089
|
return { conn, storedVersion: Number(conn.pragma("user_version", { simple: true })) };
|
|
2436
1090
|
} catch (e) {
|
|
2437
1091
|
try {
|
|
@@ -2477,10 +1131,54 @@ function connectionKey(dbPath) {
|
|
|
2477
1131
|
const resolved = resolveDbPath(dbPath);
|
|
2478
1132
|
return { resolved, key: foldPath(resolved) };
|
|
2479
1133
|
}
|
|
2480
|
-
|
|
1134
|
+
var PROBE_BUSY_TIMEOUT_MS = 250;
|
|
1135
|
+
function withProbeIndex(fn, dbPath) {
|
|
1136
|
+
const resolved = resolveDbPath(dbPath ?? globalDbPath());
|
|
1137
|
+
if (!fs2.existsSync(resolved)) return null;
|
|
1138
|
+
let conn = null;
|
|
1139
|
+
try {
|
|
1140
|
+
let opened;
|
|
1141
|
+
try {
|
|
1142
|
+
opened = openReadOnlyAt(resolved, false, PROBE_BUSY_TIMEOUT_MS);
|
|
1143
|
+
} catch (e) {
|
|
1144
|
+
if (!isWriteAccessError(e)) throw e;
|
|
1145
|
+
opened = openReadOnlyAt(resolved, true, PROBE_BUSY_TIMEOUT_MS);
|
|
1146
|
+
}
|
|
1147
|
+
conn = opened.conn;
|
|
1148
|
+
if (opened.storedVersion !== SCHEMA_VERSION) return null;
|
|
1149
|
+
registerTgLower(conn);
|
|
1150
|
+
return fn(conn);
|
|
1151
|
+
} catch {
|
|
1152
|
+
return null;
|
|
1153
|
+
} finally {
|
|
1154
|
+
if (conn) {
|
|
1155
|
+
try {
|
|
1156
|
+
conn.close();
|
|
1157
|
+
} catch {
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
var _emptyIndex;
|
|
1163
|
+
function getReadDb(dbPath) {
|
|
1164
|
+
return getDb(dbPath, { create: false });
|
|
1165
|
+
}
|
|
1166
|
+
function getDb(dbPath, opts = {}) {
|
|
2481
1167
|
const { resolved, key } = connectionKey(dbPath);
|
|
2482
1168
|
const existing = _connections.get(key);
|
|
2483
1169
|
if (existing !== void 0) return existing;
|
|
1170
|
+
if (opts.create === false && !fs2.existsSync(resolved)) {
|
|
1171
|
+
if (_emptyIndex === void 0) {
|
|
1172
|
+
_emptyIndex = new Database(":memory:");
|
|
1173
|
+
registerTgLower(_emptyIndex);
|
|
1174
|
+
_emptyIndex.exec(SCHEMA_SQL);
|
|
1175
|
+
try {
|
|
1176
|
+
_emptyIndex.exec(FTS_SQL);
|
|
1177
|
+
} catch {
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
return _emptyIndex;
|
|
1181
|
+
}
|
|
2484
1182
|
const fallback = _readOnlyFallback;
|
|
2485
1183
|
if (fallback !== void 0) {
|
|
2486
1184
|
const readOnly = _readOnlyConnections.get(key);
|
|
@@ -2523,7 +1221,24 @@ function openReadOnlyFallback(resolved, key, fallback, writeError) {
|
|
|
2523
1221
|
}
|
|
2524
1222
|
return conn;
|
|
2525
1223
|
}
|
|
1224
|
+
function closeDb(dbPath) {
|
|
1225
|
+
const { key } = connectionKey(dbPath);
|
|
1226
|
+
for (const cache of [_connections, _readOnlyConnections]) {
|
|
1227
|
+
const conn = cache.get(key);
|
|
1228
|
+
if (conn === void 0) continue;
|
|
1229
|
+
try {
|
|
1230
|
+
conn.close();
|
|
1231
|
+
} catch {
|
|
1232
|
+
}
|
|
1233
|
+
cache.delete(key);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
2526
1236
|
function closeAllDbs() {
|
|
1237
|
+
try {
|
|
1238
|
+
_emptyIndex?.close();
|
|
1239
|
+
} catch {
|
|
1240
|
+
}
|
|
1241
|
+
_emptyIndex = void 0;
|
|
2527
1242
|
for (const cache of [_connections, _readOnlyConnections]) {
|
|
2528
1243
|
for (const conn of cache.values()) {
|
|
2529
1244
|
try {
|
|
@@ -2538,37 +1253,11 @@ registerReset(closeAllDbs, { perRequest: true });
|
|
|
2538
1253
|
registerReset(() => {
|
|
2539
1254
|
_readOnlyFallback = void 0;
|
|
2540
1255
|
}, { perRequest: true });
|
|
1256
|
+
registerReset(() => {
|
|
1257
|
+
_hookWaits = false;
|
|
1258
|
+
}, { perRequest: true });
|
|
2541
1259
|
|
|
2542
1260
|
export {
|
|
2543
|
-
precedingDocComment,
|
|
2544
|
-
buildLineIndex,
|
|
2545
|
-
offsetToLine,
|
|
2546
|
-
lineTextAt,
|
|
2547
|
-
stripCstyleComments,
|
|
2548
|
-
stripXmlComments,
|
|
2549
|
-
scanQuotedStringEnd,
|
|
2550
|
-
stripJsComments,
|
|
2551
|
-
stripHashComments,
|
|
2552
|
-
maskHtmlNoise,
|
|
2553
|
-
findHtmlHeadingMatches,
|
|
2554
|
-
isInsideStringLiteral,
|
|
2555
|
-
stripBlockCommentSpan,
|
|
2556
|
-
stripNestedBlockCommentSpan,
|
|
2557
|
-
stripLineComment,
|
|
2558
|
-
stripStringLiterals,
|
|
2559
|
-
matchRRawOpener,
|
|
2560
|
-
matchGroovySlashy,
|
|
2561
|
-
matchBashHeredocOpener,
|
|
2562
|
-
stripMultilineStringSpan,
|
|
2563
|
-
makeSpanSymbol,
|
|
2564
|
-
makeLineSymbol,
|
|
2565
|
-
makeSymbolEmitter,
|
|
2566
|
-
assignFlatEndLines,
|
|
2567
|
-
propagateEndLinesToSymbols,
|
|
2568
|
-
findMatchingBraceEndLine,
|
|
2569
|
-
assignBraceBlockSpans,
|
|
2570
|
-
lastContentLine,
|
|
2571
|
-
GENERIC_CLAUSE,
|
|
2572
1261
|
extractIni,
|
|
2573
1262
|
_lineClosesQuote,
|
|
2574
1263
|
_detectOpenQuote,
|
|
@@ -2594,7 +1283,16 @@ export {
|
|
|
2594
1283
|
unsupportedLanguageName,
|
|
2595
1284
|
isDotenvPath,
|
|
2596
1285
|
redactIfDotenv,
|
|
1286
|
+
pathEqClause,
|
|
1287
|
+
pathSuffixClause,
|
|
1288
|
+
projectScopeClause,
|
|
1289
|
+
filePathSpellingsClause,
|
|
1290
|
+
fileRowByIndexKey,
|
|
1291
|
+
limitDbWaitsForHook,
|
|
2597
1292
|
allowReadOnlyIndex,
|
|
2598
1293
|
isReadOnlyDb,
|
|
2599
|
-
|
|
1294
|
+
withProbeIndex,
|
|
1295
|
+
getReadDb,
|
|
1296
|
+
getDb,
|
|
1297
|
+
closeDb
|
|
2600
1298
|
};
|