token-goat 2.6.32 → 2.6.33
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 +20 -1
- package/dist/{token-goat-chunk-W3MX4LQV.mjs → token-goat-chunk-72R7M5H7.mjs} +6 -9
- package/dist/{token-goat-chunk-DNEPSN3P.mjs → token-goat-chunk-77CX3MCN.mjs} +4 -7
- package/dist/token-goat-chunk-AEX54RUZ.mjs +11 -0
- package/dist/{token-goat-chunk-3KW5C2KQ.mjs → token-goat-chunk-AO2QD2AG.mjs} +0 -4
- package/dist/{token-goat-hook-chunk-TKXOXN4J.mjs → token-goat-chunk-DG53MVNJ.mjs} +2 -98
- package/dist/{token-goat-chunk-N53GXI2Z.mjs → token-goat-chunk-FN6WLFIX.mjs} +14 -32
- package/dist/{token-goat-chunk-YWYITDOS.mjs → token-goat-chunk-G6XLWJWI.mjs} +2 -5
- package/dist/{token-goat-chunk-TBCLQTPG.mjs → token-goat-chunk-HPWPUBAK.mjs} +7 -7
- package/dist/{token-goat-chunk-DFBD2FFU.mjs → token-goat-chunk-L6FVTDPD.mjs} +9 -121
- package/dist/{token-goat-chunk-O7TGKV5I.mjs → token-goat-chunk-OHQ7RBLL.mjs} +23 -24
- package/dist/{token-goat-chunk-RD6O3PJU.mjs → token-goat-chunk-RPOXYJWK.mjs} +3642 -3329
- package/dist/{token-goat-chunk-GWZJ5SI2.mjs → token-goat-chunk-RQQ4SY2P.mjs} +1 -31
- package/dist/{token-goat-chunk-X5OPORR4.mjs → token-goat-chunk-TDYTBCT4.mjs} +1031 -1784
- package/dist/{token-goat-chunk-5EXIMDHA.mjs → token-goat-chunk-WFRR2DBG.mjs} +1131 -51
- package/dist/{token-goat-hook-chunk-UXD3B4OY.mjs → token-goat-hook-chunk-26DLRODR.mjs} +4 -7
- package/dist/{token-goat-chunk-4M7PSAO3.mjs → token-goat-hook-chunk-3QYSN4QV.mjs} +2 -98
- package/dist/{token-goat-hook-chunk-J2ZK2FYW.mjs → token-goat-hook-chunk-BUOCULAM.mjs} +0 -4
- package/dist/{token-goat-hook-chunk-DHW6SRHR.mjs → token-goat-hook-chunk-E6AIPKNF.mjs} +1131 -51
- package/dist/{token-goat-hook-chunk-TBJ5PUPQ.mjs → token-goat-hook-chunk-EKGDLI4D.mjs} +6 -9
- package/dist/{token-goat-hook-chunk-VHZECEQD.mjs → token-goat-hook-chunk-HXHFLKEL.mjs} +1 -31
- package/dist/{token-goat-hook-chunk-DJZGX27J.mjs → token-goat-hook-chunk-QD2DX2U7.mjs} +7 -120
- package/dist/token-goat-hook-chunk-RFRLWOQH.mjs +11 -0
- package/dist/{token-goat-hook-chunk-WBTHUYJP.mjs → token-goat-hook-chunk-UWV4MTYI.mjs} +1039 -1790
- package/dist/{token-goat-hook-chunk-Q5URQRIF.mjs → token-goat-hook-chunk-VDXQXYJK.mjs} +14 -32
- package/dist/{token-goat-hook-chunk-6NF4WM2U.mjs → token-goat-hook-chunk-WBBHV6TZ.mjs} +3643 -3330
- package/dist/token-goat-hook-chunk-XBOWDNJB.mjs +23 -0
- package/dist/{token-goat-hook-chunk-PCP4W65Z.mjs → token-goat-hook-chunk-XUMIVYEN.mjs} +2 -5
- package/dist/{token-goat-hook-chunk-LFYT4DLB.mjs → token-goat-hook-chunk-ZT47M3IA.mjs} +23 -24
- package/dist/token-goat-hook.mjs +7 -12
- package/dist/token-goat.core.mjs +7 -10
- package/package.json +13 -33
- package/dist/token-goat-chunk-3UOG7PSZ.mjs +0 -63
- package/dist/token-goat-hook-chunk-ANFXTEQO.mjs +0 -23
- package/dist/token-goat-hook-chunk-K33JMLL7.mjs +0 -63
|
@@ -2,17 +2,13 @@ import { createRequire as __cjsRequire } from 'node:module';
|
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
registerReset
|
|
5
|
-
} from "./token-goat-hook-chunk-
|
|
6
|
-
import {
|
|
7
|
-
init_define_import_meta_env
|
|
8
|
-
} from "./token-goat-hook-chunk-K33JMLL7.mjs";
|
|
5
|
+
} from "./token-goat-hook-chunk-BUOCULAM.mjs";
|
|
9
6
|
|
|
10
7
|
// src/version.ts
|
|
11
|
-
init_define_import_meta_env();
|
|
12
8
|
import { createRequire } from "node:module";
|
|
13
9
|
function resolveVersion() {
|
|
14
10
|
if (true) {
|
|
15
|
-
return "2.6.
|
|
11
|
+
return "2.6.33";
|
|
16
12
|
}
|
|
17
13
|
const require2 = createRequire(import.meta.url);
|
|
18
14
|
const pkg = require2("../package.json");
|
|
@@ -21,7 +17,6 @@ function resolveVersion() {
|
|
|
21
17
|
var VERSION = resolveVersion();
|
|
22
18
|
|
|
23
19
|
// src/constants.ts
|
|
24
|
-
init_define_import_meta_env();
|
|
25
20
|
import * as fs from "node:fs";
|
|
26
21
|
import * as os from "node:os";
|
|
27
22
|
import * as path from "node:path";
|
|
@@ -137,7 +132,6 @@ var ENV_KEYS = {
|
|
|
137
132
|
var SYMBOL_BODY_CHAR_CAP = 128 * 1024;
|
|
138
133
|
|
|
139
134
|
// src/bridges/registry.ts
|
|
140
|
-
init_define_import_meta_env();
|
|
141
135
|
var KNOWN_HARNESS_NAMES = /* @__PURE__ */ new Set([
|
|
142
136
|
"claudecode",
|
|
143
137
|
"codex",
|
|
@@ -149,6 +143,7 @@ var KNOWN_HARNESS_NAMES = /* @__PURE__ */ new Set([
|
|
|
149
143
|
"copilot_cli",
|
|
150
144
|
"grok",
|
|
151
145
|
"qwen",
|
|
146
|
+
"kimi",
|
|
152
147
|
"generic"
|
|
153
148
|
]);
|
|
154
149
|
function detectHarness() {
|
|
@@ -199,7 +194,6 @@ function resetHarnessCache() {
|
|
|
199
194
|
registerReset(resetHarnessCache);
|
|
200
195
|
|
|
201
196
|
// src/paths.ts
|
|
202
|
-
init_define_import_meta_env();
|
|
203
197
|
import * as fs2 from "node:fs";
|
|
204
198
|
import * as path2 from "node:path";
|
|
205
199
|
var WSL_PATH_RE = /^\/mnt\/([a-zA-Z])\/(.*)$/s;
|
|
@@ -296,7 +290,6 @@ function safeJoin(base, ...parts) {
|
|
|
296
290
|
}
|
|
297
291
|
|
|
298
292
|
// src/util.ts
|
|
299
|
-
init_define_import_meta_env();
|
|
300
293
|
import { spawn, spawnSync } from "node:child_process";
|
|
301
294
|
import { chmodSync as chmodSync2, closeSync, copyFileSync, existsSync, mkdirSync as mkdirSync2, openSync, readdirSync, readFileSync, renameSync, statSync as statSync2, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
302
295
|
import * as path3 from "node:path";
|
|
@@ -910,7 +903,6 @@ function suggestPackageNames(query, names) {
|
|
|
910
903
|
}
|
|
911
904
|
|
|
912
905
|
// src/fingerprint.ts
|
|
913
|
-
init_define_import_meta_env();
|
|
914
906
|
import { createHash } from "node:crypto";
|
|
915
907
|
import * as fs3 from "node:fs";
|
|
916
908
|
function fingerprintContent(content) {
|
|
@@ -932,7 +924,6 @@ function fingerprintFile(filePath) {
|
|
|
932
924
|
}
|
|
933
925
|
|
|
934
926
|
// src/project.ts
|
|
935
|
-
init_define_import_meta_env();
|
|
936
927
|
import * as fs4 from "node:fs";
|
|
937
928
|
import * as os2 from "node:os";
|
|
938
929
|
import * as path4 from "node:path";
|
|
@@ -1146,24 +1137,10 @@ function isInsideRoot(target, root) {
|
|
|
1146
1137
|
}
|
|
1147
1138
|
|
|
1148
1139
|
// src/config.ts
|
|
1149
|
-
init_define_import_meta_env();
|
|
1150
1140
|
import * as fs5 from "node:fs";
|
|
1151
1141
|
import * as path5 from "node:path";
|
|
1152
1142
|
|
|
1153
|
-
// node_modules/smol-toml/dist/index.js
|
|
1154
|
-
init_define_import_meta_env();
|
|
1155
|
-
|
|
1156
|
-
// node_modules/smol-toml/dist/parse.js
|
|
1157
|
-
init_define_import_meta_env();
|
|
1158
|
-
|
|
1159
|
-
// node_modules/smol-toml/dist/struct.js
|
|
1160
|
-
init_define_import_meta_env();
|
|
1161
|
-
|
|
1162
|
-
// node_modules/smol-toml/dist/primitive.js
|
|
1163
|
-
init_define_import_meta_env();
|
|
1164
|
-
|
|
1165
1143
|
// node_modules/smol-toml/dist/date.js
|
|
1166
|
-
init_define_import_meta_env();
|
|
1167
1144
|
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
|
|
1168
1145
|
var TomlDate = class _TomlDate extends Date {
|
|
1169
1146
|
#hasDate = false;
|
|
@@ -1256,7 +1233,6 @@ var TomlDate = class _TomlDate extends Date {
|
|
|
1256
1233
|
};
|
|
1257
1234
|
|
|
1258
1235
|
// node_modules/smol-toml/dist/error.js
|
|
1259
|
-
init_define_import_meta_env();
|
|
1260
1236
|
function getLineColFromPtr(string, ptr) {
|
|
1261
1237
|
let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
|
|
1262
1238
|
return [lines.length, lines.pop().length + 1];
|
|
@@ -1455,11 +1431,7 @@ function parseValue(value, toml, ptr, integersAsBigInt) {
|
|
|
1455
1431
|
return date;
|
|
1456
1432
|
}
|
|
1457
1433
|
|
|
1458
|
-
// node_modules/smol-toml/dist/extract.js
|
|
1459
|
-
init_define_import_meta_env();
|
|
1460
|
-
|
|
1461
1434
|
// node_modules/smol-toml/dist/util.js
|
|
1462
|
-
init_define_import_meta_env();
|
|
1463
1435
|
function indexOfNewline(str, start = 0, end = str.length) {
|
|
1464
1436
|
let idx = str.indexOf("\n", start);
|
|
1465
1437
|
if (str[idx - 1] === "\r")
|
|
@@ -1849,7 +1821,6 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
|
1849
1821
|
}
|
|
1850
1822
|
|
|
1851
1823
|
// node_modules/smol-toml/dist/stringify.js
|
|
1852
|
-
init_define_import_meta_env();
|
|
1853
1824
|
var BARE_KEY = /^[a-z0-9-_]+$/i;
|
|
1854
1825
|
function extendedTypeOf(obj) {
|
|
1855
1826
|
let type = typeof obj;
|
|
@@ -1991,7 +1962,6 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
|
1991
1962
|
}
|
|
1992
1963
|
|
|
1993
1964
|
// src/env.ts
|
|
1994
|
-
init_define_import_meta_env();
|
|
1995
1965
|
var FALSY_ENV_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "off"]);
|
|
1996
1966
|
var TRUTHY_ENV_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
|
|
1997
1967
|
function envStr(key, defaultVal) {
|
|
@@ -3235,11 +3205,1051 @@ function saveConfig(config) {
|
|
|
3235
3205
|
_cached2 = null;
|
|
3236
3206
|
}
|
|
3237
3207
|
|
|
3208
|
+
// src/parser_types.ts
|
|
3209
|
+
import * as path6 from "node:path";
|
|
3210
|
+
var EXTENSION_LANGUAGE = /* @__PURE__ */ new Map([
|
|
3211
|
+
[".py", "python"],
|
|
3212
|
+
[".pyi", "python"],
|
|
3213
|
+
[".ts", "typescript"],
|
|
3214
|
+
[".tsx", "typescript"],
|
|
3215
|
+
[".mts", "typescript"],
|
|
3216
|
+
[".cts", "typescript"],
|
|
3217
|
+
[".js", "javascript"],
|
|
3218
|
+
[".jsx", "javascript"],
|
|
3219
|
+
[".mjs", "javascript"],
|
|
3220
|
+
[".cjs", "javascript"],
|
|
3221
|
+
[".rs", "rust"],
|
|
3222
|
+
[".go", "go"],
|
|
3223
|
+
[".c", "c"],
|
|
3224
|
+
[".h", "c"],
|
|
3225
|
+
[".cpp", "cpp"],
|
|
3226
|
+
[".cc", "cpp"],
|
|
3227
|
+
[".cxx", "cpp"],
|
|
3228
|
+
[".hpp", "cpp"],
|
|
3229
|
+
[".hxx", "cpp"],
|
|
3230
|
+
[".rb", "ruby"],
|
|
3231
|
+
[".ruby", "ruby"],
|
|
3232
|
+
// Rake task files (lib/tasks/foo.rake) are plain Ruby syntax (`task :foo do ... end`),
|
|
3233
|
+
// parsed identically by the ruby tree-sitter grammar. Without this entry a `.rake` file
|
|
3234
|
+
// fell through to 'unknown' and indexed zero symbols despite the grammar handling its
|
|
3235
|
+
// content exactly like any other .rb file -- the same has-extractor-but-no-extension gap
|
|
3236
|
+
// previously fixed for `.mk` (Makefile fragments).
|
|
3237
|
+
[".rake", "ruby"],
|
|
3238
|
+
[".java", "java"],
|
|
3239
|
+
[".sh", "bash"],
|
|
3240
|
+
[".bash", "bash"],
|
|
3241
|
+
[".md", "markdown"],
|
|
3242
|
+
[".markdown", "markdown"],
|
|
3243
|
+
// MDX heading syntax is plain ATX and works with the existing markdown extractor as-is,
|
|
3244
|
+
// unlike .rst which genuinely needs an underline-style heading parser this extractor doesn't
|
|
3245
|
+
// implement (left as 'unknown' deliberately).
|
|
3246
|
+
[".mdx", "markdown"],
|
|
3247
|
+
[".toml", "toml"],
|
|
3248
|
+
[".json", "json"],
|
|
3249
|
+
[".yaml", "yaml"],
|
|
3250
|
+
[".yml", "yaml"],
|
|
3251
|
+
[".css", "css"],
|
|
3252
|
+
[".scss", "css"],
|
|
3253
|
+
[".sass", "css"],
|
|
3254
|
+
[".less", "css"],
|
|
3255
|
+
[".cs", "csharp"],
|
|
3256
|
+
[".php", "php"],
|
|
3257
|
+
[".html", "html"],
|
|
3258
|
+
[".htm", "html"],
|
|
3259
|
+
[".liquid", "liquid"],
|
|
3260
|
+
[".kt", "kotlin"],
|
|
3261
|
+
[".kts", "kotlin"],
|
|
3262
|
+
[".swift", "swift"],
|
|
3263
|
+
[".scala", "scala"],
|
|
3264
|
+
[".sc", "scala"],
|
|
3265
|
+
[".lua", "lua"],
|
|
3266
|
+
[".ex", "elixir"],
|
|
3267
|
+
[".exs", "elixir"],
|
|
3268
|
+
[".dart", "dart"],
|
|
3269
|
+
[".zig", "zig"],
|
|
3270
|
+
[".r", "r"],
|
|
3271
|
+
[".graphql", "graphql"],
|
|
3272
|
+
[".gql", "graphql"],
|
|
3273
|
+
[".sql", "sql"],
|
|
3274
|
+
[".ini", "ini"],
|
|
3275
|
+
[".cfg", "ini"],
|
|
3276
|
+
[".conf", "ini"],
|
|
3277
|
+
[".proto", "proto"],
|
|
3278
|
+
// `.mk` is the idiomatic extension for included Makefile fragments (config.mk, rules.mk,
|
|
3279
|
+
// common.mk); their syntax is identical to a bare `Makefile`, which FILENAME_LANGUAGE already
|
|
3280
|
+
// maps. Without this entry a `.mk` fragment fell through to 'unknown' and was indexed with zero
|
|
3281
|
+
// symbols despite extractMakefile handling its content fine -- the same has-extractor-but-no-
|
|
3282
|
+
// extension gap previously seen for other adapters. (importsExtensionFor already treats bare
|
|
3283
|
+
// Makefile basenames as `.mk` for the imports command, so extractImports' `.mk` branch was
|
|
3284
|
+
// reachable while symbol indexing was not.)
|
|
3285
|
+
[".mk", "makefile"],
|
|
3286
|
+
[".tf", "terraform"],
|
|
3287
|
+
[".tfvars", "terraform"],
|
|
3288
|
+
[".hcl", "terraform"],
|
|
3289
|
+
[".ps1", "powershell"],
|
|
3290
|
+
[".psm1", "powershell"],
|
|
3291
|
+
[".env", "env_file"],
|
|
3292
|
+
[".cls", "apex"],
|
|
3293
|
+
[".trigger", "apex"],
|
|
3294
|
+
[".cmp", "salesforce_markup"],
|
|
3295
|
+
[".app", "salesforce_markup"],
|
|
3296
|
+
[".evt", "salesforce_markup"],
|
|
3297
|
+
[".intf", "salesforce_markup"],
|
|
3298
|
+
[".design", "salesforce_markup"],
|
|
3299
|
+
[".auradoc", "salesforce_markup"],
|
|
3300
|
+
[".tokens", "salesforce_markup"],
|
|
3301
|
+
[".page", "salesforce_markup"],
|
|
3302
|
+
[".component", "salesforce_markup"],
|
|
3303
|
+
[".email", "salesforce_markup"],
|
|
3304
|
+
[".vue", "vue"],
|
|
3305
|
+
[".svelte", "svelte"],
|
|
3306
|
+
[".astro", "astro"],
|
|
3307
|
+
[".ipynb", "ipynb"]
|
|
3308
|
+
]);
|
|
3309
|
+
var FILENAME_LANGUAGE = /* @__PURE__ */ new Map([
|
|
3310
|
+
["dockerfile", "dockerfile"],
|
|
3311
|
+
["makefile", "makefile"],
|
|
3312
|
+
["gnumakefile", "makefile"],
|
|
3313
|
+
["bsdmakefile", "makefile"],
|
|
3314
|
+
["cargo.toml", "toml"],
|
|
3315
|
+
["pyproject.toml", "toml"],
|
|
3316
|
+
["package.json", "json"],
|
|
3317
|
+
["tsconfig.json", "json"],
|
|
3318
|
+
[".envrc", "env_file"],
|
|
3319
|
+
// Gemfile and Rakefile are plain Ruby syntax with no extension -- the dominant, idiomatic
|
|
3320
|
+
// dependency-manifest and task-runner files in virtually every real Ruby project (analogous to
|
|
3321
|
+
// package.json for Node or a bare Makefile). Without these entries both fell through to
|
|
3322
|
+
// 'unknown' and indexed zero symbols despite the ruby tree-sitter grammar handling their
|
|
3323
|
+
// content exactly like any other .rb file -- the same has-extractor-but-no-dispatch-entry gap
|
|
3324
|
+
// already fixed for bare `Makefile` / `.mk` fragments above.
|
|
3325
|
+
["gemfile", "ruby"],
|
|
3326
|
+
["rakefile", "ruby"],
|
|
3327
|
+
// Vagrantfile, Guardfile, Podfile, Capfile, Fastfile: same idiomatic extensionless-Ruby-DSL
|
|
3328
|
+
// pattern as Gemfile/Rakefile above -- `Vagrant.configure(...) do ... end`, Guard's `guard
|
|
3329
|
+
// 'rspec' do ... end`, CocoaPods' `Pod::Spec.new do |s| ... end`, Capistrano's `set :application`,
|
|
3330
|
+
// and fastlane's `lane :build do ... end` are all plain Ruby, parsed identically by the ruby
|
|
3331
|
+
// tree-sitter grammar. Without these entries each fell through to 'unknown' and indexed zero
|
|
3332
|
+
// symbols despite the grammar handling their content exactly like any other .rb file.
|
|
3333
|
+
["vagrantfile", "ruby"],
|
|
3334
|
+
["guardfile", "ruby"],
|
|
3335
|
+
["podfile", "ruby"],
|
|
3336
|
+
["capfile", "ruby"],
|
|
3337
|
+
["fastfile", "ruby"],
|
|
3338
|
+
// Brewfile: Homebrew Bundle's dependency manifest (`brew "wget"`, `cask "..."`, `tap "..."`)
|
|
3339
|
+
// is ordinary Ruby method-call syntax, evaluated by Homebrew's own Ruby DSL -- the extensionless
|
|
3340
|
+
// macOS-dev-environment analogue of Gemfile/package.json, and near-universal in dotfiles repos
|
|
3341
|
+
// that use `brew bundle dump`/`brew bundle install`. Same has-extractor-but-no-dispatch-entry
|
|
3342
|
+
// gap as the other extensionless Ruby DSL files above: without this entry it fell through to
|
|
3343
|
+
// 'unknown' and indexed zero symbols despite the ruby tree-sitter grammar handling its content
|
|
3344
|
+
// exactly like any other .rb file.
|
|
3345
|
+
["brewfile", "ruby"]
|
|
3346
|
+
]);
|
|
3347
|
+
var DOTENV_VARIANT_RE = /^\.env(\..+)?$/;
|
|
3348
|
+
function detectLanguage(filePath) {
|
|
3349
|
+
const base = path6.basename(filePath).toLowerCase();
|
|
3350
|
+
if (DOTENV_VARIANT_RE.test(base)) return "env_file";
|
|
3351
|
+
const byName = FILENAME_LANGUAGE.get(base);
|
|
3352
|
+
if (byName !== void 0) return byName;
|
|
3353
|
+
if (base.endsWith("-meta.xml")) {
|
|
3354
|
+
return "salesforce_metadata";
|
|
3355
|
+
}
|
|
3356
|
+
const ext = path6.extname(base).toLowerCase();
|
|
3357
|
+
return EXTENSION_LANGUAGE.get(ext) ?? "unknown";
|
|
3358
|
+
}
|
|
3359
|
+
var UNSUPPORTED_LANGUAGE_EXTENSIONS = /* @__PURE__ */ new Map([]);
|
|
3360
|
+
function unsupportedLanguageName(filePath) {
|
|
3361
|
+
const ext = path6.extname(filePath).toLowerCase();
|
|
3362
|
+
return UNSUPPORTED_LANGUAGE_EXTENSIONS.get(ext);
|
|
3363
|
+
}
|
|
3364
|
+
|
|
3365
|
+
// src/doc_comment.ts
|
|
3366
|
+
function precedingDocComment(lines, lineStart, style) {
|
|
3367
|
+
const aboveIdx = lineStart - 2;
|
|
3368
|
+
if (aboveIdx < 0 || aboveIdx >= lines.length) return "";
|
|
3369
|
+
const aboveLine = lines[aboveIdx];
|
|
3370
|
+
if (aboveLine === void 0) return "";
|
|
3371
|
+
const aboveTrimmed = aboveLine.trim();
|
|
3372
|
+
if (style === "hash") {
|
|
3373
|
+
if (!aboveTrimmed.startsWith("#")) return "";
|
|
3374
|
+
const collected = [];
|
|
3375
|
+
let i = aboveIdx;
|
|
3376
|
+
while (i >= 0) {
|
|
3377
|
+
const line = lines[i];
|
|
3378
|
+
if (line === void 0) break;
|
|
3379
|
+
const trimmed = line.trim();
|
|
3380
|
+
if (!trimmed.startsWith("#")) break;
|
|
3381
|
+
collected.unshift(trimmed.replace(/^#+\s?/, ""));
|
|
3382
|
+
i--;
|
|
3383
|
+
}
|
|
3384
|
+
return collected.join("\n").trim();
|
|
3385
|
+
}
|
|
3386
|
+
if (aboveTrimmed.endsWith("*/")) {
|
|
3387
|
+
let blockStart = aboveIdx;
|
|
3388
|
+
while (blockStart >= 0) {
|
|
3389
|
+
const l = lines[blockStart];
|
|
3390
|
+
if (l === void 0) break;
|
|
3391
|
+
if (l.trim().startsWith("/*")) break;
|
|
3392
|
+
blockStart--;
|
|
3393
|
+
}
|
|
3394
|
+
if (blockStart < 0) return "";
|
|
3395
|
+
const opener = lines[blockStart];
|
|
3396
|
+
if (opener === void 0 || !opener.trim().startsWith("/*")) return "";
|
|
3397
|
+
const region = lines.slice(blockStart, aboveIdx + 1);
|
|
3398
|
+
const joined = region.join("\n").trimEnd();
|
|
3399
|
+
if (joined.indexOf("*/") !== joined.length - 2) return "";
|
|
3400
|
+
return region.map(
|
|
3401
|
+
(l) => l.trim().replace(/^\/\*+/, "").replace(/\*+\/$/, "").replace(/^\*\s?/, "").trim()
|
|
3402
|
+
).filter((l) => l !== "").join("\n");
|
|
3403
|
+
}
|
|
3404
|
+
if (aboveTrimmed.startsWith("//")) {
|
|
3405
|
+
const collected = [];
|
|
3406
|
+
let i = aboveIdx;
|
|
3407
|
+
while (i >= 0) {
|
|
3408
|
+
const line = lines[i];
|
|
3409
|
+
if (line === void 0) break;
|
|
3410
|
+
const trimmed = line.trim();
|
|
3411
|
+
if (!trimmed.startsWith("//")) break;
|
|
3412
|
+
collected.unshift(trimmed.replace(/^\/\/[/!]?\s?/, ""));
|
|
3413
|
+
i--;
|
|
3414
|
+
}
|
|
3415
|
+
return collected.join("\n").trim();
|
|
3416
|
+
}
|
|
3417
|
+
return "";
|
|
3418
|
+
}
|
|
3419
|
+
|
|
3420
|
+
// src/languages/common.ts
|
|
3421
|
+
function buildLineIndex(text) {
|
|
3422
|
+
const idx = [0];
|
|
3423
|
+
for (let i = 0; i < text.length; i++) {
|
|
3424
|
+
if (text[i] === "\n") idx.push(i + 1);
|
|
3425
|
+
}
|
|
3426
|
+
return idx;
|
|
3427
|
+
}
|
|
3428
|
+
function offsetToLine(lineIndex, offset) {
|
|
3429
|
+
let lo = 0;
|
|
3430
|
+
let hi = lineIndex.length - 1;
|
|
3431
|
+
while (lo < hi) {
|
|
3432
|
+
const mid = lo + hi + 1 >> 1;
|
|
3433
|
+
const lineStart = lineIndex[mid];
|
|
3434
|
+
if (lineStart === void 0 || lineStart > offset) {
|
|
3435
|
+
hi = mid - 1;
|
|
3436
|
+
} else {
|
|
3437
|
+
lo = mid;
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
return lo + 1;
|
|
3441
|
+
}
|
|
3442
|
+
function stripCstyleComments(text, lineCommentRe) {
|
|
3443
|
+
const lines = text.split("\n");
|
|
3444
|
+
let inComment = false;
|
|
3445
|
+
const outLines = [];
|
|
3446
|
+
for (const line of lines) {
|
|
3447
|
+
const { code, inComment: nextInComment } = stripBlockCommentSpan(line, inComment);
|
|
3448
|
+
outLines.push(code);
|
|
3449
|
+
inComment = nextInComment;
|
|
3450
|
+
}
|
|
3451
|
+
let out = outLines.join("\n");
|
|
3452
|
+
if (lineCommentRe !== void 0) {
|
|
3453
|
+
out = out.replace(lineCommentRe, (m) => " ".repeat(m.length));
|
|
3454
|
+
}
|
|
3455
|
+
return out;
|
|
3456
|
+
}
|
|
3457
|
+
function stripXmlComments(text) {
|
|
3458
|
+
const lines = text.split("\n");
|
|
3459
|
+
let inComment = false;
|
|
3460
|
+
const outLines = [];
|
|
3461
|
+
for (const line of lines) {
|
|
3462
|
+
let result = "";
|
|
3463
|
+
let j = 0;
|
|
3464
|
+
while (j < line.length) {
|
|
3465
|
+
if (!inComment) {
|
|
3466
|
+
const open = line.indexOf("<!--", j);
|
|
3467
|
+
if (open === -1) {
|
|
3468
|
+
result += line.slice(j);
|
|
3469
|
+
break;
|
|
3470
|
+
}
|
|
3471
|
+
result += line.slice(j, open);
|
|
3472
|
+
const close = line.indexOf("-->", open + 4);
|
|
3473
|
+
if (close === -1) {
|
|
3474
|
+
result += " ".repeat(line.length - open);
|
|
3475
|
+
inComment = true;
|
|
3476
|
+
break;
|
|
3477
|
+
}
|
|
3478
|
+
result += " ".repeat(close + 3 - open);
|
|
3479
|
+
j = close + 3;
|
|
3480
|
+
inComment = false;
|
|
3481
|
+
} else {
|
|
3482
|
+
const close = line.indexOf("-->", j);
|
|
3483
|
+
if (close === -1) {
|
|
3484
|
+
result += " ".repeat(line.length - j);
|
|
3485
|
+
break;
|
|
3486
|
+
}
|
|
3487
|
+
result += " ".repeat(close + 3 - j);
|
|
3488
|
+
j = close + 3;
|
|
3489
|
+
inComment = false;
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
outLines.push(result);
|
|
3493
|
+
}
|
|
3494
|
+
return outLines.join("\n");
|
|
3495
|
+
}
|
|
3496
|
+
function scanQuotedStringEnd(content, start) {
|
|
3497
|
+
const quote = content[start];
|
|
3498
|
+
const n = content.length;
|
|
3499
|
+
let j = start + 1;
|
|
3500
|
+
while (j < n) {
|
|
3501
|
+
if (content[j] === "\\" && j + 1 < n) {
|
|
3502
|
+
j += 2;
|
|
3503
|
+
continue;
|
|
3504
|
+
}
|
|
3505
|
+
if (content[j] === quote) {
|
|
3506
|
+
j++;
|
|
3507
|
+
break;
|
|
3508
|
+
}
|
|
3509
|
+
if (quote !== "`" && content[j] === "\n") {
|
|
3510
|
+
j++;
|
|
3511
|
+
break;
|
|
3512
|
+
}
|
|
3513
|
+
j++;
|
|
3514
|
+
}
|
|
3515
|
+
return j;
|
|
3516
|
+
}
|
|
3517
|
+
function stripJsComments(content) {
|
|
3518
|
+
let out = "";
|
|
3519
|
+
let i = 0;
|
|
3520
|
+
const n = content.length;
|
|
3521
|
+
while (i < n) {
|
|
3522
|
+
const ch = content[i];
|
|
3523
|
+
if (ch === "/" && content[i + 1] === "/") {
|
|
3524
|
+
let j = i;
|
|
3525
|
+
while (j < n && content[j] !== "\n") j++;
|
|
3526
|
+
out += " ".repeat(j - i);
|
|
3527
|
+
i = j;
|
|
3528
|
+
continue;
|
|
3529
|
+
}
|
|
3530
|
+
if (ch === "/" && content[i + 1] === "*") {
|
|
3531
|
+
let j = i + 2;
|
|
3532
|
+
while (j < n && !(content[j] === "*" && content[j + 1] === "/")) j++;
|
|
3533
|
+
const end = j < n ? j + 2 : n;
|
|
3534
|
+
out += content.slice(i, end).replace(/[^\n]/g, " ");
|
|
3535
|
+
i = end;
|
|
3536
|
+
continue;
|
|
3537
|
+
}
|
|
3538
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
3539
|
+
const j = scanQuotedStringEnd(content, i);
|
|
3540
|
+
out += content.slice(i, j);
|
|
3541
|
+
i = j;
|
|
3542
|
+
continue;
|
|
3543
|
+
}
|
|
3544
|
+
out += ch;
|
|
3545
|
+
i++;
|
|
3546
|
+
}
|
|
3547
|
+
return out;
|
|
3548
|
+
}
|
|
3549
|
+
function stripHashComments(text) {
|
|
3550
|
+
return text.split("\n").map((line) => {
|
|
3551
|
+
for (let i = 0; i < line.length; i++) {
|
|
3552
|
+
if (line[i] === "#" && !isInsideStringLiteral(line, i)) {
|
|
3553
|
+
return line.slice(0, i) + " ".repeat(line.length - i);
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
return line;
|
|
3557
|
+
}).join("\n");
|
|
3558
|
+
}
|
|
3559
|
+
var HTML_COMMENT_RE = /<!--[\s\S]*?-->/g;
|
|
3560
|
+
var HTML_SCRIPT_BODY_RE = /(<script\b[^>]*>)([\s\S]*?)(<\/script\s*>)/gi;
|
|
3561
|
+
var HTML_CDATA_RE = /<!\[CDATA\[[\s\S]*?\]\]>/g;
|
|
3562
|
+
var LIQUID_COMMENT_RE = /{%-?\s*comment\s*-?%}[\s\S]*?{%-?\s*endcomment\s*-?%}/gi;
|
|
3563
|
+
function maskHtmlNoise(text) {
|
|
3564
|
+
let out = text.replace(
|
|
3565
|
+
HTML_SCRIPT_BODY_RE,
|
|
3566
|
+
(_m, open, body, close) => open + body.replace(/[^\n]/g, " ") + close
|
|
3567
|
+
);
|
|
3568
|
+
out = out.replace(HTML_COMMENT_RE, (m) => m.replace(/[^\n]/g, " "));
|
|
3569
|
+
out = out.replace(LIQUID_COMMENT_RE, (m) => m.replace(/[^\n]/g, " "));
|
|
3570
|
+
out = out.replace(HTML_CDATA_RE, (m) => m.replace(/[^\n]/g, " "));
|
|
3571
|
+
return out;
|
|
3572
|
+
}
|
|
3573
|
+
var HTML_HEADING_RE = /<h([1-6])[^>]*>(.*?)<\/h\1>/gis;
|
|
3574
|
+
var HTML_HEADING_TAG_STRIP_RE = /<[^>]+>/g;
|
|
3575
|
+
function findHtmlHeadingMatches(content) {
|
|
3576
|
+
const masked = maskHtmlNoise(content);
|
|
3577
|
+
const matches = [];
|
|
3578
|
+
for (const m of masked.matchAll(HTML_HEADING_RE)) {
|
|
3579
|
+
const level = parseInt(m[1] ?? "1", 10);
|
|
3580
|
+
const raw = m[2] ?? "";
|
|
3581
|
+
const heading = raw.replace(HTML_HEADING_TAG_STRIP_RE, "").trim();
|
|
3582
|
+
matches.push({ level, heading, offset: m.index ?? 0, tag: m[0] ?? "" });
|
|
3583
|
+
}
|
|
3584
|
+
return matches;
|
|
3585
|
+
}
|
|
3586
|
+
function isInsideStringLiteral(line, index, from = 0) {
|
|
3587
|
+
let openQuote = null;
|
|
3588
|
+
let i = from;
|
|
3589
|
+
while (i < index) {
|
|
3590
|
+
const ch = line[i];
|
|
3591
|
+
if (openQuote !== null && ch === "\\" && i + 1 < line.length) {
|
|
3592
|
+
i += 2;
|
|
3593
|
+
continue;
|
|
3594
|
+
}
|
|
3595
|
+
if (ch === '"' || ch === "'") {
|
|
3596
|
+
if (openQuote === null) {
|
|
3597
|
+
openQuote = ch;
|
|
3598
|
+
} else if (openQuote === ch) {
|
|
3599
|
+
openQuote = null;
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3602
|
+
i++;
|
|
3603
|
+
}
|
|
3604
|
+
return openQuote !== null;
|
|
3605
|
+
}
|
|
3606
|
+
function stripBlockCommentSpan(line, inComment) {
|
|
3607
|
+
let code = "";
|
|
3608
|
+
let j = 0;
|
|
3609
|
+
let comment = inComment;
|
|
3610
|
+
while (j < line.length) {
|
|
3611
|
+
if (!comment) {
|
|
3612
|
+
const lineCommentIdx = lineCommentStartIndex(line, ["//"], j);
|
|
3613
|
+
let open = line.indexOf("/*", j);
|
|
3614
|
+
while (open !== -1 && (isInsideStringLiteral(line, open, j) || lineCommentIdx !== -1 && open >= lineCommentIdx)) {
|
|
3615
|
+
open = line.indexOf("/*", open + 1);
|
|
3616
|
+
}
|
|
3617
|
+
if (open === -1) {
|
|
3618
|
+
code += line.slice(j);
|
|
3619
|
+
break;
|
|
3620
|
+
}
|
|
3621
|
+
code += line.slice(j, open);
|
|
3622
|
+
const close = line.indexOf("*/", open + 2);
|
|
3623
|
+
if (close === -1) {
|
|
3624
|
+
code += " ".repeat(line.length - open);
|
|
3625
|
+
comment = true;
|
|
3626
|
+
break;
|
|
3627
|
+
}
|
|
3628
|
+
code += " ".repeat(close + 2 - open);
|
|
3629
|
+
j = close + 2;
|
|
3630
|
+
comment = false;
|
|
3631
|
+
} else {
|
|
3632
|
+
const close = line.indexOf("*/", j);
|
|
3633
|
+
if (close === -1) {
|
|
3634
|
+
code += " ".repeat(line.length - j);
|
|
3635
|
+
break;
|
|
3636
|
+
}
|
|
3637
|
+
code += " ".repeat(close + 2 - j);
|
|
3638
|
+
j = close + 2;
|
|
3639
|
+
comment = false;
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3642
|
+
return { code, inComment: comment };
|
|
3643
|
+
}
|
|
3644
|
+
function stripNestedBlockCommentSpan(line, depth) {
|
|
3645
|
+
let code = "";
|
|
3646
|
+
let j = 0;
|
|
3647
|
+
let d = depth;
|
|
3648
|
+
while (j < line.length) {
|
|
3649
|
+
if (d === 0) {
|
|
3650
|
+
const lineCommentIdx = lineCommentStartIndex(line, ["//"], j);
|
|
3651
|
+
let open = line.indexOf("/*", j);
|
|
3652
|
+
while (open !== -1 && (isInsideStringLiteral(line, open, j) || lineCommentIdx !== -1 && open >= lineCommentIdx)) {
|
|
3653
|
+
open = line.indexOf("/*", open + 1);
|
|
3654
|
+
}
|
|
3655
|
+
if (open === -1) {
|
|
3656
|
+
code += line.slice(j);
|
|
3657
|
+
break;
|
|
3658
|
+
}
|
|
3659
|
+
code += line.slice(j, open);
|
|
3660
|
+
code += " ";
|
|
3661
|
+
j = open + 2;
|
|
3662
|
+
d = 1;
|
|
3663
|
+
} else {
|
|
3664
|
+
const open = line.indexOf("/*", j);
|
|
3665
|
+
const close = line.indexOf("*/", j);
|
|
3666
|
+
if (close === -1 && open === -1) {
|
|
3667
|
+
code += " ".repeat(line.length - j);
|
|
3668
|
+
break;
|
|
3669
|
+
}
|
|
3670
|
+
const next = close === -1 ? open : open === -1 ? close : Math.min(open, close);
|
|
3671
|
+
code += " ".repeat(next + 2 - j);
|
|
3672
|
+
d = Math.max(0, d + (next === open ? 1 : -1));
|
|
3673
|
+
j = next + 2;
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
return { code, depth: d };
|
|
3677
|
+
}
|
|
3678
|
+
function stripLineComment(line, markers = ["//"]) {
|
|
3679
|
+
const cutIdx = lineCommentStartIndex(line, markers);
|
|
3680
|
+
return cutIdx === -1 ? line : line.slice(0, cutIdx);
|
|
3681
|
+
}
|
|
3682
|
+
function lineCommentStartIndex(line, markers, from = 0) {
|
|
3683
|
+
let cutIdx = -1;
|
|
3684
|
+
for (const marker of markers) {
|
|
3685
|
+
let idx = line.indexOf(marker, from);
|
|
3686
|
+
while (idx !== -1 && isInsideStringLiteral(line, idx, from)) {
|
|
3687
|
+
idx = line.indexOf(marker, idx + 1);
|
|
3688
|
+
}
|
|
3689
|
+
if (idx !== -1 && (cutIdx === -1 || idx < cutIdx)) cutIdx = idx;
|
|
3690
|
+
}
|
|
3691
|
+
return cutIdx;
|
|
3692
|
+
}
|
|
3693
|
+
function stripStringLiterals(line) {
|
|
3694
|
+
let out = "";
|
|
3695
|
+
let i = 0;
|
|
3696
|
+
const stack = [];
|
|
3697
|
+
while (i < line.length) {
|
|
3698
|
+
const ch = line[i];
|
|
3699
|
+
if (ch === "\n") {
|
|
3700
|
+
out += ch;
|
|
3701
|
+
i++;
|
|
3702
|
+
stack.length = 0;
|
|
3703
|
+
continue;
|
|
3704
|
+
}
|
|
3705
|
+
const top = stack[stack.length - 1];
|
|
3706
|
+
if (top === void 0) {
|
|
3707
|
+
if (ch === '"' || ch === "'") {
|
|
3708
|
+
const bareBraceHole = ch === '"' && i > 0 && line[i - 1] === "$";
|
|
3709
|
+
stack.push({ kind: "string", quote: ch, bareBraceHole });
|
|
3710
|
+
out += ch;
|
|
3711
|
+
i++;
|
|
3712
|
+
continue;
|
|
3713
|
+
}
|
|
3714
|
+
out += ch;
|
|
3715
|
+
i++;
|
|
3716
|
+
continue;
|
|
3717
|
+
}
|
|
3718
|
+
if (top.kind === "hole") {
|
|
3719
|
+
if (ch === '"' || ch === "'") {
|
|
3720
|
+
const bareBraceHole = ch === '"' && i > 0 && line[i - 1] === "$";
|
|
3721
|
+
stack.push({ kind: "string", quote: ch, bareBraceHole });
|
|
3722
|
+
out += ch;
|
|
3723
|
+
i++;
|
|
3724
|
+
continue;
|
|
3725
|
+
}
|
|
3726
|
+
if (ch === "{") {
|
|
3727
|
+
top.depth++;
|
|
3728
|
+
out += ch;
|
|
3729
|
+
i++;
|
|
3730
|
+
continue;
|
|
3731
|
+
}
|
|
3732
|
+
if (ch === "}") {
|
|
3733
|
+
if (top.depth > 0) {
|
|
3734
|
+
top.depth--;
|
|
3735
|
+
} else {
|
|
3736
|
+
stack.pop();
|
|
3737
|
+
}
|
|
3738
|
+
out += ch;
|
|
3739
|
+
i++;
|
|
3740
|
+
continue;
|
|
3741
|
+
}
|
|
3742
|
+
out += ch;
|
|
3743
|
+
i++;
|
|
3744
|
+
continue;
|
|
3745
|
+
}
|
|
3746
|
+
if (ch === "\\" && i + 1 < line.length) {
|
|
3747
|
+
out += " ";
|
|
3748
|
+
i += 2;
|
|
3749
|
+
continue;
|
|
3750
|
+
}
|
|
3751
|
+
if (ch === top.quote) {
|
|
3752
|
+
stack.pop();
|
|
3753
|
+
out += ch;
|
|
3754
|
+
i++;
|
|
3755
|
+
continue;
|
|
3756
|
+
}
|
|
3757
|
+
if (top.quote === '"') {
|
|
3758
|
+
if (top.bareBraceHole && ch === "{") {
|
|
3759
|
+
if (line[i + 1] === "{") {
|
|
3760
|
+
out += " ";
|
|
3761
|
+
i += 2;
|
|
3762
|
+
continue;
|
|
3763
|
+
}
|
|
3764
|
+
stack.push({ kind: "hole", depth: 0 });
|
|
3765
|
+
out += ch;
|
|
3766
|
+
i++;
|
|
3767
|
+
continue;
|
|
3768
|
+
}
|
|
3769
|
+
if (!top.bareBraceHole && ch === "$" && line[i + 1] === "{") {
|
|
3770
|
+
stack.push({ kind: "hole", depth: 0 });
|
|
3771
|
+
out += line.slice(i, i + 2);
|
|
3772
|
+
i += 2;
|
|
3773
|
+
continue;
|
|
3774
|
+
}
|
|
3775
|
+
if (!top.bareBraceHole && ch === "{" && line[i + 1] === "$") {
|
|
3776
|
+
stack.push({ kind: "hole", depth: 0 });
|
|
3777
|
+
out += ch;
|
|
3778
|
+
i++;
|
|
3779
|
+
continue;
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
out += " ";
|
|
3783
|
+
i++;
|
|
3784
|
+
}
|
|
3785
|
+
return out;
|
|
3786
|
+
}
|
|
3787
|
+
function findMultilineCloser(line, from, state) {
|
|
3788
|
+
switch (state.kind) {
|
|
3789
|
+
case "heredoc":
|
|
3790
|
+
case "nowdoc": {
|
|
3791
|
+
const re = new RegExp(`^[ \\t]*${escapeRegExp(state.identifier)}\\b`);
|
|
3792
|
+
const m = re.exec(line);
|
|
3793
|
+
return m ? { maskEnd: m[0].length } : null;
|
|
3794
|
+
}
|
|
3795
|
+
case "tripleSingleQuote": {
|
|
3796
|
+
const m = /'{3,}/.exec(line.slice(from));
|
|
3797
|
+
return m === null ? null : { maskEnd: from + m.index + m[0].length };
|
|
3798
|
+
}
|
|
3799
|
+
case "tripleQuote": {
|
|
3800
|
+
const n = state.identifier !== "" ? parseInt(state.identifier, 10) : 3;
|
|
3801
|
+
const re = new RegExp(`"{${n},}`);
|
|
3802
|
+
const m = re.exec(line.slice(from));
|
|
3803
|
+
return m === null ? null : { maskEnd: from + m.index + m[0].length };
|
|
3804
|
+
}
|
|
3805
|
+
case "verbatim": {
|
|
3806
|
+
if (!state.interpolated) {
|
|
3807
|
+
let j2 = from;
|
|
3808
|
+
while (j2 < line.length) {
|
|
3809
|
+
if (line[j2] === '"') {
|
|
3810
|
+
if (line[j2 + 1] === '"') {
|
|
3811
|
+
j2 += 2;
|
|
3812
|
+
continue;
|
|
3813
|
+
}
|
|
3814
|
+
return { maskEnd: j2 + 1 };
|
|
3815
|
+
}
|
|
3816
|
+
j2++;
|
|
3817
|
+
}
|
|
3818
|
+
return null;
|
|
3819
|
+
}
|
|
3820
|
+
let j = from;
|
|
3821
|
+
let holeDepth = 0;
|
|
3822
|
+
let nestedQuote = null;
|
|
3823
|
+
while (j < line.length) {
|
|
3824
|
+
const c = line[j];
|
|
3825
|
+
if (nestedQuote !== null) {
|
|
3826
|
+
if (c === "\\" && j + 1 < line.length) {
|
|
3827
|
+
j += 2;
|
|
3828
|
+
continue;
|
|
3829
|
+
}
|
|
3830
|
+
if (c === nestedQuote) {
|
|
3831
|
+
nestedQuote = null;
|
|
3832
|
+
}
|
|
3833
|
+
j++;
|
|
3834
|
+
continue;
|
|
3835
|
+
}
|
|
3836
|
+
if (holeDepth > 0) {
|
|
3837
|
+
if (c === '"' || c === "'") {
|
|
3838
|
+
nestedQuote = c;
|
|
3839
|
+
j++;
|
|
3840
|
+
continue;
|
|
3841
|
+
}
|
|
3842
|
+
if (c === "{") holeDepth++;
|
|
3843
|
+
else if (c === "}") holeDepth--;
|
|
3844
|
+
j++;
|
|
3845
|
+
continue;
|
|
3846
|
+
}
|
|
3847
|
+
if (c === "{") {
|
|
3848
|
+
holeDepth = 1;
|
|
3849
|
+
j++;
|
|
3850
|
+
continue;
|
|
3851
|
+
}
|
|
3852
|
+
if (c === '"') {
|
|
3853
|
+
if (line[j + 1] === '"') {
|
|
3854
|
+
j += 2;
|
|
3855
|
+
continue;
|
|
3856
|
+
}
|
|
3857
|
+
return { maskEnd: j + 1 };
|
|
3858
|
+
}
|
|
3859
|
+
j++;
|
|
3860
|
+
}
|
|
3861
|
+
return null;
|
|
3862
|
+
}
|
|
3863
|
+
case "psHereDouble":
|
|
3864
|
+
return line.startsWith('"@', from) ? { maskEnd: from + 2 } : null;
|
|
3865
|
+
case "psHereSingle":
|
|
3866
|
+
return line.startsWith("'@", from) ? { maskEnd: from + 2 } : null;
|
|
3867
|
+
default:
|
|
3868
|
+
return null;
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
var MULTILINE_OPENER_COMMENT_MARKERS = {
|
|
3872
|
+
php: ["//", "#"],
|
|
3873
|
+
kotlin: ["//"],
|
|
3874
|
+
csharp: ["//"],
|
|
3875
|
+
powershell: ["#"],
|
|
3876
|
+
swift: ["//"],
|
|
3877
|
+
elixir: ["#"]
|
|
3878
|
+
};
|
|
3879
|
+
var MULTILINE_OPENER_BLOCK_COMMENT_LANGS = /* @__PURE__ */ new Set(["php", "kotlin", "csharp", "swift"]);
|
|
3880
|
+
function isInsideSameLineBlockComment(line, idx, from = 0) {
|
|
3881
|
+
let comment = false;
|
|
3882
|
+
let j = from;
|
|
3883
|
+
while (j < idx) {
|
|
3884
|
+
if (!comment) {
|
|
3885
|
+
const open = line.indexOf("/*", j);
|
|
3886
|
+
if (open === -1 || open >= idx) return false;
|
|
3887
|
+
if (isInsideStringLiteral(line, open, from)) {
|
|
3888
|
+
j = open + 2;
|
|
3889
|
+
continue;
|
|
3890
|
+
}
|
|
3891
|
+
comment = true;
|
|
3892
|
+
j = open + 2;
|
|
3893
|
+
} else {
|
|
3894
|
+
const close = line.indexOf("*/", j);
|
|
3895
|
+
if (close === -1 || close >= idx) return true;
|
|
3896
|
+
comment = false;
|
|
3897
|
+
j = close + 2;
|
|
3898
|
+
}
|
|
3899
|
+
}
|
|
3900
|
+
return comment;
|
|
3901
|
+
}
|
|
3902
|
+
function findMultilineOpener(line, from, lang) {
|
|
3903
|
+
const commentIdx = lineCommentStartIndex(line, MULTILINE_OPENER_COMMENT_MARKERS[lang], from);
|
|
3904
|
+
const isCommented = (idx) => commentIdx !== -1 && idx >= commentIdx || MULTILINE_OPENER_BLOCK_COMMENT_LANGS.has(lang) && isInsideSameLineBlockComment(line, idx, from);
|
|
3905
|
+
if (lang === "php") {
|
|
3906
|
+
const re = /<<<\s*(['"]?)([A-Za-z_]\w*)\1/g;
|
|
3907
|
+
re.lastIndex = from;
|
|
3908
|
+
const m = re.exec(line);
|
|
3909
|
+
if (!m || isInsideStringLiteral(line, m.index, from) || isCommented(m.index)) return null;
|
|
3910
|
+
const identifier = m[2] ?? "";
|
|
3911
|
+
const kind = m[1] === "'" ? "nowdoc" : "heredoc";
|
|
3912
|
+
return { openStart: m.index, closesSameLine: null, state: { kind, identifier } };
|
|
3913
|
+
}
|
|
3914
|
+
if (lang === "kotlin") {
|
|
3915
|
+
const idx = line.indexOf('"""', from);
|
|
3916
|
+
if (idx === -1 || isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
|
|
3917
|
+
const closeIdx = line.indexOf('"""', idx + 3);
|
|
3918
|
+
if (closeIdx !== -1) {
|
|
3919
|
+
return { openStart: idx, closesSameLine: closeIdx + 3, state: { kind: "tripleQuote", identifier: "3" } };
|
|
3920
|
+
}
|
|
3921
|
+
return { openStart: idx, closesSameLine: null, state: { kind: "tripleQuote", identifier: "3" } };
|
|
3922
|
+
}
|
|
3923
|
+
if (lang === "swift") {
|
|
3924
|
+
const idx = line.indexOf('"""', from);
|
|
3925
|
+
if (idx === -1 || isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
|
|
3926
|
+
const closeIdx = line.indexOf('"""', idx + 3);
|
|
3927
|
+
if (closeIdx !== -1) {
|
|
3928
|
+
return { openStart: idx, closesSameLine: closeIdx + 3, state: { kind: "tripleQuote", identifier: "3" } };
|
|
3929
|
+
}
|
|
3930
|
+
return { openStart: idx, closesSameLine: null, state: { kind: "tripleQuote", identifier: "3" } };
|
|
3931
|
+
}
|
|
3932
|
+
if (lang === "elixir") {
|
|
3933
|
+
const candidates = [];
|
|
3934
|
+
const dq = line.indexOf('"""', from);
|
|
3935
|
+
if (dq !== -1) candidates.push([dq, "tripleQuote", '"""']);
|
|
3936
|
+
const sq = line.indexOf("'''", from);
|
|
3937
|
+
if (sq !== -1) candidates.push([sq, "tripleSingleQuote", "'''"]);
|
|
3938
|
+
candidates.sort((a, b) => a[0] - b[0]);
|
|
3939
|
+
const first = candidates[0];
|
|
3940
|
+
if (first === void 0) return null;
|
|
3941
|
+
const [idx, kind, delim] = first;
|
|
3942
|
+
if (isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
|
|
3943
|
+
const closeIdx = line.indexOf(delim, idx + 3);
|
|
3944
|
+
const state = { kind, identifier: "3" };
|
|
3945
|
+
if (closeIdx !== -1) return { openStart: idx, closesSameLine: closeIdx + 3, state };
|
|
3946
|
+
return { openStart: idx, closesSameLine: null, state };
|
|
3947
|
+
}
|
|
3948
|
+
if (lang === "csharp") {
|
|
3949
|
+
const tripleRe = /"{3,}/g;
|
|
3950
|
+
tripleRe.lastIndex = from;
|
|
3951
|
+
const tripleM = tripleRe.exec(line);
|
|
3952
|
+
let tripleIdx = tripleM ? tripleM.index : -1;
|
|
3953
|
+
const tripleLen = tripleM ? tripleM[0].length : 0;
|
|
3954
|
+
if (tripleIdx !== -1 && (isInsideStringLiteral(line, tripleIdx, from) || isCommented(tripleIdx))) tripleIdx = -1;
|
|
3955
|
+
const verbRe = /\$?@\$?"/g;
|
|
3956
|
+
verbRe.lastIndex = from;
|
|
3957
|
+
const verbM = verbRe.exec(line);
|
|
3958
|
+
let verbIdx = verbM ? verbM.index : -1;
|
|
3959
|
+
if (verbIdx !== -1 && isCommented(verbIdx)) verbIdx = -1;
|
|
3960
|
+
if (verbIdx !== -1 && isInsideStringLiteral(line, verbIdx, from)) verbIdx = -1;
|
|
3961
|
+
if (tripleIdx === -1 && verbIdx === -1) return null;
|
|
3962
|
+
const useTriple = tripleIdx !== -1 && (verbIdx === -1 || tripleIdx < verbIdx);
|
|
3963
|
+
if (useTriple) {
|
|
3964
|
+
const closeRe = new RegExp(`"{${tripleLen},}`);
|
|
3965
|
+
const closeM = closeRe.exec(line.slice(tripleIdx + tripleLen));
|
|
3966
|
+
if (closeM !== null) {
|
|
3967
|
+
const closeIdx = tripleIdx + tripleLen + closeM.index;
|
|
3968
|
+
return { openStart: tripleIdx, closesSameLine: closeIdx + closeM[0].length, state: { kind: "tripleQuote", identifier: String(tripleLen) } };
|
|
3969
|
+
}
|
|
3970
|
+
return { openStart: tripleIdx, closesSameLine: null, state: { kind: "tripleQuote", identifier: String(tripleLen) } };
|
|
3971
|
+
}
|
|
3972
|
+
const quoteIdx = verbIdx + (verbM?.[0].length ?? 1) - 1;
|
|
3973
|
+
const interpolated = (verbM?.[0] ?? "").includes("$");
|
|
3974
|
+
const closer = findMultilineCloser(line, quoteIdx + 1, { kind: "verbatim", identifier: "", interpolated });
|
|
3975
|
+
if (closer !== null) {
|
|
3976
|
+
return { openStart: verbIdx, closesSameLine: closer.maskEnd, state: { kind: "verbatim", identifier: "", interpolated } };
|
|
3977
|
+
}
|
|
3978
|
+
return { openStart: verbIdx, closesSameLine: null, state: { kind: "verbatim", identifier: "", interpolated } };
|
|
3979
|
+
}
|
|
3980
|
+
if (lang === "powershell") {
|
|
3981
|
+
const re = /@("|')\s*$/;
|
|
3982
|
+
const tail = line.slice(from);
|
|
3983
|
+
const m = re.exec(tail);
|
|
3984
|
+
if (!m) return null;
|
|
3985
|
+
const openStart = from + m.index;
|
|
3986
|
+
if (isCommented(openStart)) return null;
|
|
3987
|
+
if (isInsideStringLiteral(line, openStart, from)) return null;
|
|
3988
|
+
const kind = m[1] === '"' ? "psHereDouble" : "psHereSingle";
|
|
3989
|
+
return { openStart, closesSameLine: null, state: { kind, identifier: "" } };
|
|
3990
|
+
}
|
|
3991
|
+
return null;
|
|
3992
|
+
}
|
|
3993
|
+
function stripMultilineStringSpan(line, state, lang) {
|
|
3994
|
+
let code = "";
|
|
3995
|
+
let i = 0;
|
|
3996
|
+
let cur = state;
|
|
3997
|
+
while (i < line.length) {
|
|
3998
|
+
if (cur !== null) {
|
|
3999
|
+
const closed = findMultilineCloser(line, i, cur);
|
|
4000
|
+
if (closed === null) {
|
|
4001
|
+
code += " ".repeat(line.length - i);
|
|
4002
|
+
i = line.length;
|
|
4003
|
+
continue;
|
|
4004
|
+
}
|
|
4005
|
+
code += " ".repeat(closed.maskEnd - i);
|
|
4006
|
+
i = closed.maskEnd;
|
|
4007
|
+
cur = null;
|
|
4008
|
+
continue;
|
|
4009
|
+
}
|
|
4010
|
+
const opened = findMultilineOpener(line, i, lang);
|
|
4011
|
+
if (opened === null) {
|
|
4012
|
+
code += line.slice(i);
|
|
4013
|
+
break;
|
|
4014
|
+
}
|
|
4015
|
+
code += line.slice(i, opened.openStart);
|
|
4016
|
+
if (opened.closesSameLine !== null) {
|
|
4017
|
+
code += " ".repeat(opened.closesSameLine - opened.openStart);
|
|
4018
|
+
i = opened.closesSameLine;
|
|
4019
|
+
cur = null;
|
|
4020
|
+
} else {
|
|
4021
|
+
code += " ".repeat(line.length - opened.openStart);
|
|
4022
|
+
i = line.length;
|
|
4023
|
+
cur = opened.state;
|
|
4024
|
+
}
|
|
4025
|
+
}
|
|
4026
|
+
return { code, state: cur };
|
|
4027
|
+
}
|
|
4028
|
+
function makeSpanSymbol(filePath, name, kind, span, parent = "", lines, style) {
|
|
4029
|
+
return {
|
|
4030
|
+
filePath,
|
|
4031
|
+
name,
|
|
4032
|
+
kind,
|
|
4033
|
+
lineStart: span.startLine,
|
|
4034
|
+
lineEnd: span.endLine,
|
|
4035
|
+
body: span.body,
|
|
4036
|
+
docstring: lines !== void 0 && style !== void 0 ? precedingDocComment(lines, span.startLine, style) : "",
|
|
4037
|
+
parent
|
|
4038
|
+
};
|
|
4039
|
+
}
|
|
4040
|
+
function makeLineSymbol(filePath, name, kind, line, sig, parent, lines, style) {
|
|
4041
|
+
return {
|
|
4042
|
+
filePath,
|
|
4043
|
+
name,
|
|
4044
|
+
kind,
|
|
4045
|
+
lineStart: line,
|
|
4046
|
+
lineEnd: line,
|
|
4047
|
+
body: sig ?? "",
|
|
4048
|
+
docstring: lines !== void 0 && style !== void 0 ? precedingDocComment(lines, line, style) : "",
|
|
4049
|
+
parent: parent ?? ""
|
|
4050
|
+
};
|
|
4051
|
+
}
|
|
4052
|
+
function makeSymbolEmitter(symbols, sections, seen, filePath, maxSymbols = 500, maxHeadingLen = 120) {
|
|
4053
|
+
return function emit(name, kind, line) {
|
|
4054
|
+
if (!name || name.length > maxHeadingLen) return;
|
|
4055
|
+
if (symbols.length >= maxSymbols) return;
|
|
4056
|
+
const key = `${name}\0${kind}\0${line}`;
|
|
4057
|
+
if (seen.has(key)) return;
|
|
4058
|
+
seen.add(key);
|
|
4059
|
+
symbols.push({
|
|
4060
|
+
filePath,
|
|
4061
|
+
name,
|
|
4062
|
+
kind,
|
|
4063
|
+
lineStart: line,
|
|
4064
|
+
lineEnd: line,
|
|
4065
|
+
body: "",
|
|
4066
|
+
docstring: "",
|
|
4067
|
+
parent: ""
|
|
4068
|
+
});
|
|
4069
|
+
sections.push({ heading: name, level: 1, line, endLine: line });
|
|
4070
|
+
};
|
|
4071
|
+
}
|
|
4072
|
+
function assignFlatEndLines(sections, totalLines) {
|
|
4073
|
+
for (let i = 0; i < sections.length; i++) {
|
|
4074
|
+
const next = sections[i + 1];
|
|
4075
|
+
const s = sections[i];
|
|
4076
|
+
if (s === void 0) continue;
|
|
4077
|
+
const end = next !== void 0 ? next.line - 1 : totalLines;
|
|
4078
|
+
s.endLine = end < s.line ? s.line : end;
|
|
4079
|
+
}
|
|
4080
|
+
}
|
|
4081
|
+
function propagateEndLinesToSymbols(symbols, sections) {
|
|
4082
|
+
const sectionMap = /* @__PURE__ */ new Map();
|
|
4083
|
+
for (const sec of sections) {
|
|
4084
|
+
const key = `${sec.heading}\0${sec.line}`;
|
|
4085
|
+
const queue = sectionMap.get(key);
|
|
4086
|
+
if (queue !== void 0) queue.push(sec.endLine);
|
|
4087
|
+
else sectionMap.set(key, [sec.endLine]);
|
|
4088
|
+
}
|
|
4089
|
+
return symbols.map((sym) => {
|
|
4090
|
+
const key = `${sym.name}\0${sym.lineStart}`;
|
|
4091
|
+
const endLine = sectionMap.get(key)?.shift();
|
|
4092
|
+
if (endLine !== void 0 && endLine !== sym.lineEnd) {
|
|
4093
|
+
return { ...sym, lineEnd: endLine };
|
|
4094
|
+
}
|
|
4095
|
+
return sym;
|
|
4096
|
+
});
|
|
4097
|
+
}
|
|
4098
|
+
function findMatchingBraceEndLine(content, openBraceIndex, totalLines, lineIndex) {
|
|
4099
|
+
let depth = 0;
|
|
4100
|
+
let quote = null;
|
|
4101
|
+
for (let i = openBraceIndex; i < content.length; i++) {
|
|
4102
|
+
const ch = content[i];
|
|
4103
|
+
if (quote !== null) {
|
|
4104
|
+
if (ch === "\\") {
|
|
4105
|
+
i++;
|
|
4106
|
+
continue;
|
|
4107
|
+
}
|
|
4108
|
+
if (ch === quote) quote = null;
|
|
4109
|
+
continue;
|
|
4110
|
+
}
|
|
4111
|
+
if (ch === '"' || ch === "'") {
|
|
4112
|
+
quote = ch;
|
|
4113
|
+
continue;
|
|
4114
|
+
}
|
|
4115
|
+
if (ch === "{") depth++;
|
|
4116
|
+
else if (ch === "}") {
|
|
4117
|
+
depth--;
|
|
4118
|
+
if (depth === 0) {
|
|
4119
|
+
return offsetToLine(lineIndex, i);
|
|
4120
|
+
}
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
return totalLines;
|
|
4124
|
+
}
|
|
4125
|
+
|
|
4126
|
+
// src/languages/ini_idx.ts
|
|
4127
|
+
var MAX_SECTIONS = 200;
|
|
4128
|
+
var MAX_HEADING_LEN = 200;
|
|
4129
|
+
var MAX_ENV_KEYS = 200;
|
|
4130
|
+
var HEADER_RE = /^\[([^\]\r\n]+)\]\s*(?:[;#].*)?$/;
|
|
4131
|
+
var ENV_KEY_RE = /^(?:export\s+)?([A-Za-z_][\w.-]*)\s*(?:=|:(?!\/\/))/;
|
|
4132
|
+
function extractIni(content, filePath) {
|
|
4133
|
+
const symbols = [];
|
|
4134
|
+
const sections = [];
|
|
4135
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4136
|
+
const lines = content.split(/\r?\n/);
|
|
4137
|
+
const totalLines = lines.length;
|
|
4138
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4139
|
+
if (symbols.length >= MAX_SECTIONS) break;
|
|
4140
|
+
const line = lines[i] ?? "";
|
|
4141
|
+
if (!line || line[0] !== "[") continue;
|
|
4142
|
+
const m = HEADER_RE.exec(line);
|
|
4143
|
+
if (m === null) continue;
|
|
4144
|
+
const name = m[1]?.trim() ?? "";
|
|
4145
|
+
if (!name || name.length > MAX_HEADING_LEN) continue;
|
|
4146
|
+
const key = `${name}\0${i + 1}`;
|
|
4147
|
+
if (seen.has(key)) continue;
|
|
4148
|
+
seen.add(key);
|
|
4149
|
+
symbols.push(makeLineSymbol(filePath, name, "ini_section", i + 1));
|
|
4150
|
+
sections.push({ heading: name, level: 1, line: i + 1, endLine: i + 1 });
|
|
4151
|
+
}
|
|
4152
|
+
sections.sort((a, b) => a.line - b.line);
|
|
4153
|
+
assignFlatEndLines(sections, totalLines);
|
|
4154
|
+
return propagateEndLinesToSymbols(symbols, sections);
|
|
4155
|
+
}
|
|
4156
|
+
function _isEscapedQuote(line, i, q) {
|
|
4157
|
+
if (q === "'") return false;
|
|
4158
|
+
let backslashes = 0;
|
|
4159
|
+
let j = i - 1;
|
|
4160
|
+
while (j >= 0 && line[j] === "\\") {
|
|
4161
|
+
backslashes++;
|
|
4162
|
+
j--;
|
|
4163
|
+
}
|
|
4164
|
+
return backslashes % 2 === 1;
|
|
4165
|
+
}
|
|
4166
|
+
function _lineClosesQuote(line, q) {
|
|
4167
|
+
for (let i = 0; i < line.length; i++) {
|
|
4168
|
+
if (line[i] === q && !_isEscapedQuote(line, i, q)) return true;
|
|
4169
|
+
}
|
|
4170
|
+
return false;
|
|
4171
|
+
}
|
|
4172
|
+
function _detectOpenQuote(value) {
|
|
4173
|
+
const trimmed = value.replace(/^\s+/, "");
|
|
4174
|
+
const q = trimmed[0];
|
|
4175
|
+
if (q !== '"' && q !== "'") return null;
|
|
4176
|
+
for (let i = 1; i < trimmed.length; i++) {
|
|
4177
|
+
if (trimmed[i] === q && !_isEscapedQuote(trimmed, i, q)) return null;
|
|
4178
|
+
}
|
|
4179
|
+
return q;
|
|
4180
|
+
}
|
|
4181
|
+
function extractEnv(content, filePath) {
|
|
4182
|
+
const symbols = [];
|
|
4183
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4184
|
+
const lines = content.split(/\r?\n/);
|
|
4185
|
+
let openQuote = null;
|
|
4186
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4187
|
+
if (symbols.length >= MAX_ENV_KEYS) break;
|
|
4188
|
+
const line = lines[i] ?? "";
|
|
4189
|
+
if (openQuote !== null) {
|
|
4190
|
+
if (_lineClosesQuote(line, openQuote)) openQuote = null;
|
|
4191
|
+
continue;
|
|
4192
|
+
}
|
|
4193
|
+
if (!line || line[0] === "#" || line[0] === ";" || line[0] === " " || line[0] === " ") continue;
|
|
4194
|
+
const m = ENV_KEY_RE.exec(line);
|
|
4195
|
+
if (m === null) continue;
|
|
4196
|
+
const name = m[1]?.trim() ?? "";
|
|
4197
|
+
if (!name || name.length > MAX_HEADING_LEN) continue;
|
|
4198
|
+
const key = `${name}\0${i + 1}`;
|
|
4199
|
+
if (seen.has(key)) continue;
|
|
4200
|
+
seen.add(key);
|
|
4201
|
+
symbols.push(makeLineSymbol(filePath, name, "env_key", i + 1));
|
|
4202
|
+
openQuote = _detectOpenQuote(line.slice(m[0].length));
|
|
4203
|
+
}
|
|
4204
|
+
return symbols;
|
|
4205
|
+
}
|
|
4206
|
+
|
|
4207
|
+
// src/dotenv_redact.ts
|
|
4208
|
+
var DOTENV_VALUE_PLACEHOLDER = "[REDACTED:dotenv_value]";
|
|
4209
|
+
var ASSIGNMENT_RE = /^(\s*(?:export\s+)?[A-Za-z_][\w.-]*\s*(?:\+?=|:(?!\/\/)))/;
|
|
4210
|
+
var SAFE_LINE_RE = /^\s*(?:[#;].*)?$/;
|
|
4211
|
+
function isDotenvPath(filePath) {
|
|
4212
|
+
return detectLanguage(filePath) === "env_file";
|
|
4213
|
+
}
|
|
4214
|
+
function redactDotenvValues(text) {
|
|
4215
|
+
const lines = text.split("\n");
|
|
4216
|
+
const out = [];
|
|
4217
|
+
let openQuote = null;
|
|
4218
|
+
for (const raw of lines) {
|
|
4219
|
+
const hasCr = raw.endsWith("\r");
|
|
4220
|
+
const line = hasCr ? raw.slice(0, -1) : raw;
|
|
4221
|
+
const eol = hasCr ? "\r" : "";
|
|
4222
|
+
const emit = (s) => {
|
|
4223
|
+
out.push(`${s}${eol}`);
|
|
4224
|
+
};
|
|
4225
|
+
if (openQuote !== null) {
|
|
4226
|
+
if (_lineClosesQuote(line, openQuote)) openQuote = null;
|
|
4227
|
+
emit(DOTENV_VALUE_PLACEHOLDER);
|
|
4228
|
+
continue;
|
|
4229
|
+
}
|
|
4230
|
+
if (SAFE_LINE_RE.test(line)) {
|
|
4231
|
+
emit(line);
|
|
4232
|
+
continue;
|
|
4233
|
+
}
|
|
4234
|
+
const m = ASSIGNMENT_RE.exec(line);
|
|
4235
|
+
if (m === null || m[1] === void 0) {
|
|
4236
|
+
emit(DOTENV_VALUE_PLACEHOLDER);
|
|
4237
|
+
continue;
|
|
4238
|
+
}
|
|
4239
|
+
const prefix = m[1];
|
|
4240
|
+
openQuote = _detectOpenQuote(line.slice(prefix.length));
|
|
4241
|
+
emit(`${prefix}${DOTENV_VALUE_PLACEHOLDER}`);
|
|
4242
|
+
}
|
|
4243
|
+
return out.join("\n");
|
|
4244
|
+
}
|
|
4245
|
+
function redactIfDotenv(filePath, text) {
|
|
4246
|
+
return isDotenvPath(filePath) ? redactDotenvValues(text) : text;
|
|
4247
|
+
}
|
|
4248
|
+
|
|
3238
4249
|
// src/db.ts
|
|
3239
|
-
init_define_import_meta_env();
|
|
3240
4250
|
import * as fs6 from "node:fs";
|
|
3241
4251
|
import { createRequire as createRequire2 } from "node:module";
|
|
3242
|
-
import * as
|
|
4252
|
+
import * as path7 from "node:path";
|
|
3243
4253
|
import Database from "better-sqlite3";
|
|
3244
4254
|
var _require = createRequire2(import.meta.url);
|
|
3245
4255
|
var _connections = /* @__PURE__ */ new Map();
|
|
@@ -3491,7 +4501,7 @@ CREATE TRIGGER IF NOT EXISTS cache_recall_au AFTER UPDATE ON cache_recall BEGIN
|
|
|
3491
4501
|
VALUES (new.row_id, new.label, new.content);
|
|
3492
4502
|
END;
|
|
3493
4503
|
`;
|
|
3494
|
-
var SCHEMA_VERSION =
|
|
4504
|
+
var SCHEMA_VERSION = 11;
|
|
3495
4505
|
function alterTableIdempotent(conn, sql) {
|
|
3496
4506
|
try {
|
|
3497
4507
|
conn.exec(sql);
|
|
@@ -3499,6 +4509,26 @@ function alterTableIdempotent(conn, sql) {
|
|
|
3499
4509
|
if (!(err instanceof Error) || !/duplicate column/i.test(err.message)) throw err;
|
|
3500
4510
|
}
|
|
3501
4511
|
}
|
|
4512
|
+
function purgeDotenvEmbeddings(conn) {
|
|
4513
|
+
let paths;
|
|
4514
|
+
try {
|
|
4515
|
+
paths = conn.prepare("SELECT DISTINCT file_path FROM chunks").all().map((r) => r.file_path).filter(isDotenvPath);
|
|
4516
|
+
} catch {
|
|
4517
|
+
return;
|
|
4518
|
+
}
|
|
4519
|
+
if (paths.length === 0) return;
|
|
4520
|
+
for (const p of paths) {
|
|
4521
|
+
try {
|
|
4522
|
+
conn.prepare("DELETE FROM chunk_vectors WHERE rowid IN (SELECT id FROM chunks WHERE file_path = ?)").run(p);
|
|
4523
|
+
} catch {
|
|
4524
|
+
}
|
|
4525
|
+
conn.prepare("DELETE FROM chunks WHERE file_path = ?").run(p);
|
|
4526
|
+
try {
|
|
4527
|
+
conn.prepare("UPDATE files SET embed_sha = NULL WHERE path = ?").run(p);
|
|
4528
|
+
} catch {
|
|
4529
|
+
}
|
|
4530
|
+
}
|
|
4531
|
+
}
|
|
3502
4532
|
var MIGRATIONS = {
|
|
3503
4533
|
// v1 -> v2: adds files.embed_sha, tracked separately from files.sha so embedding freshness can be gated independently of parse freshness (see makeIndexer in worker.ts). A pre-existing v1 database's `files` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has the column 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, so a genuine ALTER TABLE failure is never silently lost.
|
|
3504
4534
|
1: (conn) => alterTableIdempotent(conn, "ALTER TABLE files ADD COLUMN embed_sha TEXT"),
|
|
@@ -3507,7 +4537,15 @@ var MIGRATIONS = {
|
|
|
3507
4537
|
// v8 -> v9: adds symbols.parent (see SCHEMA_VERSION comment above for why). A pre-existing v8 database's `symbols` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has the column 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 v1 -> v2 / v2 -> v3 above.
|
|
3508
4538
|
8: (conn) => alterTableIdempotent(conn, "ALTER TABLE symbols ADD COLUMN parent TEXT NOT NULL DEFAULT ''"),
|
|
3509
4539
|
// v9 -> v10: adds hint_emissions.bytes_emitted (see SCHEMA_VERSION comment above for why). A pre-existing v9 database's `hint_emissions` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has the column 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 v1 -> v2 / v2 -> v3 / v8 -> v9 above.
|
|
3510
|
-
9: (conn) => alterTableIdempotent(conn, "ALTER TABLE hint_emissions ADD COLUMN bytes_emitted INTEGER")
|
|
4540
|
+
9: (conn) => alterTableIdempotent(conn, "ALTER TABLE hint_emissions ADD COLUMN bytes_emitted INTEGER"),
|
|
4541
|
+
// v10 -> v11: purge chunks (and their vectors) for dotenv files. Until this version, a tracked
|
|
4542
|
+
// `.env` was chunked and embedded verbatim on the git path, so `semantic` returned its values --
|
|
4543
|
+
// see dotenv_redact.ts. Redacting from now on is not enough on its own: the embed-freshness gate
|
|
4544
|
+
// (isEmbedFresh in parser.ts) skips a file whose bytes have not changed, so an already-indexed
|
|
4545
|
+
// .env would have kept serving its pre-fix chunks indefinitely. Deleting the rows here both
|
|
4546
|
+
// removes the stored secrets and, by clearing embed_sha, makes the next drain re-embed the file
|
|
4547
|
+
// through the redacting path.
|
|
4548
|
+
10: purgeDotenvEmbeddings
|
|
3511
4549
|
};
|
|
3512
4550
|
function runMigrations(conn, fromVersion, toVersion) {
|
|
3513
4551
|
for (let v = fromVersion; v < toVersion; v++) {
|
|
@@ -3553,8 +4591,8 @@ function initConnection(conn) {
|
|
|
3553
4591
|
}
|
|
3554
4592
|
}
|
|
3555
4593
|
function resolveDbPath(dbPath) {
|
|
3556
|
-
if (
|
|
3557
|
-
if (dbPath.includes("/") || dbPath.includes("\\")) return
|
|
4594
|
+
if (path7.isAbsolute(dbPath)) return dbPath;
|
|
4595
|
+
if (dbPath.includes("/") || dbPath.includes("\\")) return path7.resolve(dbPath);
|
|
3558
4596
|
return safeJoin(dataDir(), dbPath);
|
|
3559
4597
|
}
|
|
3560
4598
|
function connectionKey(dbPath) {
|
|
@@ -3565,7 +4603,7 @@ function getDb(dbPath) {
|
|
|
3565
4603
|
const { resolved, key } = connectionKey(dbPath);
|
|
3566
4604
|
const existing = _connections.get(key);
|
|
3567
4605
|
if (existing !== void 0) return existing;
|
|
3568
|
-
const dir =
|
|
4606
|
+
const dir = path7.dirname(resolved);
|
|
3569
4607
|
try {
|
|
3570
4608
|
ensureDirSync(dir);
|
|
3571
4609
|
} catch (e) {
|
|
@@ -3596,7 +4634,6 @@ function closeAllDbs() {
|
|
|
3596
4634
|
registerReset(closeAllDbs);
|
|
3597
4635
|
|
|
3598
4636
|
// src/render/ansi.ts
|
|
3599
|
-
init_define_import_meta_env();
|
|
3600
4637
|
function _colorStream(isatty) {
|
|
3601
4638
|
if (process.env["NO_COLOR"]) return false;
|
|
3602
4639
|
return isatty;
|
|
@@ -3671,11 +4708,9 @@ var C = {
|
|
|
3671
4708
|
};
|
|
3672
4709
|
|
|
3673
4710
|
// src/stats.ts
|
|
3674
|
-
|
|
3675
|
-
import * as path7 from "node:path";
|
|
4711
|
+
import * as path8 from "node:path";
|
|
3676
4712
|
|
|
3677
4713
|
// src/render/stats_renderer.ts
|
|
3678
|
-
init_define_import_meta_env();
|
|
3679
4714
|
var _STATS_MESSAGES_FALLBACK = {
|
|
3680
4715
|
bytesModeOnlyNote: "tracks bytes, not vision tokens",
|
|
3681
4716
|
sessionHintSplitNote: "session_hint shows realized savings; session_hint_overhead shows injected hint cost",
|
|
@@ -4565,7 +5600,7 @@ var _globalSchemaApplied = /* @__PURE__ */ new Set();
|
|
|
4565
5600
|
registerReset(() => _globalSchemaApplied.clear());
|
|
4566
5601
|
function getGlobalDb(homeDir) {
|
|
4567
5602
|
const basePath = homeDir ? dataDirForHome(homeDir) : dataDir();
|
|
4568
|
-
const dbPath =
|
|
5603
|
+
const dbPath = path8.join(basePath, "global.db");
|
|
4569
5604
|
const db = getDb(dbPath);
|
|
4570
5605
|
if (!_globalSchemaApplied.has(dbPath)) {
|
|
4571
5606
|
db.exec(GLOBAL_SCHEMA_SQL);
|
|
@@ -4803,7 +5838,6 @@ function renderStats2(opts) {
|
|
|
4803
5838
|
}
|
|
4804
5839
|
|
|
4805
5840
|
// src/secret_redact.ts
|
|
4806
|
-
init_define_import_meta_env();
|
|
4807
5841
|
var SECRET_PATTERNS = [
|
|
4808
5842
|
// Anthropic keys share OpenAI's "sk-" prefix but are more specific
|
|
4809
5843
|
// ("sk-ant-"), so they're matched first — the generic OpenAI pattern's
|
|
@@ -4831,8 +5865,13 @@ var SECRET_PATTERNS = [
|
|
|
4831
5865
|
// Redacts only the token itself, not the "Authorization: Bearer " prefix -- the lookbehind
|
|
4832
5866
|
// anchors on the header name and scheme so the surrounding request-log line stays readable,
|
|
4833
5867
|
// matching how AWS_ACCESS_KEY_ID=... above keeps its own prefix intact.
|
|
4834
|
-
|
|
4835
|
-
|
|
5868
|
+
// The optional quotes on either side of the colon are what let this see a header carried in
|
|
5869
|
+
// JSON rather than in raw wire format. Without them the lookbehind demanded the colon sit
|
|
5870
|
+
// directly against the header name and the scheme directly against the space, so a body like
|
|
5871
|
+
// {"Authorization": "Bearer <token>"} -- the shape any logged fetch or MCP result arrives in
|
|
5872
|
+
// -- matched nothing and the token was cached verbatim.
|
|
5873
|
+
["auth_bearer_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}Bearer[ \t])[A-Za-z0-9\-._~+/]{10,}=*/gi],
|
|
5874
|
+
["auth_basic_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}Basic[ \t])[A-Za-z0-9+/]{6,}=*/gi],
|
|
4836
5875
|
// JWTs have no distinctive prefix of their own, but the base64url encoding of the smallest
|
|
4837
5876
|
// realistic header ('{"alg":' or similar) always starts with "eyJ", so that's the practical
|
|
4838
5877
|
// anchor here -- each of the three dot-separated segments requires a minimum length to avoid
|
|
@@ -4851,6 +5890,13 @@ var SECRET_PATTERNS = [
|
|
|
4851
5890
|
// are what make the short, generic 'sig' name safe to key on: a prose or code mention of "sig"
|
|
4852
5891
|
// never sits directly after a query separator followed by that much opaque token.
|
|
4853
5892
|
["presigned_signature", /(?<=[?&](?:X-Amz-Signature|X-Goog-Signature|sig)=)[A-Za-z0-9%+/=_-]{16,}/gi],
|
|
5893
|
+
// A password inside a connection url. `postgres://user:hunter2@db.internal` carries the
|
|
5894
|
+
// credential in the authority section, where there is no `key=value` separator for the
|
|
5895
|
+
// generic pattern below to anchor on, so a DATABASE_URL echoed by a failing migration or a
|
|
5896
|
+
// psql error went through untouched. The anchors are what keep this narrow: a scheme's `://`,
|
|
5897
|
+
// a userinfo segment, the colon, and a following `@`. `http://host:8080/path` has no `@` and
|
|
5898
|
+
// is left alone; so is any url without credentials.
|
|
5899
|
+
["url_credentials", /(?<=:\/\/[^\s:@/]{1,64}:)[^\s:@/]{1,256}(?=@)/g],
|
|
4854
5900
|
// Generic key=value assignments in .env-file and connection-string/query-string shape. The
|
|
4855
5901
|
// lookbehind again redacts only the value, and the value's character class deliberately
|
|
4856
5902
|
// excludes whitespace, '&', ';', '#', quote characters, and '[' ']' ':' -- that exclusion is
|
|
@@ -4866,13 +5912,19 @@ var SECRET_PATTERNS = [
|
|
|
4866
5912
|
// this cannot backtrack catastrophically -- there is no nested or overlapping quantifier for
|
|
4867
5913
|
// the engine to explore multiple ways of matching, so removing the upper bound does not
|
|
4868
5914
|
// introduce a ReDoS risk.
|
|
5915
|
+
// Quotes are permitted around the separator, but never inside the value class. A quoted value
|
|
5916
|
+
// is the ordinary way secrets are written -- .env files, JSON, YAML, TOML all quote by default
|
|
5917
|
+
// -- and the lookbehind used to stop dead at the opening quote, so `API_KEY="..."` passed
|
|
5918
|
+
// through in full while the bare `API_KEY=...` was caught. The closing quote of the key name
|
|
5919
|
+
// blocked it from the other side too, which is what kept every JSON body unredacted. Keeping
|
|
5920
|
+
// quotes out of the value class is still what stops the match running past the closing quote.
|
|
4869
5921
|
// The keyword may be a prefix of a longer key name rather than the whole of it, so the
|
|
4870
5922
|
// trailing identifier class below is load-bearing: without it the lookbehind required the
|
|
4871
5923
|
// keyword to sit immediately before the separator, and AWS_SECRET_ACCESS_KEY=,
|
|
4872
5924
|
// SECRET_KEY=, and DB_PASSWORD_HASH= all passed through in full. That class matches
|
|
4873
5925
|
// identifier characters only, so prose that merely mentions a keyword still never reaches
|
|
4874
5926
|
// a separator and stays unredacted. api[_-]?key covers the apikey and api-key spellings too.
|
|
4875
|
-
["generic_secret_assignment", /(?<=(?:password|passwd|secret|api[_-]?key)[a-z0-9_-]
|
|
5927
|
+
["generic_secret_assignment", /(?<=(?:password|passwd|secret|api[_-]?key|access[_-]?token|refresh[_-]?token|id[_-]?token)[a-z0-9_-]{0,64}["']?[ \t]{0,8}[:=][ \t]{0,8}["']?)(?:\\[^\n]|[^\s\\&;#'"[\],{}:]){4,}/gi]
|
|
4876
5928
|
];
|
|
4877
5929
|
function redactSecrets(text) {
|
|
4878
5930
|
let count = 0;
|
|
@@ -4887,7 +5939,6 @@ function redactSecrets(text) {
|
|
|
4887
5939
|
}
|
|
4888
5940
|
|
|
4889
5941
|
// src/filters.ts
|
|
4890
|
-
init_define_import_meta_env();
|
|
4891
5942
|
var DROP = () => null;
|
|
4892
5943
|
var FILTERS = [
|
|
4893
5944
|
{
|
|
@@ -4948,7 +5999,6 @@ var FILTERS = [
|
|
|
4948
5999
|
];
|
|
4949
6000
|
|
|
4950
6001
|
// src/bash_compress.ts
|
|
4951
|
-
init_define_import_meta_env();
|
|
4952
6002
|
function stripAnsiCodes(text) {
|
|
4953
6003
|
return stripAnsiEscapes(text);
|
|
4954
6004
|
}
|
|
@@ -5042,6 +6092,36 @@ export {
|
|
|
5042
6092
|
CONFIG_KEY_ENV_OVERRIDES,
|
|
5043
6093
|
saveConfig,
|
|
5044
6094
|
redactSecrets,
|
|
6095
|
+
precedingDocComment,
|
|
6096
|
+
buildLineIndex,
|
|
6097
|
+
offsetToLine,
|
|
6098
|
+
stripCstyleComments,
|
|
6099
|
+
stripXmlComments,
|
|
6100
|
+
scanQuotedStringEnd,
|
|
6101
|
+
stripJsComments,
|
|
6102
|
+
stripHashComments,
|
|
6103
|
+
maskHtmlNoise,
|
|
6104
|
+
findHtmlHeadingMatches,
|
|
6105
|
+
isInsideStringLiteral,
|
|
6106
|
+
stripBlockCommentSpan,
|
|
6107
|
+
stripNestedBlockCommentSpan,
|
|
6108
|
+
stripLineComment,
|
|
6109
|
+
stripStringLiterals,
|
|
6110
|
+
stripMultilineStringSpan,
|
|
6111
|
+
makeSpanSymbol,
|
|
6112
|
+
makeLineSymbol,
|
|
6113
|
+
makeSymbolEmitter,
|
|
6114
|
+
assignFlatEndLines,
|
|
6115
|
+
propagateEndLinesToSymbols,
|
|
6116
|
+
findMatchingBraceEndLine,
|
|
6117
|
+
extractIni,
|
|
6118
|
+
_lineClosesQuote,
|
|
6119
|
+
_detectOpenQuote,
|
|
6120
|
+
extractEnv,
|
|
6121
|
+
detectLanguage,
|
|
6122
|
+
unsupportedLanguageName,
|
|
6123
|
+
isDotenvPath,
|
|
6124
|
+
redactIfDotenv,
|
|
5045
6125
|
getDb,
|
|
5046
6126
|
colorStdout,
|
|
5047
6127
|
RESET,
|