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-chunk-
|
|
6
|
-
import {
|
|
7
|
-
init_define_import_meta_env
|
|
8
|
-
} from "./token-goat-chunk-3UOG7PSZ.mjs";
|
|
5
|
+
} from "./token-goat-chunk-AO2QD2AG.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/fingerprint.ts
|
|
202
|
-
init_define_import_meta_env();
|
|
203
197
|
import { createHash } from "node:crypto";
|
|
204
198
|
import * as fs2 from "node:fs";
|
|
205
199
|
function fingerprintContent(content) {
|
|
@@ -221,7 +215,6 @@ function fingerprintFile(filePath) {
|
|
|
221
215
|
}
|
|
222
216
|
|
|
223
217
|
// src/paths.ts
|
|
224
|
-
init_define_import_meta_env();
|
|
225
218
|
import * as fs3 from "node:fs";
|
|
226
219
|
import * as path2 from "node:path";
|
|
227
220
|
var WSL_PATH_RE = /^\/mnt\/([a-zA-Z])\/(.*)$/s;
|
|
@@ -318,7 +311,6 @@ function safeJoin(base, ...parts) {
|
|
|
318
311
|
}
|
|
319
312
|
|
|
320
313
|
// src/util.ts
|
|
321
|
-
init_define_import_meta_env();
|
|
322
314
|
import { spawn, spawnSync } from "node:child_process";
|
|
323
315
|
import { chmodSync as chmodSync2, closeSync, copyFileSync, existsSync, mkdirSync as mkdirSync2, openSync, readdirSync, readFileSync as readFileSync2, renameSync, statSync as statSync2, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
324
316
|
import * as path3 from "node:path";
|
|
@@ -945,7 +937,6 @@ function suggestPackageNames(query, names) {
|
|
|
945
937
|
}
|
|
946
938
|
|
|
947
939
|
// src/project.ts
|
|
948
|
-
init_define_import_meta_env();
|
|
949
940
|
import * as fs4 from "node:fs";
|
|
950
941
|
import * as os2 from "node:os";
|
|
951
942
|
import * as path4 from "node:path";
|
|
@@ -1159,24 +1150,10 @@ function isInsideRoot(target, root) {
|
|
|
1159
1150
|
}
|
|
1160
1151
|
|
|
1161
1152
|
// src/config.ts
|
|
1162
|
-
init_define_import_meta_env();
|
|
1163
1153
|
import * as fs5 from "node:fs";
|
|
1164
1154
|
import * as path5 from "node:path";
|
|
1165
1155
|
|
|
1166
|
-
// node_modules/smol-toml/dist/index.js
|
|
1167
|
-
init_define_import_meta_env();
|
|
1168
|
-
|
|
1169
|
-
// node_modules/smol-toml/dist/parse.js
|
|
1170
|
-
init_define_import_meta_env();
|
|
1171
|
-
|
|
1172
|
-
// node_modules/smol-toml/dist/struct.js
|
|
1173
|
-
init_define_import_meta_env();
|
|
1174
|
-
|
|
1175
|
-
// node_modules/smol-toml/dist/primitive.js
|
|
1176
|
-
init_define_import_meta_env();
|
|
1177
|
-
|
|
1178
1156
|
// node_modules/smol-toml/dist/date.js
|
|
1179
|
-
init_define_import_meta_env();
|
|
1180
1157
|
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
|
|
1181
1158
|
var TomlDate = class _TomlDate extends Date {
|
|
1182
1159
|
#hasDate = false;
|
|
@@ -1269,7 +1246,6 @@ var TomlDate = class _TomlDate extends Date {
|
|
|
1269
1246
|
};
|
|
1270
1247
|
|
|
1271
1248
|
// node_modules/smol-toml/dist/error.js
|
|
1272
|
-
init_define_import_meta_env();
|
|
1273
1249
|
function getLineColFromPtr(string, ptr) {
|
|
1274
1250
|
let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
|
|
1275
1251
|
return [lines.length, lines.pop().length + 1];
|
|
@@ -1468,11 +1444,7 @@ function parseValue(value, toml, ptr, integersAsBigInt) {
|
|
|
1468
1444
|
return date;
|
|
1469
1445
|
}
|
|
1470
1446
|
|
|
1471
|
-
// node_modules/smol-toml/dist/extract.js
|
|
1472
|
-
init_define_import_meta_env();
|
|
1473
|
-
|
|
1474
1447
|
// node_modules/smol-toml/dist/util.js
|
|
1475
|
-
init_define_import_meta_env();
|
|
1476
1448
|
function indexOfNewline(str, start = 0, end = str.length) {
|
|
1477
1449
|
let idx = str.indexOf("\n", start);
|
|
1478
1450
|
if (str[idx - 1] === "\r")
|
|
@@ -1862,7 +1834,6 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
|
1862
1834
|
}
|
|
1863
1835
|
|
|
1864
1836
|
// node_modules/smol-toml/dist/stringify.js
|
|
1865
|
-
init_define_import_meta_env();
|
|
1866
1837
|
var BARE_KEY = /^[a-z0-9-_]+$/i;
|
|
1867
1838
|
function extendedTypeOf(obj) {
|
|
1868
1839
|
let type = typeof obj;
|
|
@@ -2004,7 +1975,6 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
|
2004
1975
|
}
|
|
2005
1976
|
|
|
2006
1977
|
// src/env.ts
|
|
2007
|
-
init_define_import_meta_env();
|
|
2008
1978
|
var FALSY_ENV_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "off"]);
|
|
2009
1979
|
var TRUTHY_ENV_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
|
|
2010
1980
|
function envStr(key, defaultVal) {
|
|
@@ -3248,11 +3218,1051 @@ function saveConfig(config) {
|
|
|
3248
3218
|
_cached2 = null;
|
|
3249
3219
|
}
|
|
3250
3220
|
|
|
3221
|
+
// src/parser_types.ts
|
|
3222
|
+
import * as path6 from "node:path";
|
|
3223
|
+
var EXTENSION_LANGUAGE = /* @__PURE__ */ new Map([
|
|
3224
|
+
[".py", "python"],
|
|
3225
|
+
[".pyi", "python"],
|
|
3226
|
+
[".ts", "typescript"],
|
|
3227
|
+
[".tsx", "typescript"],
|
|
3228
|
+
[".mts", "typescript"],
|
|
3229
|
+
[".cts", "typescript"],
|
|
3230
|
+
[".js", "javascript"],
|
|
3231
|
+
[".jsx", "javascript"],
|
|
3232
|
+
[".mjs", "javascript"],
|
|
3233
|
+
[".cjs", "javascript"],
|
|
3234
|
+
[".rs", "rust"],
|
|
3235
|
+
[".go", "go"],
|
|
3236
|
+
[".c", "c"],
|
|
3237
|
+
[".h", "c"],
|
|
3238
|
+
[".cpp", "cpp"],
|
|
3239
|
+
[".cc", "cpp"],
|
|
3240
|
+
[".cxx", "cpp"],
|
|
3241
|
+
[".hpp", "cpp"],
|
|
3242
|
+
[".hxx", "cpp"],
|
|
3243
|
+
[".rb", "ruby"],
|
|
3244
|
+
[".ruby", "ruby"],
|
|
3245
|
+
// Rake task files (lib/tasks/foo.rake) are plain Ruby syntax (`task :foo do ... end`),
|
|
3246
|
+
// parsed identically by the ruby tree-sitter grammar. Without this entry a `.rake` file
|
|
3247
|
+
// fell through to 'unknown' and indexed zero symbols despite the grammar handling its
|
|
3248
|
+
// content exactly like any other .rb file -- the same has-extractor-but-no-extension gap
|
|
3249
|
+
// previously fixed for `.mk` (Makefile fragments).
|
|
3250
|
+
[".rake", "ruby"],
|
|
3251
|
+
[".java", "java"],
|
|
3252
|
+
[".sh", "bash"],
|
|
3253
|
+
[".bash", "bash"],
|
|
3254
|
+
[".md", "markdown"],
|
|
3255
|
+
[".markdown", "markdown"],
|
|
3256
|
+
// MDX heading syntax is plain ATX and works with the existing markdown extractor as-is,
|
|
3257
|
+
// unlike .rst which genuinely needs an underline-style heading parser this extractor doesn't
|
|
3258
|
+
// implement (left as 'unknown' deliberately).
|
|
3259
|
+
[".mdx", "markdown"],
|
|
3260
|
+
[".toml", "toml"],
|
|
3261
|
+
[".json", "json"],
|
|
3262
|
+
[".yaml", "yaml"],
|
|
3263
|
+
[".yml", "yaml"],
|
|
3264
|
+
[".css", "css"],
|
|
3265
|
+
[".scss", "css"],
|
|
3266
|
+
[".sass", "css"],
|
|
3267
|
+
[".less", "css"],
|
|
3268
|
+
[".cs", "csharp"],
|
|
3269
|
+
[".php", "php"],
|
|
3270
|
+
[".html", "html"],
|
|
3271
|
+
[".htm", "html"],
|
|
3272
|
+
[".liquid", "liquid"],
|
|
3273
|
+
[".kt", "kotlin"],
|
|
3274
|
+
[".kts", "kotlin"],
|
|
3275
|
+
[".swift", "swift"],
|
|
3276
|
+
[".scala", "scala"],
|
|
3277
|
+
[".sc", "scala"],
|
|
3278
|
+
[".lua", "lua"],
|
|
3279
|
+
[".ex", "elixir"],
|
|
3280
|
+
[".exs", "elixir"],
|
|
3281
|
+
[".dart", "dart"],
|
|
3282
|
+
[".zig", "zig"],
|
|
3283
|
+
[".r", "r"],
|
|
3284
|
+
[".graphql", "graphql"],
|
|
3285
|
+
[".gql", "graphql"],
|
|
3286
|
+
[".sql", "sql"],
|
|
3287
|
+
[".ini", "ini"],
|
|
3288
|
+
[".cfg", "ini"],
|
|
3289
|
+
[".conf", "ini"],
|
|
3290
|
+
[".proto", "proto"],
|
|
3291
|
+
// `.mk` is the idiomatic extension for included Makefile fragments (config.mk, rules.mk,
|
|
3292
|
+
// common.mk); their syntax is identical to a bare `Makefile`, which FILENAME_LANGUAGE already
|
|
3293
|
+
// maps. Without this entry a `.mk` fragment fell through to 'unknown' and was indexed with zero
|
|
3294
|
+
// symbols despite extractMakefile handling its content fine -- the same has-extractor-but-no-
|
|
3295
|
+
// extension gap previously seen for other adapters. (importsExtensionFor already treats bare
|
|
3296
|
+
// Makefile basenames as `.mk` for the imports command, so extractImports' `.mk` branch was
|
|
3297
|
+
// reachable while symbol indexing was not.)
|
|
3298
|
+
[".mk", "makefile"],
|
|
3299
|
+
[".tf", "terraform"],
|
|
3300
|
+
[".tfvars", "terraform"],
|
|
3301
|
+
[".hcl", "terraform"],
|
|
3302
|
+
[".ps1", "powershell"],
|
|
3303
|
+
[".psm1", "powershell"],
|
|
3304
|
+
[".env", "env_file"],
|
|
3305
|
+
[".cls", "apex"],
|
|
3306
|
+
[".trigger", "apex"],
|
|
3307
|
+
[".cmp", "salesforce_markup"],
|
|
3308
|
+
[".app", "salesforce_markup"],
|
|
3309
|
+
[".evt", "salesforce_markup"],
|
|
3310
|
+
[".intf", "salesforce_markup"],
|
|
3311
|
+
[".design", "salesforce_markup"],
|
|
3312
|
+
[".auradoc", "salesforce_markup"],
|
|
3313
|
+
[".tokens", "salesforce_markup"],
|
|
3314
|
+
[".page", "salesforce_markup"],
|
|
3315
|
+
[".component", "salesforce_markup"],
|
|
3316
|
+
[".email", "salesforce_markup"],
|
|
3317
|
+
[".vue", "vue"],
|
|
3318
|
+
[".svelte", "svelte"],
|
|
3319
|
+
[".astro", "astro"],
|
|
3320
|
+
[".ipynb", "ipynb"]
|
|
3321
|
+
]);
|
|
3322
|
+
var FILENAME_LANGUAGE = /* @__PURE__ */ new Map([
|
|
3323
|
+
["dockerfile", "dockerfile"],
|
|
3324
|
+
["makefile", "makefile"],
|
|
3325
|
+
["gnumakefile", "makefile"],
|
|
3326
|
+
["bsdmakefile", "makefile"],
|
|
3327
|
+
["cargo.toml", "toml"],
|
|
3328
|
+
["pyproject.toml", "toml"],
|
|
3329
|
+
["package.json", "json"],
|
|
3330
|
+
["tsconfig.json", "json"],
|
|
3331
|
+
[".envrc", "env_file"],
|
|
3332
|
+
// Gemfile and Rakefile are plain Ruby syntax with no extension -- the dominant, idiomatic
|
|
3333
|
+
// dependency-manifest and task-runner files in virtually every real Ruby project (analogous to
|
|
3334
|
+
// package.json for Node or a bare Makefile). Without these entries both fell through to
|
|
3335
|
+
// 'unknown' and indexed zero symbols despite the ruby tree-sitter grammar handling their
|
|
3336
|
+
// content exactly like any other .rb file -- the same has-extractor-but-no-dispatch-entry gap
|
|
3337
|
+
// already fixed for bare `Makefile` / `.mk` fragments above.
|
|
3338
|
+
["gemfile", "ruby"],
|
|
3339
|
+
["rakefile", "ruby"],
|
|
3340
|
+
// Vagrantfile, Guardfile, Podfile, Capfile, Fastfile: same idiomatic extensionless-Ruby-DSL
|
|
3341
|
+
// pattern as Gemfile/Rakefile above -- `Vagrant.configure(...) do ... end`, Guard's `guard
|
|
3342
|
+
// 'rspec' do ... end`, CocoaPods' `Pod::Spec.new do |s| ... end`, Capistrano's `set :application`,
|
|
3343
|
+
// and fastlane's `lane :build do ... end` are all plain Ruby, parsed identically by the ruby
|
|
3344
|
+
// tree-sitter grammar. Without these entries each fell through to 'unknown' and indexed zero
|
|
3345
|
+
// symbols despite the grammar handling their content exactly like any other .rb file.
|
|
3346
|
+
["vagrantfile", "ruby"],
|
|
3347
|
+
["guardfile", "ruby"],
|
|
3348
|
+
["podfile", "ruby"],
|
|
3349
|
+
["capfile", "ruby"],
|
|
3350
|
+
["fastfile", "ruby"],
|
|
3351
|
+
// Brewfile: Homebrew Bundle's dependency manifest (`brew "wget"`, `cask "..."`, `tap "..."`)
|
|
3352
|
+
// is ordinary Ruby method-call syntax, evaluated by Homebrew's own Ruby DSL -- the extensionless
|
|
3353
|
+
// macOS-dev-environment analogue of Gemfile/package.json, and near-universal in dotfiles repos
|
|
3354
|
+
// that use `brew bundle dump`/`brew bundle install`. Same has-extractor-but-no-dispatch-entry
|
|
3355
|
+
// gap as the other extensionless Ruby DSL files above: without this entry it fell through to
|
|
3356
|
+
// 'unknown' and indexed zero symbols despite the ruby tree-sitter grammar handling its content
|
|
3357
|
+
// exactly like any other .rb file.
|
|
3358
|
+
["brewfile", "ruby"]
|
|
3359
|
+
]);
|
|
3360
|
+
var DOTENV_VARIANT_RE = /^\.env(\..+)?$/;
|
|
3361
|
+
function detectLanguage(filePath) {
|
|
3362
|
+
const base = path6.basename(filePath).toLowerCase();
|
|
3363
|
+
if (DOTENV_VARIANT_RE.test(base)) return "env_file";
|
|
3364
|
+
const byName = FILENAME_LANGUAGE.get(base);
|
|
3365
|
+
if (byName !== void 0) return byName;
|
|
3366
|
+
if (base.endsWith("-meta.xml")) {
|
|
3367
|
+
return "salesforce_metadata";
|
|
3368
|
+
}
|
|
3369
|
+
const ext = path6.extname(base).toLowerCase();
|
|
3370
|
+
return EXTENSION_LANGUAGE.get(ext) ?? "unknown";
|
|
3371
|
+
}
|
|
3372
|
+
var UNSUPPORTED_LANGUAGE_EXTENSIONS = /* @__PURE__ */ new Map([]);
|
|
3373
|
+
function unsupportedLanguageName(filePath) {
|
|
3374
|
+
const ext = path6.extname(filePath).toLowerCase();
|
|
3375
|
+
return UNSUPPORTED_LANGUAGE_EXTENSIONS.get(ext);
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3378
|
+
// src/doc_comment.ts
|
|
3379
|
+
function precedingDocComment(lines, lineStart, style) {
|
|
3380
|
+
const aboveIdx = lineStart - 2;
|
|
3381
|
+
if (aboveIdx < 0 || aboveIdx >= lines.length) return "";
|
|
3382
|
+
const aboveLine = lines[aboveIdx];
|
|
3383
|
+
if (aboveLine === void 0) return "";
|
|
3384
|
+
const aboveTrimmed = aboveLine.trim();
|
|
3385
|
+
if (style === "hash") {
|
|
3386
|
+
if (!aboveTrimmed.startsWith("#")) return "";
|
|
3387
|
+
const collected = [];
|
|
3388
|
+
let i = aboveIdx;
|
|
3389
|
+
while (i >= 0) {
|
|
3390
|
+
const line = lines[i];
|
|
3391
|
+
if (line === void 0) break;
|
|
3392
|
+
const trimmed = line.trim();
|
|
3393
|
+
if (!trimmed.startsWith("#")) break;
|
|
3394
|
+
collected.unshift(trimmed.replace(/^#+\s?/, ""));
|
|
3395
|
+
i--;
|
|
3396
|
+
}
|
|
3397
|
+
return collected.join("\n").trim();
|
|
3398
|
+
}
|
|
3399
|
+
if (aboveTrimmed.endsWith("*/")) {
|
|
3400
|
+
let blockStart = aboveIdx;
|
|
3401
|
+
while (blockStart >= 0) {
|
|
3402
|
+
const l = lines[blockStart];
|
|
3403
|
+
if (l === void 0) break;
|
|
3404
|
+
if (l.trim().startsWith("/*")) break;
|
|
3405
|
+
blockStart--;
|
|
3406
|
+
}
|
|
3407
|
+
if (blockStart < 0) return "";
|
|
3408
|
+
const opener = lines[blockStart];
|
|
3409
|
+
if (opener === void 0 || !opener.trim().startsWith("/*")) return "";
|
|
3410
|
+
const region = lines.slice(blockStart, aboveIdx + 1);
|
|
3411
|
+
const joined = region.join("\n").trimEnd();
|
|
3412
|
+
if (joined.indexOf("*/") !== joined.length - 2) return "";
|
|
3413
|
+
return region.map(
|
|
3414
|
+
(l) => l.trim().replace(/^\/\*+/, "").replace(/\*+\/$/, "").replace(/^\*\s?/, "").trim()
|
|
3415
|
+
).filter((l) => l !== "").join("\n");
|
|
3416
|
+
}
|
|
3417
|
+
if (aboveTrimmed.startsWith("//")) {
|
|
3418
|
+
const collected = [];
|
|
3419
|
+
let i = aboveIdx;
|
|
3420
|
+
while (i >= 0) {
|
|
3421
|
+
const line = lines[i];
|
|
3422
|
+
if (line === void 0) break;
|
|
3423
|
+
const trimmed = line.trim();
|
|
3424
|
+
if (!trimmed.startsWith("//")) break;
|
|
3425
|
+
collected.unshift(trimmed.replace(/^\/\/[/!]?\s?/, ""));
|
|
3426
|
+
i--;
|
|
3427
|
+
}
|
|
3428
|
+
return collected.join("\n").trim();
|
|
3429
|
+
}
|
|
3430
|
+
return "";
|
|
3431
|
+
}
|
|
3432
|
+
|
|
3433
|
+
// src/languages/common.ts
|
|
3434
|
+
function buildLineIndex(text) {
|
|
3435
|
+
const idx = [0];
|
|
3436
|
+
for (let i = 0; i < text.length; i++) {
|
|
3437
|
+
if (text[i] === "\n") idx.push(i + 1);
|
|
3438
|
+
}
|
|
3439
|
+
return idx;
|
|
3440
|
+
}
|
|
3441
|
+
function offsetToLine(lineIndex, offset) {
|
|
3442
|
+
let lo = 0;
|
|
3443
|
+
let hi = lineIndex.length - 1;
|
|
3444
|
+
while (lo < hi) {
|
|
3445
|
+
const mid = lo + hi + 1 >> 1;
|
|
3446
|
+
const lineStart = lineIndex[mid];
|
|
3447
|
+
if (lineStart === void 0 || lineStart > offset) {
|
|
3448
|
+
hi = mid - 1;
|
|
3449
|
+
} else {
|
|
3450
|
+
lo = mid;
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
return lo + 1;
|
|
3454
|
+
}
|
|
3455
|
+
function stripCstyleComments(text, lineCommentRe) {
|
|
3456
|
+
const lines = text.split("\n");
|
|
3457
|
+
let inComment = false;
|
|
3458
|
+
const outLines = [];
|
|
3459
|
+
for (const line of lines) {
|
|
3460
|
+
const { code, inComment: nextInComment } = stripBlockCommentSpan(line, inComment);
|
|
3461
|
+
outLines.push(code);
|
|
3462
|
+
inComment = nextInComment;
|
|
3463
|
+
}
|
|
3464
|
+
let out = outLines.join("\n");
|
|
3465
|
+
if (lineCommentRe !== void 0) {
|
|
3466
|
+
out = out.replace(lineCommentRe, (m) => " ".repeat(m.length));
|
|
3467
|
+
}
|
|
3468
|
+
return out;
|
|
3469
|
+
}
|
|
3470
|
+
function stripXmlComments(text) {
|
|
3471
|
+
const lines = text.split("\n");
|
|
3472
|
+
let inComment = false;
|
|
3473
|
+
const outLines = [];
|
|
3474
|
+
for (const line of lines) {
|
|
3475
|
+
let result = "";
|
|
3476
|
+
let j = 0;
|
|
3477
|
+
while (j < line.length) {
|
|
3478
|
+
if (!inComment) {
|
|
3479
|
+
const open = line.indexOf("<!--", j);
|
|
3480
|
+
if (open === -1) {
|
|
3481
|
+
result += line.slice(j);
|
|
3482
|
+
break;
|
|
3483
|
+
}
|
|
3484
|
+
result += line.slice(j, open);
|
|
3485
|
+
const close = line.indexOf("-->", open + 4);
|
|
3486
|
+
if (close === -1) {
|
|
3487
|
+
result += " ".repeat(line.length - open);
|
|
3488
|
+
inComment = true;
|
|
3489
|
+
break;
|
|
3490
|
+
}
|
|
3491
|
+
result += " ".repeat(close + 3 - open);
|
|
3492
|
+
j = close + 3;
|
|
3493
|
+
inComment = false;
|
|
3494
|
+
} else {
|
|
3495
|
+
const close = line.indexOf("-->", j);
|
|
3496
|
+
if (close === -1) {
|
|
3497
|
+
result += " ".repeat(line.length - j);
|
|
3498
|
+
break;
|
|
3499
|
+
}
|
|
3500
|
+
result += " ".repeat(close + 3 - j);
|
|
3501
|
+
j = close + 3;
|
|
3502
|
+
inComment = false;
|
|
3503
|
+
}
|
|
3504
|
+
}
|
|
3505
|
+
outLines.push(result);
|
|
3506
|
+
}
|
|
3507
|
+
return outLines.join("\n");
|
|
3508
|
+
}
|
|
3509
|
+
function scanQuotedStringEnd(content, start) {
|
|
3510
|
+
const quote = content[start];
|
|
3511
|
+
const n = content.length;
|
|
3512
|
+
let j = start + 1;
|
|
3513
|
+
while (j < n) {
|
|
3514
|
+
if (content[j] === "\\" && j + 1 < n) {
|
|
3515
|
+
j += 2;
|
|
3516
|
+
continue;
|
|
3517
|
+
}
|
|
3518
|
+
if (content[j] === quote) {
|
|
3519
|
+
j++;
|
|
3520
|
+
break;
|
|
3521
|
+
}
|
|
3522
|
+
if (quote !== "`" && content[j] === "\n") {
|
|
3523
|
+
j++;
|
|
3524
|
+
break;
|
|
3525
|
+
}
|
|
3526
|
+
j++;
|
|
3527
|
+
}
|
|
3528
|
+
return j;
|
|
3529
|
+
}
|
|
3530
|
+
function stripJsComments(content) {
|
|
3531
|
+
let out = "";
|
|
3532
|
+
let i = 0;
|
|
3533
|
+
const n = content.length;
|
|
3534
|
+
while (i < n) {
|
|
3535
|
+
const ch = content[i];
|
|
3536
|
+
if (ch === "/" && content[i + 1] === "/") {
|
|
3537
|
+
let j = i;
|
|
3538
|
+
while (j < n && content[j] !== "\n") j++;
|
|
3539
|
+
out += " ".repeat(j - i);
|
|
3540
|
+
i = j;
|
|
3541
|
+
continue;
|
|
3542
|
+
}
|
|
3543
|
+
if (ch === "/" && content[i + 1] === "*") {
|
|
3544
|
+
let j = i + 2;
|
|
3545
|
+
while (j < n && !(content[j] === "*" && content[j + 1] === "/")) j++;
|
|
3546
|
+
const end = j < n ? j + 2 : n;
|
|
3547
|
+
out += content.slice(i, end).replace(/[^\n]/g, " ");
|
|
3548
|
+
i = end;
|
|
3549
|
+
continue;
|
|
3550
|
+
}
|
|
3551
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
3552
|
+
const j = scanQuotedStringEnd(content, i);
|
|
3553
|
+
out += content.slice(i, j);
|
|
3554
|
+
i = j;
|
|
3555
|
+
continue;
|
|
3556
|
+
}
|
|
3557
|
+
out += ch;
|
|
3558
|
+
i++;
|
|
3559
|
+
}
|
|
3560
|
+
return out;
|
|
3561
|
+
}
|
|
3562
|
+
function stripHashComments(text) {
|
|
3563
|
+
return text.split("\n").map((line) => {
|
|
3564
|
+
for (let i = 0; i < line.length; i++) {
|
|
3565
|
+
if (line[i] === "#" && !isInsideStringLiteral(line, i)) {
|
|
3566
|
+
return line.slice(0, i) + " ".repeat(line.length - i);
|
|
3567
|
+
}
|
|
3568
|
+
}
|
|
3569
|
+
return line;
|
|
3570
|
+
}).join("\n");
|
|
3571
|
+
}
|
|
3572
|
+
var HTML_COMMENT_RE = /<!--[\s\S]*?-->/g;
|
|
3573
|
+
var HTML_SCRIPT_BODY_RE = /(<script\b[^>]*>)([\s\S]*?)(<\/script\s*>)/gi;
|
|
3574
|
+
var HTML_CDATA_RE = /<!\[CDATA\[[\s\S]*?\]\]>/g;
|
|
3575
|
+
var LIQUID_COMMENT_RE = /{%-?\s*comment\s*-?%}[\s\S]*?{%-?\s*endcomment\s*-?%}/gi;
|
|
3576
|
+
function maskHtmlNoise(text) {
|
|
3577
|
+
let out = text.replace(
|
|
3578
|
+
HTML_SCRIPT_BODY_RE,
|
|
3579
|
+
(_m, open, body, close) => open + body.replace(/[^\n]/g, " ") + close
|
|
3580
|
+
);
|
|
3581
|
+
out = out.replace(HTML_COMMENT_RE, (m) => m.replace(/[^\n]/g, " "));
|
|
3582
|
+
out = out.replace(LIQUID_COMMENT_RE, (m) => m.replace(/[^\n]/g, " "));
|
|
3583
|
+
out = out.replace(HTML_CDATA_RE, (m) => m.replace(/[^\n]/g, " "));
|
|
3584
|
+
return out;
|
|
3585
|
+
}
|
|
3586
|
+
var HTML_HEADING_RE = /<h([1-6])[^>]*>(.*?)<\/h\1>/gis;
|
|
3587
|
+
var HTML_HEADING_TAG_STRIP_RE = /<[^>]+>/g;
|
|
3588
|
+
function findHtmlHeadingMatches(content) {
|
|
3589
|
+
const masked = maskHtmlNoise(content);
|
|
3590
|
+
const matches = [];
|
|
3591
|
+
for (const m of masked.matchAll(HTML_HEADING_RE)) {
|
|
3592
|
+
const level = parseInt(m[1] ?? "1", 10);
|
|
3593
|
+
const raw = m[2] ?? "";
|
|
3594
|
+
const heading = raw.replace(HTML_HEADING_TAG_STRIP_RE, "").trim();
|
|
3595
|
+
matches.push({ level, heading, offset: m.index ?? 0, tag: m[0] ?? "" });
|
|
3596
|
+
}
|
|
3597
|
+
return matches;
|
|
3598
|
+
}
|
|
3599
|
+
function isInsideStringLiteral(line, index, from = 0) {
|
|
3600
|
+
let openQuote = null;
|
|
3601
|
+
let i = from;
|
|
3602
|
+
while (i < index) {
|
|
3603
|
+
const ch = line[i];
|
|
3604
|
+
if (openQuote !== null && ch === "\\" && i + 1 < line.length) {
|
|
3605
|
+
i += 2;
|
|
3606
|
+
continue;
|
|
3607
|
+
}
|
|
3608
|
+
if (ch === '"' || ch === "'") {
|
|
3609
|
+
if (openQuote === null) {
|
|
3610
|
+
openQuote = ch;
|
|
3611
|
+
} else if (openQuote === ch) {
|
|
3612
|
+
openQuote = null;
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
i++;
|
|
3616
|
+
}
|
|
3617
|
+
return openQuote !== null;
|
|
3618
|
+
}
|
|
3619
|
+
function stripBlockCommentSpan(line, inComment) {
|
|
3620
|
+
let code = "";
|
|
3621
|
+
let j = 0;
|
|
3622
|
+
let comment = inComment;
|
|
3623
|
+
while (j < line.length) {
|
|
3624
|
+
if (!comment) {
|
|
3625
|
+
const lineCommentIdx = lineCommentStartIndex(line, ["//"], j);
|
|
3626
|
+
let open = line.indexOf("/*", j);
|
|
3627
|
+
while (open !== -1 && (isInsideStringLiteral(line, open, j) || lineCommentIdx !== -1 && open >= lineCommentIdx)) {
|
|
3628
|
+
open = line.indexOf("/*", open + 1);
|
|
3629
|
+
}
|
|
3630
|
+
if (open === -1) {
|
|
3631
|
+
code += line.slice(j);
|
|
3632
|
+
break;
|
|
3633
|
+
}
|
|
3634
|
+
code += line.slice(j, open);
|
|
3635
|
+
const close = line.indexOf("*/", open + 2);
|
|
3636
|
+
if (close === -1) {
|
|
3637
|
+
code += " ".repeat(line.length - open);
|
|
3638
|
+
comment = true;
|
|
3639
|
+
break;
|
|
3640
|
+
}
|
|
3641
|
+
code += " ".repeat(close + 2 - open);
|
|
3642
|
+
j = close + 2;
|
|
3643
|
+
comment = false;
|
|
3644
|
+
} else {
|
|
3645
|
+
const close = line.indexOf("*/", j);
|
|
3646
|
+
if (close === -1) {
|
|
3647
|
+
code += " ".repeat(line.length - j);
|
|
3648
|
+
break;
|
|
3649
|
+
}
|
|
3650
|
+
code += " ".repeat(close + 2 - j);
|
|
3651
|
+
j = close + 2;
|
|
3652
|
+
comment = false;
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
return { code, inComment: comment };
|
|
3656
|
+
}
|
|
3657
|
+
function stripNestedBlockCommentSpan(line, depth) {
|
|
3658
|
+
let code = "";
|
|
3659
|
+
let j = 0;
|
|
3660
|
+
let d = depth;
|
|
3661
|
+
while (j < line.length) {
|
|
3662
|
+
if (d === 0) {
|
|
3663
|
+
const lineCommentIdx = lineCommentStartIndex(line, ["//"], j);
|
|
3664
|
+
let open = line.indexOf("/*", j);
|
|
3665
|
+
while (open !== -1 && (isInsideStringLiteral(line, open, j) || lineCommentIdx !== -1 && open >= lineCommentIdx)) {
|
|
3666
|
+
open = line.indexOf("/*", open + 1);
|
|
3667
|
+
}
|
|
3668
|
+
if (open === -1) {
|
|
3669
|
+
code += line.slice(j);
|
|
3670
|
+
break;
|
|
3671
|
+
}
|
|
3672
|
+
code += line.slice(j, open);
|
|
3673
|
+
code += " ";
|
|
3674
|
+
j = open + 2;
|
|
3675
|
+
d = 1;
|
|
3676
|
+
} else {
|
|
3677
|
+
const open = line.indexOf("/*", j);
|
|
3678
|
+
const close = line.indexOf("*/", j);
|
|
3679
|
+
if (close === -1 && open === -1) {
|
|
3680
|
+
code += " ".repeat(line.length - j);
|
|
3681
|
+
break;
|
|
3682
|
+
}
|
|
3683
|
+
const next = close === -1 ? open : open === -1 ? close : Math.min(open, close);
|
|
3684
|
+
code += " ".repeat(next + 2 - j);
|
|
3685
|
+
d = Math.max(0, d + (next === open ? 1 : -1));
|
|
3686
|
+
j = next + 2;
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3689
|
+
return { code, depth: d };
|
|
3690
|
+
}
|
|
3691
|
+
function stripLineComment(line, markers = ["//"]) {
|
|
3692
|
+
const cutIdx = lineCommentStartIndex(line, markers);
|
|
3693
|
+
return cutIdx === -1 ? line : line.slice(0, cutIdx);
|
|
3694
|
+
}
|
|
3695
|
+
function lineCommentStartIndex(line, markers, from = 0) {
|
|
3696
|
+
let cutIdx = -1;
|
|
3697
|
+
for (const marker of markers) {
|
|
3698
|
+
let idx = line.indexOf(marker, from);
|
|
3699
|
+
while (idx !== -1 && isInsideStringLiteral(line, idx, from)) {
|
|
3700
|
+
idx = line.indexOf(marker, idx + 1);
|
|
3701
|
+
}
|
|
3702
|
+
if (idx !== -1 && (cutIdx === -1 || idx < cutIdx)) cutIdx = idx;
|
|
3703
|
+
}
|
|
3704
|
+
return cutIdx;
|
|
3705
|
+
}
|
|
3706
|
+
function stripStringLiterals(line) {
|
|
3707
|
+
let out = "";
|
|
3708
|
+
let i = 0;
|
|
3709
|
+
const stack = [];
|
|
3710
|
+
while (i < line.length) {
|
|
3711
|
+
const ch = line[i];
|
|
3712
|
+
if (ch === "\n") {
|
|
3713
|
+
out += ch;
|
|
3714
|
+
i++;
|
|
3715
|
+
stack.length = 0;
|
|
3716
|
+
continue;
|
|
3717
|
+
}
|
|
3718
|
+
const top = stack[stack.length - 1];
|
|
3719
|
+
if (top === void 0) {
|
|
3720
|
+
if (ch === '"' || ch === "'") {
|
|
3721
|
+
const bareBraceHole = ch === '"' && i > 0 && line[i - 1] === "$";
|
|
3722
|
+
stack.push({ kind: "string", quote: ch, bareBraceHole });
|
|
3723
|
+
out += ch;
|
|
3724
|
+
i++;
|
|
3725
|
+
continue;
|
|
3726
|
+
}
|
|
3727
|
+
out += ch;
|
|
3728
|
+
i++;
|
|
3729
|
+
continue;
|
|
3730
|
+
}
|
|
3731
|
+
if (top.kind === "hole") {
|
|
3732
|
+
if (ch === '"' || ch === "'") {
|
|
3733
|
+
const bareBraceHole = ch === '"' && i > 0 && line[i - 1] === "$";
|
|
3734
|
+
stack.push({ kind: "string", quote: ch, bareBraceHole });
|
|
3735
|
+
out += ch;
|
|
3736
|
+
i++;
|
|
3737
|
+
continue;
|
|
3738
|
+
}
|
|
3739
|
+
if (ch === "{") {
|
|
3740
|
+
top.depth++;
|
|
3741
|
+
out += ch;
|
|
3742
|
+
i++;
|
|
3743
|
+
continue;
|
|
3744
|
+
}
|
|
3745
|
+
if (ch === "}") {
|
|
3746
|
+
if (top.depth > 0) {
|
|
3747
|
+
top.depth--;
|
|
3748
|
+
} else {
|
|
3749
|
+
stack.pop();
|
|
3750
|
+
}
|
|
3751
|
+
out += ch;
|
|
3752
|
+
i++;
|
|
3753
|
+
continue;
|
|
3754
|
+
}
|
|
3755
|
+
out += ch;
|
|
3756
|
+
i++;
|
|
3757
|
+
continue;
|
|
3758
|
+
}
|
|
3759
|
+
if (ch === "\\" && i + 1 < line.length) {
|
|
3760
|
+
out += " ";
|
|
3761
|
+
i += 2;
|
|
3762
|
+
continue;
|
|
3763
|
+
}
|
|
3764
|
+
if (ch === top.quote) {
|
|
3765
|
+
stack.pop();
|
|
3766
|
+
out += ch;
|
|
3767
|
+
i++;
|
|
3768
|
+
continue;
|
|
3769
|
+
}
|
|
3770
|
+
if (top.quote === '"') {
|
|
3771
|
+
if (top.bareBraceHole && ch === "{") {
|
|
3772
|
+
if (line[i + 1] === "{") {
|
|
3773
|
+
out += " ";
|
|
3774
|
+
i += 2;
|
|
3775
|
+
continue;
|
|
3776
|
+
}
|
|
3777
|
+
stack.push({ kind: "hole", depth: 0 });
|
|
3778
|
+
out += ch;
|
|
3779
|
+
i++;
|
|
3780
|
+
continue;
|
|
3781
|
+
}
|
|
3782
|
+
if (!top.bareBraceHole && ch === "$" && line[i + 1] === "{") {
|
|
3783
|
+
stack.push({ kind: "hole", depth: 0 });
|
|
3784
|
+
out += line.slice(i, i + 2);
|
|
3785
|
+
i += 2;
|
|
3786
|
+
continue;
|
|
3787
|
+
}
|
|
3788
|
+
if (!top.bareBraceHole && ch === "{" && line[i + 1] === "$") {
|
|
3789
|
+
stack.push({ kind: "hole", depth: 0 });
|
|
3790
|
+
out += ch;
|
|
3791
|
+
i++;
|
|
3792
|
+
continue;
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3795
|
+
out += " ";
|
|
3796
|
+
i++;
|
|
3797
|
+
}
|
|
3798
|
+
return out;
|
|
3799
|
+
}
|
|
3800
|
+
function findMultilineCloser(line, from, state) {
|
|
3801
|
+
switch (state.kind) {
|
|
3802
|
+
case "heredoc":
|
|
3803
|
+
case "nowdoc": {
|
|
3804
|
+
const re = new RegExp(`^[ \\t]*${escapeRegExp(state.identifier)}\\b`);
|
|
3805
|
+
const m = re.exec(line);
|
|
3806
|
+
return m ? { maskEnd: m[0].length } : null;
|
|
3807
|
+
}
|
|
3808
|
+
case "tripleSingleQuote": {
|
|
3809
|
+
const m = /'{3,}/.exec(line.slice(from));
|
|
3810
|
+
return m === null ? null : { maskEnd: from + m.index + m[0].length };
|
|
3811
|
+
}
|
|
3812
|
+
case "tripleQuote": {
|
|
3813
|
+
const n = state.identifier !== "" ? parseInt(state.identifier, 10) : 3;
|
|
3814
|
+
const re = new RegExp(`"{${n},}`);
|
|
3815
|
+
const m = re.exec(line.slice(from));
|
|
3816
|
+
return m === null ? null : { maskEnd: from + m.index + m[0].length };
|
|
3817
|
+
}
|
|
3818
|
+
case "verbatim": {
|
|
3819
|
+
if (!state.interpolated) {
|
|
3820
|
+
let j2 = from;
|
|
3821
|
+
while (j2 < line.length) {
|
|
3822
|
+
if (line[j2] === '"') {
|
|
3823
|
+
if (line[j2 + 1] === '"') {
|
|
3824
|
+
j2 += 2;
|
|
3825
|
+
continue;
|
|
3826
|
+
}
|
|
3827
|
+
return { maskEnd: j2 + 1 };
|
|
3828
|
+
}
|
|
3829
|
+
j2++;
|
|
3830
|
+
}
|
|
3831
|
+
return null;
|
|
3832
|
+
}
|
|
3833
|
+
let j = from;
|
|
3834
|
+
let holeDepth = 0;
|
|
3835
|
+
let nestedQuote = null;
|
|
3836
|
+
while (j < line.length) {
|
|
3837
|
+
const c = line[j];
|
|
3838
|
+
if (nestedQuote !== null) {
|
|
3839
|
+
if (c === "\\" && j + 1 < line.length) {
|
|
3840
|
+
j += 2;
|
|
3841
|
+
continue;
|
|
3842
|
+
}
|
|
3843
|
+
if (c === nestedQuote) {
|
|
3844
|
+
nestedQuote = null;
|
|
3845
|
+
}
|
|
3846
|
+
j++;
|
|
3847
|
+
continue;
|
|
3848
|
+
}
|
|
3849
|
+
if (holeDepth > 0) {
|
|
3850
|
+
if (c === '"' || c === "'") {
|
|
3851
|
+
nestedQuote = c;
|
|
3852
|
+
j++;
|
|
3853
|
+
continue;
|
|
3854
|
+
}
|
|
3855
|
+
if (c === "{") holeDepth++;
|
|
3856
|
+
else if (c === "}") holeDepth--;
|
|
3857
|
+
j++;
|
|
3858
|
+
continue;
|
|
3859
|
+
}
|
|
3860
|
+
if (c === "{") {
|
|
3861
|
+
holeDepth = 1;
|
|
3862
|
+
j++;
|
|
3863
|
+
continue;
|
|
3864
|
+
}
|
|
3865
|
+
if (c === '"') {
|
|
3866
|
+
if (line[j + 1] === '"') {
|
|
3867
|
+
j += 2;
|
|
3868
|
+
continue;
|
|
3869
|
+
}
|
|
3870
|
+
return { maskEnd: j + 1 };
|
|
3871
|
+
}
|
|
3872
|
+
j++;
|
|
3873
|
+
}
|
|
3874
|
+
return null;
|
|
3875
|
+
}
|
|
3876
|
+
case "psHereDouble":
|
|
3877
|
+
return line.startsWith('"@', from) ? { maskEnd: from + 2 } : null;
|
|
3878
|
+
case "psHereSingle":
|
|
3879
|
+
return line.startsWith("'@", from) ? { maskEnd: from + 2 } : null;
|
|
3880
|
+
default:
|
|
3881
|
+
return null;
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3884
|
+
var MULTILINE_OPENER_COMMENT_MARKERS = {
|
|
3885
|
+
php: ["//", "#"],
|
|
3886
|
+
kotlin: ["//"],
|
|
3887
|
+
csharp: ["//"],
|
|
3888
|
+
powershell: ["#"],
|
|
3889
|
+
swift: ["//"],
|
|
3890
|
+
elixir: ["#"]
|
|
3891
|
+
};
|
|
3892
|
+
var MULTILINE_OPENER_BLOCK_COMMENT_LANGS = /* @__PURE__ */ new Set(["php", "kotlin", "csharp", "swift"]);
|
|
3893
|
+
function isInsideSameLineBlockComment(line, idx, from = 0) {
|
|
3894
|
+
let comment = false;
|
|
3895
|
+
let j = from;
|
|
3896
|
+
while (j < idx) {
|
|
3897
|
+
if (!comment) {
|
|
3898
|
+
const open = line.indexOf("/*", j);
|
|
3899
|
+
if (open === -1 || open >= idx) return false;
|
|
3900
|
+
if (isInsideStringLiteral(line, open, from)) {
|
|
3901
|
+
j = open + 2;
|
|
3902
|
+
continue;
|
|
3903
|
+
}
|
|
3904
|
+
comment = true;
|
|
3905
|
+
j = open + 2;
|
|
3906
|
+
} else {
|
|
3907
|
+
const close = line.indexOf("*/", j);
|
|
3908
|
+
if (close === -1 || close >= idx) return true;
|
|
3909
|
+
comment = false;
|
|
3910
|
+
j = close + 2;
|
|
3911
|
+
}
|
|
3912
|
+
}
|
|
3913
|
+
return comment;
|
|
3914
|
+
}
|
|
3915
|
+
function findMultilineOpener(line, from, lang) {
|
|
3916
|
+
const commentIdx = lineCommentStartIndex(line, MULTILINE_OPENER_COMMENT_MARKERS[lang], from);
|
|
3917
|
+
const isCommented = (idx) => commentIdx !== -1 && idx >= commentIdx || MULTILINE_OPENER_BLOCK_COMMENT_LANGS.has(lang) && isInsideSameLineBlockComment(line, idx, from);
|
|
3918
|
+
if (lang === "php") {
|
|
3919
|
+
const re = /<<<\s*(['"]?)([A-Za-z_]\w*)\1/g;
|
|
3920
|
+
re.lastIndex = from;
|
|
3921
|
+
const m = re.exec(line);
|
|
3922
|
+
if (!m || isInsideStringLiteral(line, m.index, from) || isCommented(m.index)) return null;
|
|
3923
|
+
const identifier = m[2] ?? "";
|
|
3924
|
+
const kind = m[1] === "'" ? "nowdoc" : "heredoc";
|
|
3925
|
+
return { openStart: m.index, closesSameLine: null, state: { kind, identifier } };
|
|
3926
|
+
}
|
|
3927
|
+
if (lang === "kotlin") {
|
|
3928
|
+
const idx = line.indexOf('"""', from);
|
|
3929
|
+
if (idx === -1 || isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
|
|
3930
|
+
const closeIdx = line.indexOf('"""', idx + 3);
|
|
3931
|
+
if (closeIdx !== -1) {
|
|
3932
|
+
return { openStart: idx, closesSameLine: closeIdx + 3, state: { kind: "tripleQuote", identifier: "3" } };
|
|
3933
|
+
}
|
|
3934
|
+
return { openStart: idx, closesSameLine: null, state: { kind: "tripleQuote", identifier: "3" } };
|
|
3935
|
+
}
|
|
3936
|
+
if (lang === "swift") {
|
|
3937
|
+
const idx = line.indexOf('"""', from);
|
|
3938
|
+
if (idx === -1 || isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
|
|
3939
|
+
const closeIdx = line.indexOf('"""', idx + 3);
|
|
3940
|
+
if (closeIdx !== -1) {
|
|
3941
|
+
return { openStart: idx, closesSameLine: closeIdx + 3, state: { kind: "tripleQuote", identifier: "3" } };
|
|
3942
|
+
}
|
|
3943
|
+
return { openStart: idx, closesSameLine: null, state: { kind: "tripleQuote", identifier: "3" } };
|
|
3944
|
+
}
|
|
3945
|
+
if (lang === "elixir") {
|
|
3946
|
+
const candidates = [];
|
|
3947
|
+
const dq = line.indexOf('"""', from);
|
|
3948
|
+
if (dq !== -1) candidates.push([dq, "tripleQuote", '"""']);
|
|
3949
|
+
const sq = line.indexOf("'''", from);
|
|
3950
|
+
if (sq !== -1) candidates.push([sq, "tripleSingleQuote", "'''"]);
|
|
3951
|
+
candidates.sort((a, b) => a[0] - b[0]);
|
|
3952
|
+
const first = candidates[0];
|
|
3953
|
+
if (first === void 0) return null;
|
|
3954
|
+
const [idx, kind, delim] = first;
|
|
3955
|
+
if (isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
|
|
3956
|
+
const closeIdx = line.indexOf(delim, idx + 3);
|
|
3957
|
+
const state = { kind, identifier: "3" };
|
|
3958
|
+
if (closeIdx !== -1) return { openStart: idx, closesSameLine: closeIdx + 3, state };
|
|
3959
|
+
return { openStart: idx, closesSameLine: null, state };
|
|
3960
|
+
}
|
|
3961
|
+
if (lang === "csharp") {
|
|
3962
|
+
const tripleRe = /"{3,}/g;
|
|
3963
|
+
tripleRe.lastIndex = from;
|
|
3964
|
+
const tripleM = tripleRe.exec(line);
|
|
3965
|
+
let tripleIdx = tripleM ? tripleM.index : -1;
|
|
3966
|
+
const tripleLen = tripleM ? tripleM[0].length : 0;
|
|
3967
|
+
if (tripleIdx !== -1 && (isInsideStringLiteral(line, tripleIdx, from) || isCommented(tripleIdx))) tripleIdx = -1;
|
|
3968
|
+
const verbRe = /\$?@\$?"/g;
|
|
3969
|
+
verbRe.lastIndex = from;
|
|
3970
|
+
const verbM = verbRe.exec(line);
|
|
3971
|
+
let verbIdx = verbM ? verbM.index : -1;
|
|
3972
|
+
if (verbIdx !== -1 && isCommented(verbIdx)) verbIdx = -1;
|
|
3973
|
+
if (verbIdx !== -1 && isInsideStringLiteral(line, verbIdx, from)) verbIdx = -1;
|
|
3974
|
+
if (tripleIdx === -1 && verbIdx === -1) return null;
|
|
3975
|
+
const useTriple = tripleIdx !== -1 && (verbIdx === -1 || tripleIdx < verbIdx);
|
|
3976
|
+
if (useTriple) {
|
|
3977
|
+
const closeRe = new RegExp(`"{${tripleLen},}`);
|
|
3978
|
+
const closeM = closeRe.exec(line.slice(tripleIdx + tripleLen));
|
|
3979
|
+
if (closeM !== null) {
|
|
3980
|
+
const closeIdx = tripleIdx + tripleLen + closeM.index;
|
|
3981
|
+
return { openStart: tripleIdx, closesSameLine: closeIdx + closeM[0].length, state: { kind: "tripleQuote", identifier: String(tripleLen) } };
|
|
3982
|
+
}
|
|
3983
|
+
return { openStart: tripleIdx, closesSameLine: null, state: { kind: "tripleQuote", identifier: String(tripleLen) } };
|
|
3984
|
+
}
|
|
3985
|
+
const quoteIdx = verbIdx + (verbM?.[0].length ?? 1) - 1;
|
|
3986
|
+
const interpolated = (verbM?.[0] ?? "").includes("$");
|
|
3987
|
+
const closer = findMultilineCloser(line, quoteIdx + 1, { kind: "verbatim", identifier: "", interpolated });
|
|
3988
|
+
if (closer !== null) {
|
|
3989
|
+
return { openStart: verbIdx, closesSameLine: closer.maskEnd, state: { kind: "verbatim", identifier: "", interpolated } };
|
|
3990
|
+
}
|
|
3991
|
+
return { openStart: verbIdx, closesSameLine: null, state: { kind: "verbatim", identifier: "", interpolated } };
|
|
3992
|
+
}
|
|
3993
|
+
if (lang === "powershell") {
|
|
3994
|
+
const re = /@("|')\s*$/;
|
|
3995
|
+
const tail = line.slice(from);
|
|
3996
|
+
const m = re.exec(tail);
|
|
3997
|
+
if (!m) return null;
|
|
3998
|
+
const openStart = from + m.index;
|
|
3999
|
+
if (isCommented(openStart)) return null;
|
|
4000
|
+
if (isInsideStringLiteral(line, openStart, from)) return null;
|
|
4001
|
+
const kind = m[1] === '"' ? "psHereDouble" : "psHereSingle";
|
|
4002
|
+
return { openStart, closesSameLine: null, state: { kind, identifier: "" } };
|
|
4003
|
+
}
|
|
4004
|
+
return null;
|
|
4005
|
+
}
|
|
4006
|
+
function stripMultilineStringSpan(line, state, lang) {
|
|
4007
|
+
let code = "";
|
|
4008
|
+
let i = 0;
|
|
4009
|
+
let cur = state;
|
|
4010
|
+
while (i < line.length) {
|
|
4011
|
+
if (cur !== null) {
|
|
4012
|
+
const closed = findMultilineCloser(line, i, cur);
|
|
4013
|
+
if (closed === null) {
|
|
4014
|
+
code += " ".repeat(line.length - i);
|
|
4015
|
+
i = line.length;
|
|
4016
|
+
continue;
|
|
4017
|
+
}
|
|
4018
|
+
code += " ".repeat(closed.maskEnd - i);
|
|
4019
|
+
i = closed.maskEnd;
|
|
4020
|
+
cur = null;
|
|
4021
|
+
continue;
|
|
4022
|
+
}
|
|
4023
|
+
const opened = findMultilineOpener(line, i, lang);
|
|
4024
|
+
if (opened === null) {
|
|
4025
|
+
code += line.slice(i);
|
|
4026
|
+
break;
|
|
4027
|
+
}
|
|
4028
|
+
code += line.slice(i, opened.openStart);
|
|
4029
|
+
if (opened.closesSameLine !== null) {
|
|
4030
|
+
code += " ".repeat(opened.closesSameLine - opened.openStart);
|
|
4031
|
+
i = opened.closesSameLine;
|
|
4032
|
+
cur = null;
|
|
4033
|
+
} else {
|
|
4034
|
+
code += " ".repeat(line.length - opened.openStart);
|
|
4035
|
+
i = line.length;
|
|
4036
|
+
cur = opened.state;
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
4039
|
+
return { code, state: cur };
|
|
4040
|
+
}
|
|
4041
|
+
function makeSpanSymbol(filePath, name, kind, span, parent = "", lines, style) {
|
|
4042
|
+
return {
|
|
4043
|
+
filePath,
|
|
4044
|
+
name,
|
|
4045
|
+
kind,
|
|
4046
|
+
lineStart: span.startLine,
|
|
4047
|
+
lineEnd: span.endLine,
|
|
4048
|
+
body: span.body,
|
|
4049
|
+
docstring: lines !== void 0 && style !== void 0 ? precedingDocComment(lines, span.startLine, style) : "",
|
|
4050
|
+
parent
|
|
4051
|
+
};
|
|
4052
|
+
}
|
|
4053
|
+
function makeLineSymbol(filePath, name, kind, line, sig, parent, lines, style) {
|
|
4054
|
+
return {
|
|
4055
|
+
filePath,
|
|
4056
|
+
name,
|
|
4057
|
+
kind,
|
|
4058
|
+
lineStart: line,
|
|
4059
|
+
lineEnd: line,
|
|
4060
|
+
body: sig ?? "",
|
|
4061
|
+
docstring: lines !== void 0 && style !== void 0 ? precedingDocComment(lines, line, style) : "",
|
|
4062
|
+
parent: parent ?? ""
|
|
4063
|
+
};
|
|
4064
|
+
}
|
|
4065
|
+
function makeSymbolEmitter(symbols, sections, seen, filePath, maxSymbols = 500, maxHeadingLen = 120) {
|
|
4066
|
+
return function emit(name, kind, line) {
|
|
4067
|
+
if (!name || name.length > maxHeadingLen) return;
|
|
4068
|
+
if (symbols.length >= maxSymbols) return;
|
|
4069
|
+
const key = `${name}\0${kind}\0${line}`;
|
|
4070
|
+
if (seen.has(key)) return;
|
|
4071
|
+
seen.add(key);
|
|
4072
|
+
symbols.push({
|
|
4073
|
+
filePath,
|
|
4074
|
+
name,
|
|
4075
|
+
kind,
|
|
4076
|
+
lineStart: line,
|
|
4077
|
+
lineEnd: line,
|
|
4078
|
+
body: "",
|
|
4079
|
+
docstring: "",
|
|
4080
|
+
parent: ""
|
|
4081
|
+
});
|
|
4082
|
+
sections.push({ heading: name, level: 1, line, endLine: line });
|
|
4083
|
+
};
|
|
4084
|
+
}
|
|
4085
|
+
function assignFlatEndLines(sections, totalLines) {
|
|
4086
|
+
for (let i = 0; i < sections.length; i++) {
|
|
4087
|
+
const next = sections[i + 1];
|
|
4088
|
+
const s = sections[i];
|
|
4089
|
+
if (s === void 0) continue;
|
|
4090
|
+
const end = next !== void 0 ? next.line - 1 : totalLines;
|
|
4091
|
+
s.endLine = end < s.line ? s.line : end;
|
|
4092
|
+
}
|
|
4093
|
+
}
|
|
4094
|
+
function propagateEndLinesToSymbols(symbols, sections) {
|
|
4095
|
+
const sectionMap = /* @__PURE__ */ new Map();
|
|
4096
|
+
for (const sec of sections) {
|
|
4097
|
+
const key = `${sec.heading}\0${sec.line}`;
|
|
4098
|
+
const queue = sectionMap.get(key);
|
|
4099
|
+
if (queue !== void 0) queue.push(sec.endLine);
|
|
4100
|
+
else sectionMap.set(key, [sec.endLine]);
|
|
4101
|
+
}
|
|
4102
|
+
return symbols.map((sym) => {
|
|
4103
|
+
const key = `${sym.name}\0${sym.lineStart}`;
|
|
4104
|
+
const endLine = sectionMap.get(key)?.shift();
|
|
4105
|
+
if (endLine !== void 0 && endLine !== sym.lineEnd) {
|
|
4106
|
+
return { ...sym, lineEnd: endLine };
|
|
4107
|
+
}
|
|
4108
|
+
return sym;
|
|
4109
|
+
});
|
|
4110
|
+
}
|
|
4111
|
+
function findMatchingBraceEndLine(content, openBraceIndex, totalLines, lineIndex) {
|
|
4112
|
+
let depth = 0;
|
|
4113
|
+
let quote = null;
|
|
4114
|
+
for (let i = openBraceIndex; i < content.length; i++) {
|
|
4115
|
+
const ch = content[i];
|
|
4116
|
+
if (quote !== null) {
|
|
4117
|
+
if (ch === "\\") {
|
|
4118
|
+
i++;
|
|
4119
|
+
continue;
|
|
4120
|
+
}
|
|
4121
|
+
if (ch === quote) quote = null;
|
|
4122
|
+
continue;
|
|
4123
|
+
}
|
|
4124
|
+
if (ch === '"' || ch === "'") {
|
|
4125
|
+
quote = ch;
|
|
4126
|
+
continue;
|
|
4127
|
+
}
|
|
4128
|
+
if (ch === "{") depth++;
|
|
4129
|
+
else if (ch === "}") {
|
|
4130
|
+
depth--;
|
|
4131
|
+
if (depth === 0) {
|
|
4132
|
+
return offsetToLine(lineIndex, i);
|
|
4133
|
+
}
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
return totalLines;
|
|
4137
|
+
}
|
|
4138
|
+
|
|
4139
|
+
// src/languages/ini_idx.ts
|
|
4140
|
+
var MAX_SECTIONS = 200;
|
|
4141
|
+
var MAX_HEADING_LEN = 200;
|
|
4142
|
+
var MAX_ENV_KEYS = 200;
|
|
4143
|
+
var HEADER_RE = /^\[([^\]\r\n]+)\]\s*(?:[;#].*)?$/;
|
|
4144
|
+
var ENV_KEY_RE = /^(?:export\s+)?([A-Za-z_][\w.-]*)\s*(?:=|:(?!\/\/))/;
|
|
4145
|
+
function extractIni(content, filePath) {
|
|
4146
|
+
const symbols = [];
|
|
4147
|
+
const sections = [];
|
|
4148
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4149
|
+
const lines = content.split(/\r?\n/);
|
|
4150
|
+
const totalLines = lines.length;
|
|
4151
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4152
|
+
if (symbols.length >= MAX_SECTIONS) break;
|
|
4153
|
+
const line = lines[i] ?? "";
|
|
4154
|
+
if (!line || line[0] !== "[") continue;
|
|
4155
|
+
const m = HEADER_RE.exec(line);
|
|
4156
|
+
if (m === null) continue;
|
|
4157
|
+
const name = m[1]?.trim() ?? "";
|
|
4158
|
+
if (!name || name.length > MAX_HEADING_LEN) continue;
|
|
4159
|
+
const key = `${name}\0${i + 1}`;
|
|
4160
|
+
if (seen.has(key)) continue;
|
|
4161
|
+
seen.add(key);
|
|
4162
|
+
symbols.push(makeLineSymbol(filePath, name, "ini_section", i + 1));
|
|
4163
|
+
sections.push({ heading: name, level: 1, line: i + 1, endLine: i + 1 });
|
|
4164
|
+
}
|
|
4165
|
+
sections.sort((a, b) => a.line - b.line);
|
|
4166
|
+
assignFlatEndLines(sections, totalLines);
|
|
4167
|
+
return propagateEndLinesToSymbols(symbols, sections);
|
|
4168
|
+
}
|
|
4169
|
+
function _isEscapedQuote(line, i, q) {
|
|
4170
|
+
if (q === "'") return false;
|
|
4171
|
+
let backslashes = 0;
|
|
4172
|
+
let j = i - 1;
|
|
4173
|
+
while (j >= 0 && line[j] === "\\") {
|
|
4174
|
+
backslashes++;
|
|
4175
|
+
j--;
|
|
4176
|
+
}
|
|
4177
|
+
return backslashes % 2 === 1;
|
|
4178
|
+
}
|
|
4179
|
+
function _lineClosesQuote(line, q) {
|
|
4180
|
+
for (let i = 0; i < line.length; i++) {
|
|
4181
|
+
if (line[i] === q && !_isEscapedQuote(line, i, q)) return true;
|
|
4182
|
+
}
|
|
4183
|
+
return false;
|
|
4184
|
+
}
|
|
4185
|
+
function _detectOpenQuote(value) {
|
|
4186
|
+
const trimmed = value.replace(/^\s+/, "");
|
|
4187
|
+
const q = trimmed[0];
|
|
4188
|
+
if (q !== '"' && q !== "'") return null;
|
|
4189
|
+
for (let i = 1; i < trimmed.length; i++) {
|
|
4190
|
+
if (trimmed[i] === q && !_isEscapedQuote(trimmed, i, q)) return null;
|
|
4191
|
+
}
|
|
4192
|
+
return q;
|
|
4193
|
+
}
|
|
4194
|
+
function extractEnv(content, filePath) {
|
|
4195
|
+
const symbols = [];
|
|
4196
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4197
|
+
const lines = content.split(/\r?\n/);
|
|
4198
|
+
let openQuote = null;
|
|
4199
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4200
|
+
if (symbols.length >= MAX_ENV_KEYS) break;
|
|
4201
|
+
const line = lines[i] ?? "";
|
|
4202
|
+
if (openQuote !== null) {
|
|
4203
|
+
if (_lineClosesQuote(line, openQuote)) openQuote = null;
|
|
4204
|
+
continue;
|
|
4205
|
+
}
|
|
4206
|
+
if (!line || line[0] === "#" || line[0] === ";" || line[0] === " " || line[0] === " ") continue;
|
|
4207
|
+
const m = ENV_KEY_RE.exec(line);
|
|
4208
|
+
if (m === null) continue;
|
|
4209
|
+
const name = m[1]?.trim() ?? "";
|
|
4210
|
+
if (!name || name.length > MAX_HEADING_LEN) continue;
|
|
4211
|
+
const key = `${name}\0${i + 1}`;
|
|
4212
|
+
if (seen.has(key)) continue;
|
|
4213
|
+
seen.add(key);
|
|
4214
|
+
symbols.push(makeLineSymbol(filePath, name, "env_key", i + 1));
|
|
4215
|
+
openQuote = _detectOpenQuote(line.slice(m[0].length));
|
|
4216
|
+
}
|
|
4217
|
+
return symbols;
|
|
4218
|
+
}
|
|
4219
|
+
|
|
4220
|
+
// src/dotenv_redact.ts
|
|
4221
|
+
var DOTENV_VALUE_PLACEHOLDER = "[REDACTED:dotenv_value]";
|
|
4222
|
+
var ASSIGNMENT_RE = /^(\s*(?:export\s+)?[A-Za-z_][\w.-]*\s*(?:\+?=|:(?!\/\/)))/;
|
|
4223
|
+
var SAFE_LINE_RE = /^\s*(?:[#;].*)?$/;
|
|
4224
|
+
function isDotenvPath(filePath) {
|
|
4225
|
+
return detectLanguage(filePath) === "env_file";
|
|
4226
|
+
}
|
|
4227
|
+
function redactDotenvValues(text) {
|
|
4228
|
+
const lines = text.split("\n");
|
|
4229
|
+
const out = [];
|
|
4230
|
+
let openQuote = null;
|
|
4231
|
+
for (const raw of lines) {
|
|
4232
|
+
const hasCr = raw.endsWith("\r");
|
|
4233
|
+
const line = hasCr ? raw.slice(0, -1) : raw;
|
|
4234
|
+
const eol = hasCr ? "\r" : "";
|
|
4235
|
+
const emit = (s) => {
|
|
4236
|
+
out.push(`${s}${eol}`);
|
|
4237
|
+
};
|
|
4238
|
+
if (openQuote !== null) {
|
|
4239
|
+
if (_lineClosesQuote(line, openQuote)) openQuote = null;
|
|
4240
|
+
emit(DOTENV_VALUE_PLACEHOLDER);
|
|
4241
|
+
continue;
|
|
4242
|
+
}
|
|
4243
|
+
if (SAFE_LINE_RE.test(line)) {
|
|
4244
|
+
emit(line);
|
|
4245
|
+
continue;
|
|
4246
|
+
}
|
|
4247
|
+
const m = ASSIGNMENT_RE.exec(line);
|
|
4248
|
+
if (m === null || m[1] === void 0) {
|
|
4249
|
+
emit(DOTENV_VALUE_PLACEHOLDER);
|
|
4250
|
+
continue;
|
|
4251
|
+
}
|
|
4252
|
+
const prefix = m[1];
|
|
4253
|
+
openQuote = _detectOpenQuote(line.slice(prefix.length));
|
|
4254
|
+
emit(`${prefix}${DOTENV_VALUE_PLACEHOLDER}`);
|
|
4255
|
+
}
|
|
4256
|
+
return out.join("\n");
|
|
4257
|
+
}
|
|
4258
|
+
function redactIfDotenv(filePath, text) {
|
|
4259
|
+
return isDotenvPath(filePath) ? redactDotenvValues(text) : text;
|
|
4260
|
+
}
|
|
4261
|
+
|
|
3251
4262
|
// src/db.ts
|
|
3252
|
-
init_define_import_meta_env();
|
|
3253
4263
|
import * as fs6 from "node:fs";
|
|
3254
4264
|
import { createRequire as createRequire2 } from "node:module";
|
|
3255
|
-
import * as
|
|
4265
|
+
import * as path7 from "node:path";
|
|
3256
4266
|
import Database from "better-sqlite3";
|
|
3257
4267
|
var _require = createRequire2(import.meta.url);
|
|
3258
4268
|
var _connections = /* @__PURE__ */ new Map();
|
|
@@ -3504,7 +4514,7 @@ CREATE TRIGGER IF NOT EXISTS cache_recall_au AFTER UPDATE ON cache_recall BEGIN
|
|
|
3504
4514
|
VALUES (new.row_id, new.label, new.content);
|
|
3505
4515
|
END;
|
|
3506
4516
|
`;
|
|
3507
|
-
var SCHEMA_VERSION =
|
|
4517
|
+
var SCHEMA_VERSION = 11;
|
|
3508
4518
|
function alterTableIdempotent(conn, sql) {
|
|
3509
4519
|
try {
|
|
3510
4520
|
conn.exec(sql);
|
|
@@ -3512,6 +4522,26 @@ function alterTableIdempotent(conn, sql) {
|
|
|
3512
4522
|
if (!(err instanceof Error) || !/duplicate column/i.test(err.message)) throw err;
|
|
3513
4523
|
}
|
|
3514
4524
|
}
|
|
4525
|
+
function purgeDotenvEmbeddings(conn) {
|
|
4526
|
+
let paths;
|
|
4527
|
+
try {
|
|
4528
|
+
paths = conn.prepare("SELECT DISTINCT file_path FROM chunks").all().map((r) => r.file_path).filter(isDotenvPath);
|
|
4529
|
+
} catch {
|
|
4530
|
+
return;
|
|
4531
|
+
}
|
|
4532
|
+
if (paths.length === 0) return;
|
|
4533
|
+
for (const p of paths) {
|
|
4534
|
+
try {
|
|
4535
|
+
conn.prepare("DELETE FROM chunk_vectors WHERE rowid IN (SELECT id FROM chunks WHERE file_path = ?)").run(p);
|
|
4536
|
+
} catch {
|
|
4537
|
+
}
|
|
4538
|
+
conn.prepare("DELETE FROM chunks WHERE file_path = ?").run(p);
|
|
4539
|
+
try {
|
|
4540
|
+
conn.prepare("UPDATE files SET embed_sha = NULL WHERE path = ?").run(p);
|
|
4541
|
+
} catch {
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
}
|
|
3515
4545
|
var MIGRATIONS = {
|
|
3516
4546
|
// 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.
|
|
3517
4547
|
1: (conn) => alterTableIdempotent(conn, "ALTER TABLE files ADD COLUMN embed_sha TEXT"),
|
|
@@ -3520,7 +4550,15 @@ var MIGRATIONS = {
|
|
|
3520
4550
|
// 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.
|
|
3521
4551
|
8: (conn) => alterTableIdempotent(conn, "ALTER TABLE symbols ADD COLUMN parent TEXT NOT NULL DEFAULT ''"),
|
|
3522
4552
|
// 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.
|
|
3523
|
-
9: (conn) => alterTableIdempotent(conn, "ALTER TABLE hint_emissions ADD COLUMN bytes_emitted INTEGER")
|
|
4553
|
+
9: (conn) => alterTableIdempotent(conn, "ALTER TABLE hint_emissions ADD COLUMN bytes_emitted INTEGER"),
|
|
4554
|
+
// v10 -> v11: purge chunks (and their vectors) for dotenv files. Until this version, a tracked
|
|
4555
|
+
// `.env` was chunked and embedded verbatim on the git path, so `semantic` returned its values --
|
|
4556
|
+
// see dotenv_redact.ts. Redacting from now on is not enough on its own: the embed-freshness gate
|
|
4557
|
+
// (isEmbedFresh in parser.ts) skips a file whose bytes have not changed, so an already-indexed
|
|
4558
|
+
// .env would have kept serving its pre-fix chunks indefinitely. Deleting the rows here both
|
|
4559
|
+
// removes the stored secrets and, by clearing embed_sha, makes the next drain re-embed the file
|
|
4560
|
+
// through the redacting path.
|
|
4561
|
+
10: purgeDotenvEmbeddings
|
|
3524
4562
|
};
|
|
3525
4563
|
function runMigrations(conn, fromVersion, toVersion) {
|
|
3526
4564
|
for (let v = fromVersion; v < toVersion; v++) {
|
|
@@ -3566,8 +4604,8 @@ function initConnection(conn) {
|
|
|
3566
4604
|
}
|
|
3567
4605
|
}
|
|
3568
4606
|
function resolveDbPath(dbPath) {
|
|
3569
|
-
if (
|
|
3570
|
-
if (dbPath.includes("/") || dbPath.includes("\\")) return
|
|
4607
|
+
if (path7.isAbsolute(dbPath)) return dbPath;
|
|
4608
|
+
if (dbPath.includes("/") || dbPath.includes("\\")) return path7.resolve(dbPath);
|
|
3571
4609
|
return safeJoin(dataDir(), dbPath);
|
|
3572
4610
|
}
|
|
3573
4611
|
function connectionKey(dbPath) {
|
|
@@ -3578,7 +4616,7 @@ function getDb(dbPath) {
|
|
|
3578
4616
|
const { resolved, key } = connectionKey(dbPath);
|
|
3579
4617
|
const existing = _connections.get(key);
|
|
3580
4618
|
if (existing !== void 0) return existing;
|
|
3581
|
-
const dir =
|
|
4619
|
+
const dir = path7.dirname(resolved);
|
|
3582
4620
|
try {
|
|
3583
4621
|
ensureDirSync(dir);
|
|
3584
4622
|
} catch (e) {
|
|
@@ -3609,7 +4647,6 @@ function closeAllDbs() {
|
|
|
3609
4647
|
registerReset(closeAllDbs);
|
|
3610
4648
|
|
|
3611
4649
|
// src/render/ansi.ts
|
|
3612
|
-
init_define_import_meta_env();
|
|
3613
4650
|
function _colorStream(isatty) {
|
|
3614
4651
|
if (process.env["NO_COLOR"]) return false;
|
|
3615
4652
|
return isatty;
|
|
@@ -3684,11 +4721,9 @@ var C = {
|
|
|
3684
4721
|
};
|
|
3685
4722
|
|
|
3686
4723
|
// src/stats.ts
|
|
3687
|
-
|
|
3688
|
-
import * as path7 from "node:path";
|
|
4724
|
+
import * as path8 from "node:path";
|
|
3689
4725
|
|
|
3690
4726
|
// src/render/stats_renderer.ts
|
|
3691
|
-
init_define_import_meta_env();
|
|
3692
4727
|
var _STATS_MESSAGES_FALLBACK = {
|
|
3693
4728
|
bytesModeOnlyNote: "tracks bytes, not vision tokens",
|
|
3694
4729
|
sessionHintSplitNote: "session_hint shows realized savings; session_hint_overhead shows injected hint cost",
|
|
@@ -4578,7 +5613,7 @@ var _globalSchemaApplied = /* @__PURE__ */ new Set();
|
|
|
4578
5613
|
registerReset(() => _globalSchemaApplied.clear());
|
|
4579
5614
|
function getGlobalDb(homeDir) {
|
|
4580
5615
|
const basePath = homeDir ? dataDirForHome(homeDir) : dataDir();
|
|
4581
|
-
const dbPath =
|
|
5616
|
+
const dbPath = path8.join(basePath, "global.db");
|
|
4582
5617
|
const db = getDb(dbPath);
|
|
4583
5618
|
if (!_globalSchemaApplied.has(dbPath)) {
|
|
4584
5619
|
db.exec(GLOBAL_SCHEMA_SQL);
|
|
@@ -4816,7 +5851,6 @@ function renderStats2(opts) {
|
|
|
4816
5851
|
}
|
|
4817
5852
|
|
|
4818
5853
|
// src/secret_redact.ts
|
|
4819
|
-
init_define_import_meta_env();
|
|
4820
5854
|
var SECRET_PATTERNS = [
|
|
4821
5855
|
// Anthropic keys share OpenAI's "sk-" prefix but are more specific
|
|
4822
5856
|
// ("sk-ant-"), so they're matched first — the generic OpenAI pattern's
|
|
@@ -4844,8 +5878,13 @@ var SECRET_PATTERNS = [
|
|
|
4844
5878
|
// Redacts only the token itself, not the "Authorization: Bearer " prefix -- the lookbehind
|
|
4845
5879
|
// anchors on the header name and scheme so the surrounding request-log line stays readable,
|
|
4846
5880
|
// matching how AWS_ACCESS_KEY_ID=... above keeps its own prefix intact.
|
|
4847
|
-
|
|
4848
|
-
|
|
5881
|
+
// The optional quotes on either side of the colon are what let this see a header carried in
|
|
5882
|
+
// JSON rather than in raw wire format. Without them the lookbehind demanded the colon sit
|
|
5883
|
+
// directly against the header name and the scheme directly against the space, so a body like
|
|
5884
|
+
// {"Authorization": "Bearer <token>"} -- the shape any logged fetch or MCP result arrives in
|
|
5885
|
+
// -- matched nothing and the token was cached verbatim.
|
|
5886
|
+
["auth_bearer_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}Bearer[ \t])[A-Za-z0-9\-._~+/]{10,}=*/gi],
|
|
5887
|
+
["auth_basic_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}Basic[ \t])[A-Za-z0-9+/]{6,}=*/gi],
|
|
4849
5888
|
// JWTs have no distinctive prefix of their own, but the base64url encoding of the smallest
|
|
4850
5889
|
// realistic header ('{"alg":' or similar) always starts with "eyJ", so that's the practical
|
|
4851
5890
|
// anchor here -- each of the three dot-separated segments requires a minimum length to avoid
|
|
@@ -4864,6 +5903,13 @@ var SECRET_PATTERNS = [
|
|
|
4864
5903
|
// are what make the short, generic 'sig' name safe to key on: a prose or code mention of "sig"
|
|
4865
5904
|
// never sits directly after a query separator followed by that much opaque token.
|
|
4866
5905
|
["presigned_signature", /(?<=[?&](?:X-Amz-Signature|X-Goog-Signature|sig)=)[A-Za-z0-9%+/=_-]{16,}/gi],
|
|
5906
|
+
// A password inside a connection url. `postgres://user:hunter2@db.internal` carries the
|
|
5907
|
+
// credential in the authority section, where there is no `key=value` separator for the
|
|
5908
|
+
// generic pattern below to anchor on, so a DATABASE_URL echoed by a failing migration or a
|
|
5909
|
+
// psql error went through untouched. The anchors are what keep this narrow: a scheme's `://`,
|
|
5910
|
+
// a userinfo segment, the colon, and a following `@`. `http://host:8080/path` has no `@` and
|
|
5911
|
+
// is left alone; so is any url without credentials.
|
|
5912
|
+
["url_credentials", /(?<=:\/\/[^\s:@/]{1,64}:)[^\s:@/]{1,256}(?=@)/g],
|
|
4867
5913
|
// Generic key=value assignments in .env-file and connection-string/query-string shape. The
|
|
4868
5914
|
// lookbehind again redacts only the value, and the value's character class deliberately
|
|
4869
5915
|
// excludes whitespace, '&', ';', '#', quote characters, and '[' ']' ':' -- that exclusion is
|
|
@@ -4879,13 +5925,19 @@ var SECRET_PATTERNS = [
|
|
|
4879
5925
|
// this cannot backtrack catastrophically -- there is no nested or overlapping quantifier for
|
|
4880
5926
|
// the engine to explore multiple ways of matching, so removing the upper bound does not
|
|
4881
5927
|
// introduce a ReDoS risk.
|
|
5928
|
+
// Quotes are permitted around the separator, but never inside the value class. A quoted value
|
|
5929
|
+
// is the ordinary way secrets are written -- .env files, JSON, YAML, TOML all quote by default
|
|
5930
|
+
// -- and the lookbehind used to stop dead at the opening quote, so `API_KEY="..."` passed
|
|
5931
|
+
// through in full while the bare `API_KEY=...` was caught. The closing quote of the key name
|
|
5932
|
+
// blocked it from the other side too, which is what kept every JSON body unredacted. Keeping
|
|
5933
|
+
// quotes out of the value class is still what stops the match running past the closing quote.
|
|
4882
5934
|
// The keyword may be a prefix of a longer key name rather than the whole of it, so the
|
|
4883
5935
|
// trailing identifier class below is load-bearing: without it the lookbehind required the
|
|
4884
5936
|
// keyword to sit immediately before the separator, and AWS_SECRET_ACCESS_KEY=,
|
|
4885
5937
|
// SECRET_KEY=, and DB_PASSWORD_HASH= all passed through in full. That class matches
|
|
4886
5938
|
// identifier characters only, so prose that merely mentions a keyword still never reaches
|
|
4887
5939
|
// a separator and stays unredacted. api[_-]?key covers the apikey and api-key spellings too.
|
|
4888
|
-
["generic_secret_assignment", /(?<=(?:password|passwd|secret|api[_-]?key)[a-z0-9_-]
|
|
5940
|
+
["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]
|
|
4889
5941
|
];
|
|
4890
5942
|
function redactSecrets(text) {
|
|
4891
5943
|
let count = 0;
|
|
@@ -4900,7 +5952,6 @@ function redactSecrets(text) {
|
|
|
4900
5952
|
}
|
|
4901
5953
|
|
|
4902
5954
|
// src/filters.ts
|
|
4903
|
-
init_define_import_meta_env();
|
|
4904
5955
|
var DROP = () => null;
|
|
4905
5956
|
var FILTERS = [
|
|
4906
5957
|
{
|
|
@@ -4961,7 +6012,6 @@ var FILTERS = [
|
|
|
4961
6012
|
];
|
|
4962
6013
|
|
|
4963
6014
|
// src/bash_compress.ts
|
|
4964
|
-
init_define_import_meta_env();
|
|
4965
6015
|
function stripAnsiCodes(text) {
|
|
4966
6016
|
return stripAnsiEscapes(text);
|
|
4967
6017
|
}
|
|
@@ -5055,6 +6105,36 @@ export {
|
|
|
5055
6105
|
loadPersistedConfig,
|
|
5056
6106
|
CONFIG_KEY_ENV_OVERRIDES,
|
|
5057
6107
|
saveConfig,
|
|
6108
|
+
precedingDocComment,
|
|
6109
|
+
buildLineIndex,
|
|
6110
|
+
offsetToLine,
|
|
6111
|
+
stripCstyleComments,
|
|
6112
|
+
stripXmlComments,
|
|
6113
|
+
scanQuotedStringEnd,
|
|
6114
|
+
stripJsComments,
|
|
6115
|
+
stripHashComments,
|
|
6116
|
+
maskHtmlNoise,
|
|
6117
|
+
findHtmlHeadingMatches,
|
|
6118
|
+
isInsideStringLiteral,
|
|
6119
|
+
stripBlockCommentSpan,
|
|
6120
|
+
stripNestedBlockCommentSpan,
|
|
6121
|
+
stripLineComment,
|
|
6122
|
+
stripStringLiterals,
|
|
6123
|
+
stripMultilineStringSpan,
|
|
6124
|
+
makeSpanSymbol,
|
|
6125
|
+
makeLineSymbol,
|
|
6126
|
+
makeSymbolEmitter,
|
|
6127
|
+
assignFlatEndLines,
|
|
6128
|
+
propagateEndLinesToSymbols,
|
|
6129
|
+
findMatchingBraceEndLine,
|
|
6130
|
+
extractIni,
|
|
6131
|
+
_lineClosesQuote,
|
|
6132
|
+
_detectOpenQuote,
|
|
6133
|
+
extractEnv,
|
|
6134
|
+
detectLanguage,
|
|
6135
|
+
unsupportedLanguageName,
|
|
6136
|
+
isDotenvPath,
|
|
6137
|
+
redactIfDotenv,
|
|
5058
6138
|
getDb,
|
|
5059
6139
|
colorStdout,
|
|
5060
6140
|
RESET,
|