token-goat 2.9.10 → 2.9.12
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 +54 -11
- package/SECURITY.md +17 -19
- package/THIRD_PARTY_NOTICES.md +667 -0
- package/dist/{token-goat-chunk-YFXFUG3L.mjs → token-goat-chunk-4CK445AW.mjs} +1275 -655
- package/dist/token-goat-chunk-6F5TLJC7.mjs +3728 -0
- package/dist/{token-goat-chunk-ATVQ6IIT.mjs → token-goat-chunk-6NIGPPN6.mjs} +10 -2
- package/dist/{token-goat-chunk-SLGOIXKF.mjs → token-goat-chunk-A6QTLAWO.mjs} +85 -328
- package/dist/{token-goat-chunk-7ALFFPJW.mjs → token-goat-chunk-GCXX67HM.mjs} +2699 -2175
- package/dist/{token-goat-chunk-PA5UXNOT.mjs → token-goat-chunk-GM6QZWCF.mjs} +5088 -7746
- package/dist/{token-goat-chunk-DSHYDU53.mjs → token-goat-chunk-HKFOH6JH.mjs} +11 -7
- package/dist/{token-goat-chunk-LYWIRYCF.mjs → token-goat-chunk-LHLQFGWQ.mjs} +1 -1
- package/dist/token-goat-chunk-LOCOX2ML.mjs +3564 -0
- package/dist/token-goat-chunk-OTW7LC4Y.mjs +5942 -0
- package/dist/{token-goat-chunk-FQD3OB5W.mjs → token-goat-chunk-QCQUIPIP.mjs} +6068 -1687
- package/dist/{token-goat-chunk-DCYHAUW3.mjs → token-goat-chunk-SBYRP3X4.mjs} +69 -37
- package/dist/{token-goat-chunk-JS44SRAX.mjs → token-goat-chunk-SF2CKCFQ.mjs} +3 -2
- package/dist/{token-goat-chunk-PXWBHSFB.mjs → token-goat-chunk-T6M7DAW3.mjs} +31 -4
- package/dist/{token-goat-chunk-ZQODJQTP.mjs → token-goat-chunk-THLHC6QJ.mjs} +354 -180
- package/dist/{token-goat-chunk-VCEK77ED.mjs → token-goat-chunk-TOGYS5A7.mjs} +5307 -6350
- package/dist/{token-goat-chunk-2TJBY5RD.mjs → token-goat-chunk-VRWX6QYW.mjs} +6 -5
- package/dist/token-goat-hook.mjs +6 -5
- package/dist/token-goat.core.mjs +8 -6
- package/docs/C4_RUNTIME_ARCHITECTURE.md +1 -1
- package/docs/cli.md +4 -1
- package/docs/install.md +131 -11
- package/docs/security.md +2 -0
- package/package.json +8 -3
|
@@ -1,8 +1,32 @@
|
|
|
1
1
|
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
|
-
DEFAULT_QUERY_LIMIT,
|
|
5
4
|
IMPORT_RE,
|
|
5
|
+
extractAbap,
|
|
6
|
+
extractAbl,
|
|
7
|
+
extractAsm,
|
|
8
|
+
extractBatch,
|
|
9
|
+
extractCShader,
|
|
10
|
+
extractCmake,
|
|
11
|
+
extractCobol,
|
|
12
|
+
extractErlang,
|
|
13
|
+
extractFortran,
|
|
14
|
+
extractGroovy,
|
|
15
|
+
extractJcl,
|
|
16
|
+
extractMatlab,
|
|
17
|
+
extractNatural,
|
|
18
|
+
extractObjc,
|
|
19
|
+
extractPascal,
|
|
20
|
+
extractPerl,
|
|
21
|
+
extractPli,
|
|
22
|
+
extractRpg,
|
|
23
|
+
extractSas,
|
|
24
|
+
extractSolidity,
|
|
25
|
+
extractThrift,
|
|
26
|
+
stripLeadingAttributes
|
|
27
|
+
} from "./token-goat-chunk-6F5TLJC7.mjs";
|
|
28
|
+
import {
|
|
29
|
+
DEFAULT_QUERY_LIMIT,
|
|
6
30
|
ImageDecodeError,
|
|
7
31
|
MAX_OVER_FETCH,
|
|
8
32
|
MAX_ZIP_INPUT_BYTES,
|
|
@@ -11,19 +35,17 @@ import {
|
|
|
11
35
|
SKIP_DIRS,
|
|
12
36
|
ZipInputTooLargeError,
|
|
13
37
|
ZipOutputTooLargeError,
|
|
14
|
-
capJsonRows,
|
|
15
38
|
countRefs,
|
|
16
39
|
countSymbols,
|
|
17
40
|
createLazyModuleLoader,
|
|
18
41
|
distinctSymbolKinds,
|
|
19
|
-
eachUnfencedLine,
|
|
20
42
|
emptyIndexMessage,
|
|
21
43
|
enqueueDirtyPathSafe,
|
|
22
|
-
estimateTokens,
|
|
23
44
|
extractPdfMeta,
|
|
24
45
|
extractPdfOutline,
|
|
25
46
|
extractPdfText,
|
|
26
47
|
fenceUntrusted,
|
|
48
|
+
findContainingSection,
|
|
27
49
|
formatCsvProfile,
|
|
28
50
|
formatCsvTable,
|
|
29
51
|
getEmbeddingCoverage,
|
|
@@ -35,8 +57,11 @@ import {
|
|
|
35
57
|
isImagePath,
|
|
36
58
|
isIndexEmptyForProject,
|
|
37
59
|
isOcrEngineAvailable,
|
|
60
|
+
isPrivateIpv4Octets,
|
|
61
|
+
isPrivateIpv6Groups,
|
|
38
62
|
isTextHeavy,
|
|
39
|
-
|
|
63
|
+
isTreeSitterAvailable,
|
|
64
|
+
listSections,
|
|
40
65
|
loadBlob,
|
|
41
66
|
locatePdfPages,
|
|
42
67
|
mergeNearbyHits,
|
|
@@ -52,36 +77,62 @@ import {
|
|
|
52
77
|
queryRefs,
|
|
53
78
|
queryRefsByContext,
|
|
54
79
|
querySymbols,
|
|
80
|
+
readPdfFileWithinBounds,
|
|
81
|
+
readSection,
|
|
55
82
|
scanAndRecord,
|
|
56
83
|
searchEvidenceSemantically,
|
|
57
84
|
searchSemantic,
|
|
58
85
|
searchSymbolsFts,
|
|
59
86
|
shrinkImage,
|
|
60
87
|
storeBlob,
|
|
61
|
-
stripLeadingAttributes,
|
|
62
|
-
stripTomlComment,
|
|
63
|
-
tomlBracketDelta,
|
|
64
|
-
trimToBudget,
|
|
65
88
|
unzipBounded,
|
|
66
89
|
urlPolicyDenialReason,
|
|
67
|
-
walkProject
|
|
68
|
-
|
|
69
|
-
yamlOpenQuoteAfter
|
|
70
|
-
} from "./token-goat-chunk-PA5UXNOT.mjs";
|
|
90
|
+
walkProject
|
|
91
|
+
} from "./token-goat-chunk-GM6QZWCF.mjs";
|
|
71
92
|
import {
|
|
72
93
|
Database,
|
|
94
|
+
FILENAME_LANGUAGE,
|
|
95
|
+
TREE_SITTER_LANGUAGES,
|
|
96
|
+
basenameImportsExtension,
|
|
97
|
+
capJsonRows,
|
|
98
|
+
colorStdout,
|
|
99
|
+
detectLanguage,
|
|
100
|
+
detectLanguageOfFile,
|
|
101
|
+
estimateTokens,
|
|
102
|
+
fileIsAbsent,
|
|
103
|
+
findProject,
|
|
104
|
+
fingerprintContent,
|
|
105
|
+
fingerprintFile,
|
|
106
|
+
getDb,
|
|
107
|
+
getDisplayRoot,
|
|
108
|
+
languageLabel,
|
|
109
|
+
loadConfig,
|
|
110
|
+
partialRefsReason,
|
|
111
|
+
recordStat,
|
|
112
|
+
redactIfDotenv,
|
|
113
|
+
redactSecrets,
|
|
114
|
+
resolveProjectRoot,
|
|
115
|
+
savedTokensFromBytes,
|
|
116
|
+
shortFingerprint,
|
|
117
|
+
stripAnsi,
|
|
118
|
+
trimToBudget,
|
|
119
|
+
unsupportedLanguageName
|
|
120
|
+
} from "./token-goat-chunk-TOGYS5A7.mjs";
|
|
121
|
+
import {
|
|
122
|
+
registerReset
|
|
123
|
+
} from "./token-goat-chunk-EEIDFMEM.mjs";
|
|
124
|
+
import {
|
|
73
125
|
PER_FILE_COUNTERFACTUAL_CEILING,
|
|
126
|
+
UNTRUSTED_FILE_TAG,
|
|
74
127
|
UNTRUSTED_GITHUB_TAG,
|
|
75
|
-
|
|
76
|
-
_lineClosesQuote,
|
|
128
|
+
UNTRUSTED_HTML_TAG,
|
|
77
129
|
atomicWriteBytes,
|
|
78
130
|
buildContextWindow,
|
|
79
|
-
buildLineIndex,
|
|
80
|
-
colorStdout,
|
|
81
131
|
compileGrepMatcher,
|
|
132
|
+
compileGuardedRegex,
|
|
82
133
|
countNoun,
|
|
83
134
|
decodeSource,
|
|
84
|
-
|
|
135
|
+
displaySafeJson,
|
|
85
136
|
displaySafeText,
|
|
86
137
|
ensureNewline,
|
|
87
138
|
escapeRegExp,
|
|
@@ -89,370 +140,39 @@ import {
|
|
|
89
140
|
extractErrorMessage,
|
|
90
141
|
fenceUntrustedContent,
|
|
91
142
|
fenceUntrustedFileContent,
|
|
92
|
-
fileIsAbsent,
|
|
93
143
|
filtersFilteredToEmptyNotice,
|
|
94
|
-
|
|
95
|
-
findProject,
|
|
96
|
-
fingerprintContent,
|
|
97
|
-
fingerprintFile,
|
|
144
|
+
foldCaseForContainment,
|
|
98
145
|
foldPath,
|
|
99
|
-
getDb,
|
|
100
|
-
getDisplayRoot,
|
|
101
146
|
globalDbPath,
|
|
102
147
|
grepFilteredToEmptyNotice,
|
|
148
|
+
isAblSource,
|
|
103
149
|
isInsideRoot,
|
|
150
|
+
isMatlabSource,
|
|
151
|
+
isObjcHeader,
|
|
152
|
+
isObjcSource,
|
|
153
|
+
isPascalSource,
|
|
154
|
+
isPerlSource,
|
|
155
|
+
isPrologSource,
|
|
104
156
|
isTestFile,
|
|
105
|
-
loadConfig,
|
|
106
157
|
normalizePath,
|
|
107
|
-
offsetToLine,
|
|
108
158
|
pushAll,
|
|
109
|
-
recordStat,
|
|
110
|
-
redactIfDotenv,
|
|
111
|
-
redactSecrets,
|
|
112
159
|
redactUrlQuery,
|
|
113
160
|
renderContextWindow,
|
|
114
161
|
requireNonNegativeStrictInt,
|
|
115
162
|
requirePositiveStrictInt,
|
|
116
163
|
resolveIndexPath,
|
|
117
164
|
resolveOnPath,
|
|
118
|
-
resolveProjectRoot,
|
|
119
165
|
runGit,
|
|
120
|
-
savedTokensFromBytes,
|
|
121
|
-
shortFingerprint,
|
|
122
|
-
stripAnsi,
|
|
123
166
|
stripBom,
|
|
167
|
+
supportRequestLine,
|
|
124
168
|
toDisplayPath,
|
|
125
|
-
unsupportedLanguageName,
|
|
126
169
|
windowsCmdQuoteArg,
|
|
127
170
|
withExtension
|
|
128
|
-
} from "./token-goat-chunk-
|
|
129
|
-
import {
|
|
130
|
-
registerReset
|
|
131
|
-
} from "./token-goat-chunk-EEIDFMEM.mjs";
|
|
171
|
+
} from "./token-goat-chunk-LOCOX2ML.mjs";
|
|
132
172
|
import {
|
|
133
173
|
init_define_import_meta_env
|
|
134
174
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
135
175
|
|
|
136
|
-
// src/section_reader.ts
|
|
137
|
-
init_define_import_meta_env();
|
|
138
|
-
import { readFileSync } from "node:fs";
|
|
139
|
-
function parseHeadingSpec(spec, headers) {
|
|
140
|
-
const m = /^([^#\r\n]+)#(\d+)$/.exec(spec);
|
|
141
|
-
if (m !== null && m[1] !== void 0 && m[2] !== void 0) {
|
|
142
|
-
const specLower = spec.trim().toLowerCase();
|
|
143
|
-
const isLiteralHeading = headers?.some((h) => h.heading.trim().toLowerCase() === specLower) ?? false;
|
|
144
|
-
if (isLiteralHeading) {
|
|
145
|
-
return { base: spec.trim(), ordinal: null };
|
|
146
|
-
}
|
|
147
|
-
return { base: m[1].trim(), ordinal: Number.parseInt(m[2], 10) };
|
|
148
|
-
}
|
|
149
|
-
return { base: spec.trim(), ordinal: null };
|
|
150
|
-
}
|
|
151
|
-
function normalizeHeading(s) {
|
|
152
|
-
let n = s.replace(/[—–]/g, "-");
|
|
153
|
-
n = n.replace(/\s*\([^)]+\)\s*$/, "");
|
|
154
|
-
n = n.replace(/^\d+\.\s+/, "");
|
|
155
|
-
return n.replace(/\s+/g, " ").trim();
|
|
156
|
-
}
|
|
157
|
-
function normalizeHeadingStrip(s) {
|
|
158
|
-
let n = s.replace(/\s*[—–].*$/, "");
|
|
159
|
-
n = n.replace(/\s*\([^)]+\)\s*$/, "");
|
|
160
|
-
n = n.replace(/^\d+\.\s+/, "");
|
|
161
|
-
return n.replace(/\s+/g, " ").trim();
|
|
162
|
-
}
|
|
163
|
-
var MIN_WIDEN_WORD_LEN = 3;
|
|
164
|
-
var MARKDOWN_HEADER_RE = /^(#{1,6})\s+([^\r\n]+?)(?:\s+#+)?\s*$/;
|
|
165
|
-
var TABLE_HEADER_RE = /^\s*\[+\s*([^\]]+?)\s*\]+\s*(?:[#;].*)?$/;
|
|
166
|
-
var PYTHON_HEADER_RE = /^(\s*)(?:async\s+)?(?:def|class)\s+([A-Za-z_]\w*)/;
|
|
167
|
-
var KEYVALUE_HEADER_RE = /^([A-Za-z_][\w.-]*)\s*(?:=|:(?!\/\/))/;
|
|
168
|
-
var ENV_KEYVALUE_HEADER_RE = /^(?:export\s+)?([A-Za-z_][\w.-]*)\s*(?:=|:(?!\/\/))/;
|
|
169
|
-
function findMarkdownHeaders(lines) {
|
|
170
|
-
const headers = [];
|
|
171
|
-
for (const [i, line] of eachUnfencedLine(lines)) {
|
|
172
|
-
const m = MARKDOWN_HEADER_RE.exec(line);
|
|
173
|
-
if (m === null || m[1] === void 0 || m[2] === void 0) continue;
|
|
174
|
-
headers.push({ heading: m[2].trim(), level: m[1].length, index: i });
|
|
175
|
-
}
|
|
176
|
-
return headers;
|
|
177
|
-
}
|
|
178
|
-
function findTableHeaders(lines, isToml) {
|
|
179
|
-
const headers = [];
|
|
180
|
-
let openDelim = null;
|
|
181
|
-
let arrayDepth = 0;
|
|
182
|
-
for (let i = 0; i < lines.length; i++) {
|
|
183
|
-
const line = lines[i];
|
|
184
|
-
if (line === void 0) continue;
|
|
185
|
-
if (openDelim !== null) {
|
|
186
|
-
const closeIdx = line.indexOf(openDelim);
|
|
187
|
-
if (closeIdx === -1) continue;
|
|
188
|
-
const restStart = closeIdx + openDelim.length;
|
|
189
|
-
const m2 = TABLE_HEADER_RE.exec(line.slice(restStart));
|
|
190
|
-
if (m2 !== null && m2[1] !== void 0) headers.push({ heading: m2[1].trim(), level: 1, index: i });
|
|
191
|
-
openDelim = lineOpenDelimiterAfter(stripTomlComment(line.slice(restStart)), 0);
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
if (isToml && arrayDepth > 0) {
|
|
195
|
-
arrayDepth = Math.max(0, arrayDepth + tomlBracketDelta(stripTomlComment(line)));
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
const m = TABLE_HEADER_RE.exec(line);
|
|
199
|
-
if (m !== null && m[1] !== void 0) headers.push({ heading: m[1].trim(), level: 1, index: i });
|
|
200
|
-
if (isToml) {
|
|
201
|
-
const code = stripTomlComment(line);
|
|
202
|
-
openDelim = lineOpenDelimiterAfter(code, 0);
|
|
203
|
-
if (openDelim === null) arrayDepth = Math.max(0, tomlBracketDelta(code));
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
return headers;
|
|
207
|
-
}
|
|
208
|
-
function findPythonHeaders(lines) {
|
|
209
|
-
const headers = [];
|
|
210
|
-
const indentStack = [];
|
|
211
|
-
let openDelim = null;
|
|
212
|
-
for (let i = 0; i < lines.length; i++) {
|
|
213
|
-
const line = lines[i];
|
|
214
|
-
if (line === void 0) continue;
|
|
215
|
-
if (openDelim !== null) {
|
|
216
|
-
const closeIdx = line.indexOf(openDelim);
|
|
217
|
-
if (closeIdx === -1) continue;
|
|
218
|
-
openDelim = lineOpenDelimiterAfter(line, closeIdx + openDelim.length);
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
const m = PYTHON_HEADER_RE.exec(line);
|
|
222
|
-
if (m === null || m[1] === void 0 || m[2] === void 0) {
|
|
223
|
-
openDelim = lineOpenDelimiterAfter(line, 0);
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
const indent = m[1].replace(/\t/g, " ").length;
|
|
227
|
-
while (indentStack.length > 0 && indent <= (indentStack[indentStack.length - 1] ?? -1)) {
|
|
228
|
-
indentStack.pop();
|
|
229
|
-
}
|
|
230
|
-
const level = indentStack.length + 1;
|
|
231
|
-
indentStack.push(indent);
|
|
232
|
-
headers.push({ heading: m[2], level, index: i });
|
|
233
|
-
openDelim = lineOpenDelimiterAfter(line, 0);
|
|
234
|
-
}
|
|
235
|
-
return headers;
|
|
236
|
-
}
|
|
237
|
-
function findKeyValueHeaders(lines, language) {
|
|
238
|
-
const headers = [];
|
|
239
|
-
const isEnv = language === "env_file";
|
|
240
|
-
let openQuote = null;
|
|
241
|
-
for (let i = 0; i < lines.length; i++) {
|
|
242
|
-
const line = lines[i];
|
|
243
|
-
if (line === void 0) continue;
|
|
244
|
-
if (openQuote !== null) {
|
|
245
|
-
const closed = isEnv ? _lineClosesQuote(line, openQuote) : yamlLineClosesQuote(line, openQuote);
|
|
246
|
-
if (closed) openQuote = null;
|
|
247
|
-
continue;
|
|
248
|
-
}
|
|
249
|
-
const scanned = isEnv ? line.replace(/^[ \t]+/, "") : line;
|
|
250
|
-
const m = (isEnv ? ENV_KEYVALUE_HEADER_RE : KEYVALUE_HEADER_RE).exec(scanned);
|
|
251
|
-
if (m === null || m[1] === void 0) continue;
|
|
252
|
-
headers.push({ heading: m[1], level: 1, index: i });
|
|
253
|
-
openQuote = isEnv ? _detectOpenQuote(scanned.slice(m[0].length)) : yamlOpenQuoteAfter(line, m[0].length);
|
|
254
|
-
}
|
|
255
|
-
return headers;
|
|
256
|
-
}
|
|
257
|
-
function findHtmlHeaders(text) {
|
|
258
|
-
const lineIndex = buildLineIndex(text);
|
|
259
|
-
const headers = [];
|
|
260
|
-
for (const hm of findHtmlHeadingMatches(text)) {
|
|
261
|
-
if (!hm.heading) continue;
|
|
262
|
-
const index = offsetToLine(lineIndex, hm.offset) - 1;
|
|
263
|
-
headers.push({ heading: hm.heading, level: hm.level, index });
|
|
264
|
-
}
|
|
265
|
-
return headers;
|
|
266
|
-
}
|
|
267
|
-
function findHeaders(text, language) {
|
|
268
|
-
const lines = text.split("\n");
|
|
269
|
-
if (language === "markdown") return { headers: findMarkdownHeaders(lines), kind: "markdown" };
|
|
270
|
-
if (language === "html" || language === "liquid") return { headers: findHtmlHeaders(text), kind: "markdown" };
|
|
271
|
-
if (language === "toml") return { headers: findTableHeaders(lines, true), kind: "table-toml" };
|
|
272
|
-
if (language === "python") return { headers: findPythonHeaders(lines), kind: "python" };
|
|
273
|
-
if (language === "ini") return { headers: findTableHeaders(lines, false), kind: "table-flat" };
|
|
274
|
-
if (language === "yaml" || language === "env_file")
|
|
275
|
-
return { headers: findKeyValueHeaders(lines, language), kind: "keyvalue" };
|
|
276
|
-
const md = findMarkdownHeaders(lines);
|
|
277
|
-
if (md.length > 0) return { headers: md, kind: "markdown" };
|
|
278
|
-
const tbl = findTableHeaders(lines, false);
|
|
279
|
-
if (tbl.length > 0) return { headers: tbl, kind: "table-toml" };
|
|
280
|
-
return { headers: findKeyValueHeaders(lines, language), kind: "keyvalue" };
|
|
281
|
-
}
|
|
282
|
-
function sectionEndIndex(headers, headerPos, totalLines) {
|
|
283
|
-
const current = headers[headerPos];
|
|
284
|
-
if (current === void 0) return totalLines;
|
|
285
|
-
for (let j = headerPos + 1; j < headers.length; j++) {
|
|
286
|
-
const next = headers[j];
|
|
287
|
-
if (next === void 0) continue;
|
|
288
|
-
if (next.level <= current.level) return next.index;
|
|
289
|
-
}
|
|
290
|
-
return totalLines;
|
|
291
|
-
}
|
|
292
|
-
function tableSectionEndIndex(headers, headerPos, totalLines) {
|
|
293
|
-
const current = headers[headerPos];
|
|
294
|
-
if (current === void 0) return totalLines;
|
|
295
|
-
const prefix = current.heading + ".";
|
|
296
|
-
for (let j = headerPos + 1; j < headers.length; j++) {
|
|
297
|
-
const next = headers[j];
|
|
298
|
-
if (next === void 0) continue;
|
|
299
|
-
if (next.heading.startsWith(prefix)) continue;
|
|
300
|
-
return next.index;
|
|
301
|
-
}
|
|
302
|
-
return totalLines;
|
|
303
|
-
}
|
|
304
|
-
function resolveHeaderPos(headers, base, ordinal) {
|
|
305
|
-
const target = base.toLowerCase();
|
|
306
|
-
const normalizedTarget = normalizeHeading(base).toLowerCase();
|
|
307
|
-
const strippedTarget = normalizeHeadingStrip(base).toLowerCase();
|
|
308
|
-
const exactMatches = [];
|
|
309
|
-
const normalizedMatches = [];
|
|
310
|
-
const strippedMatches = [];
|
|
311
|
-
for (let i = 0; i < headers.length; i++) {
|
|
312
|
-
const h = headers[i];
|
|
313
|
-
if (h === void 0) continue;
|
|
314
|
-
const headingLower = h.heading.toLowerCase();
|
|
315
|
-
if (headingLower === target) {
|
|
316
|
-
exactMatches.push(i);
|
|
317
|
-
} else if (normalizeHeading(h.heading).toLowerCase() === normalizedTarget) {
|
|
318
|
-
normalizedMatches.push(i);
|
|
319
|
-
} else if (normalizeHeadingStrip(h.heading).toLowerCase() === strippedTarget) {
|
|
320
|
-
strippedMatches.push(i);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
const matches = exactMatches.length > 0 ? exactMatches : normalizedMatches.length > 0 ? normalizedMatches : strippedMatches;
|
|
324
|
-
if (matches.length > 0) {
|
|
325
|
-
const pick2 = ordinal === null ? 0 : ordinal - 1;
|
|
326
|
-
const headerPos = matches[pick2];
|
|
327
|
-
if (headerPos === void 0) return null;
|
|
328
|
-
let occurrences = null;
|
|
329
|
-
if (ordinal === null && matches.length > 1) {
|
|
330
|
-
occurrences = [];
|
|
331
|
-
for (const i of matches) {
|
|
332
|
-
const h = headers[i];
|
|
333
|
-
if (h !== void 0) occurrences.push(h.index + 1);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
return { headerPos, redirectedFrom: null, occurrences };
|
|
337
|
-
}
|
|
338
|
-
if (ordinal !== null || normalizedTarget.length === 0) return null;
|
|
339
|
-
let prefixPos = -1;
|
|
340
|
-
const distinct = /* @__PURE__ */ new Set();
|
|
341
|
-
for (let i = 0; i < headers.length; i++) {
|
|
342
|
-
const h = headers[i];
|
|
343
|
-
if (h === void 0) continue;
|
|
344
|
-
const norm = normalizeHeading(h.heading).toLowerCase();
|
|
345
|
-
if (norm.startsWith(normalizedTarget)) {
|
|
346
|
-
distinct.add(norm);
|
|
347
|
-
if (prefixPos === -1) prefixPos = i;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
if (distinct.size === 1 && prefixPos !== -1) {
|
|
351
|
-
const chosen = headers[prefixPos];
|
|
352
|
-
if (chosen === void 0) return null;
|
|
353
|
-
return { headerPos: prefixPos, redirectedFrom: base, occurrences: null };
|
|
354
|
-
}
|
|
355
|
-
const queryWords = normalizedTarget.split(/\s+/).filter((w) => w.length >= MIN_WIDEN_WORD_LEN);
|
|
356
|
-
if (queryWords.length === 0) return null;
|
|
357
|
-
const widenedMatches = [];
|
|
358
|
-
for (let i = 0; i < headers.length; i++) {
|
|
359
|
-
const h = headers[i];
|
|
360
|
-
if (h === void 0) continue;
|
|
361
|
-
const headingWords = normalizeHeading(h.heading).toLowerCase().split(/\s+/);
|
|
362
|
-
const allWordsMatch = queryWords.every((qw) => headingWords.some((hw) => hw.includes(qw)));
|
|
363
|
-
if (allWordsMatch) widenedMatches.push(i);
|
|
364
|
-
}
|
|
365
|
-
if (widenedMatches.length !== 1) return null;
|
|
366
|
-
const widenedPos = widenedMatches[0];
|
|
367
|
-
if (widenedPos === void 0) return null;
|
|
368
|
-
return { headerPos: widenedPos, redirectedFrom: base, occurrences: null };
|
|
369
|
-
}
|
|
370
|
-
function buildSectionResult(headers, kind, lines, headerPos, redirectedFrom) {
|
|
371
|
-
const header = headers[headerPos];
|
|
372
|
-
if (header === void 0) return null;
|
|
373
|
-
const endIndex = kind === "table-toml" ? tableSectionEndIndex(headers, headerPos, lines.length) : sectionEndIndex(headers, headerPos, lines.length);
|
|
374
|
-
let endExclusive = endIndex;
|
|
375
|
-
while (endExclusive > header.index + 1 && (lines[endExclusive - 1] === "" || lines[endExclusive - 1] === "\r")) {
|
|
376
|
-
endExclusive--;
|
|
377
|
-
}
|
|
378
|
-
const content = lines.slice(header.index, endExclusive).join("\n");
|
|
379
|
-
const result = {
|
|
380
|
-
heading: header.heading,
|
|
381
|
-
content,
|
|
382
|
-
lineStart: header.index + 1,
|
|
383
|
-
lineEnd: endExclusive
|
|
384
|
-
};
|
|
385
|
-
return redirectedFrom === null ? result : { ...result, redirectedFrom };
|
|
386
|
-
}
|
|
387
|
-
function resolveSectionFromText(text, headingSpec, language) {
|
|
388
|
-
const { headers, kind } = findHeaders(text, language);
|
|
389
|
-
const { base, ordinal } = parseHeadingSpec(headingSpec, headers);
|
|
390
|
-
if (base.length === 0) return null;
|
|
391
|
-
const lines = text.split("\n");
|
|
392
|
-
const resolved = resolveHeaderPos(headers, base, ordinal);
|
|
393
|
-
if (resolved === null) return null;
|
|
394
|
-
const built = buildSectionResult(headers, kind, lines, resolved.headerPos, resolved.redirectedFrom);
|
|
395
|
-
if (built === null || resolved.occurrences === null) return built;
|
|
396
|
-
return { ...built, occurrences: resolved.occurrences };
|
|
397
|
-
}
|
|
398
|
-
function extractSection(text, headingSpec) {
|
|
399
|
-
return resolveSectionFromText(text, headingSpec, "unknown");
|
|
400
|
-
}
|
|
401
|
-
function readTextForSections(filePath, readFn) {
|
|
402
|
-
let text;
|
|
403
|
-
if (readFn !== void 0) {
|
|
404
|
-
const read = readFn(filePath);
|
|
405
|
-
if (read === null) return null;
|
|
406
|
-
text = read;
|
|
407
|
-
} else {
|
|
408
|
-
try {
|
|
409
|
-
text = decodeSource(readFileSync(filePath));
|
|
410
|
-
} catch {
|
|
411
|
-
return null;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
if (text.charCodeAt(0) === 65279) {
|
|
415
|
-
text = text.slice(1);
|
|
416
|
-
}
|
|
417
|
-
return redactIfDotenv(filePath, text);
|
|
418
|
-
}
|
|
419
|
-
function readSection(filePath, headingSpec, readFn) {
|
|
420
|
-
const text = readTextForSections(filePath, readFn);
|
|
421
|
-
if (text === null) return null;
|
|
422
|
-
return resolveSectionFromText(text, headingSpec, detectLanguage(filePath));
|
|
423
|
-
}
|
|
424
|
-
function findContainingSection(filePath, lineStart, lineEnd, readFn) {
|
|
425
|
-
const text = readTextForSections(filePath, readFn);
|
|
426
|
-
if (text === null) return null;
|
|
427
|
-
const language = detectLanguage(filePath);
|
|
428
|
-
const { headers, kind } = findHeaders(text, language);
|
|
429
|
-
if (headers.length === 0) return null;
|
|
430
|
-
const lines = text.split("\n");
|
|
431
|
-
let bestPos = -1;
|
|
432
|
-
let bestHeaderLine = -1;
|
|
433
|
-
for (let i = 0; i < headers.length; i++) {
|
|
434
|
-
const header = headers[i];
|
|
435
|
-
if (header === void 0) continue;
|
|
436
|
-
const endIndex = kind === "table-toml" ? tableSectionEndIndex(headers, i, lines.length) : sectionEndIndex(headers, i, lines.length);
|
|
437
|
-
const sectionLineStart = header.index + 1;
|
|
438
|
-
if (sectionLineStart <= lineStart && lineEnd <= endIndex) {
|
|
439
|
-
if (header.index > bestHeaderLine) {
|
|
440
|
-
bestHeaderLine = header.index;
|
|
441
|
-
bestPos = i;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
if (bestPos === -1) return null;
|
|
446
|
-
return buildSectionResult(headers, kind, lines, bestPos, null);
|
|
447
|
-
}
|
|
448
|
-
function listSections(filePath, readFn) {
|
|
449
|
-
const text = readTextForSections(filePath, readFn);
|
|
450
|
-
if (text === null) return [];
|
|
451
|
-
const language = detectLanguage(filePath);
|
|
452
|
-
const { headers } = findHeaders(text, language);
|
|
453
|
-
return headers.map((h) => h.heading);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
176
|
// src/graph_commands.ts
|
|
457
177
|
init_define_import_meta_env();
|
|
458
178
|
import * as fs6 from "node:fs";
|
|
@@ -480,35 +200,15 @@ function isRefIndexedLanguage(language) {
|
|
|
480
200
|
function isRefIndexedFile(filePath) {
|
|
481
201
|
return isRefIndexedLanguage(detectLanguage(filePath));
|
|
482
202
|
}
|
|
483
|
-
var LANGUAGE_LABELS = /* @__PURE__ */ new Map([
|
|
484
|
-
["csharp", "C#"],
|
|
485
|
-
["cpp", "C++"],
|
|
486
|
-
["c", "C"],
|
|
487
|
-
["php", "PHP"],
|
|
488
|
-
["powershell", "PowerShell"],
|
|
489
|
-
["sql", "SQL"],
|
|
490
|
-
["graphql", "GraphQL"],
|
|
491
|
-
["proto", "Protocol Buffers"],
|
|
492
|
-
["html", "HTML"],
|
|
493
|
-
["css", "CSS"],
|
|
494
|
-
["toml", "TOML"],
|
|
495
|
-
["json", "JSON"],
|
|
496
|
-
["yaml", "YAML"],
|
|
497
|
-
["ini", "INI"],
|
|
498
|
-
["env_file", "env file"],
|
|
499
|
-
["ipynb", "Jupyter notebook"],
|
|
500
|
-
["salesforce_metadata", "Salesforce metadata"],
|
|
501
|
-
["salesforce_markup", "Salesforce markup"],
|
|
502
|
-
["unknown", "this file type"]
|
|
503
|
-
]);
|
|
504
|
-
function languageLabel(language) {
|
|
505
|
-
return LANGUAGE_LABELS.get(language) ?? language;
|
|
506
|
-
}
|
|
507
203
|
function refBlindLanguageNotice(symbolName, language, displayPath) {
|
|
204
|
+
const partial = partialRefsReason(language);
|
|
205
|
+
if (partial !== void 0) {
|
|
206
|
+
return `No recorded references to '${symbolName}' (${displayPath}). ${partial}, so an empty result is not evidence the name is unused. Search the source directly as well, e.g. \`rg -n -w ${symbolName}\`.`;
|
|
207
|
+
}
|
|
508
208
|
return `Cannot determine references for '${symbolName}': ${languageLabel(language)} call sites are not indexed (${displayPath}). This is a gap in token-goat's index, not evidence the symbol is unreferenced. Search the source directly instead, e.g. \`rg -n -w ${symbolName}\`.`;
|
|
509
209
|
}
|
|
510
210
|
var REF_BLIND_KIND_REASON = "the index records value-position references only (calls, `new`, macro invocations), never type annotations, so a type declaration has no ref rows however widely it is used";
|
|
511
|
-
var REF_BLIND_DEF_PROBE_LIMIT =
|
|
211
|
+
var REF_BLIND_DEF_PROBE_LIMIT = -1;
|
|
512
212
|
function kindWithArticle(kind) {
|
|
513
213
|
return `${/^[aeiou]/.test(kind) ? "an" : "a"} ${kind}`;
|
|
514
214
|
}
|
|
@@ -874,16 +574,16 @@ function outlineXml(xmlText, opts = {}) {
|
|
|
874
574
|
function formatXmlOutline(summary) {
|
|
875
575
|
const lines = [];
|
|
876
576
|
lines.push(
|
|
877
|
-
`Root element: <${summary.rootTag}> (${summary.totalElements} total elements, ${summary.uniqueTags.length} unique tags, max depth ${summary.maxDepth})`
|
|
577
|
+
`Root element: <${displaySafeText(summary.rootTag)}> (${summary.totalElements} total elements, ${summary.uniqueTags.length} unique tags, max depth ${summary.maxDepth})`
|
|
878
578
|
);
|
|
879
579
|
if (summary.doctype) {
|
|
880
|
-
lines.push(`DOCTYPE: ${summary.doctype}`);
|
|
580
|
+
lines.push(`DOCTYPE: ${displaySafeText(summary.doctype)}`);
|
|
881
581
|
}
|
|
882
582
|
const nsKeys = Object.keys(summary.namespaces);
|
|
883
583
|
if (nsKeys.length > 0) {
|
|
884
584
|
lines.push("Namespaces:");
|
|
885
585
|
for (const [k, v] of Object.entries(summary.namespaces)) {
|
|
886
|
-
lines.push(` ${k}: ${v}`);
|
|
586
|
+
lines.push(` ${displaySafeText(k)}: ${displaySafeText(v)}`);
|
|
887
587
|
}
|
|
888
588
|
}
|
|
889
589
|
lines.push("");
|
|
@@ -895,12 +595,12 @@ function formatXmlOutline(summary) {
|
|
|
895
595
|
for (const [k, v] of Object.entries(node.attributes)) {
|
|
896
596
|
if (["id", "name", "type", "key", "class", "code", "status", "value"].includes(k.toLowerCase()) || attrKeys.length <= 3) {
|
|
897
597
|
const valPreview = v.length > 35 ? `${v.slice(0, 32)}...` : v;
|
|
898
|
-
attrParts.push(`${k}="${valPreview}"`);
|
|
598
|
+
attrParts.push(`${displaySafeText(k)}="${displaySafeText(valPreview)}"`);
|
|
899
599
|
}
|
|
900
600
|
}
|
|
901
601
|
const attrStr = attrParts.length > 0 ? ` [${attrParts.join(" ")}]` : "";
|
|
902
602
|
const countStr = node.childCount > 0 ? ` (${node.childCount} children)` : node.textLength > 0 ? ` (~${node.textLength} chars text)` : " (empty)";
|
|
903
|
-
lines.push(`${pad}<${node.tag}>${attrStr}${countStr}`);
|
|
603
|
+
lines.push(`${pad}<${displaySafeText(node.tag)}>${attrStr}${countStr}`);
|
|
904
604
|
for (const child of node.children) {
|
|
905
605
|
renderNode(child, indent + 1);
|
|
906
606
|
}
|
|
@@ -1137,6 +837,693 @@ function queryXml(xmlText, pathStr) {
|
|
|
1137
837
|
return { items: currentCandidates, fanned: hasFanned || currentCandidates.length > 1 };
|
|
1138
838
|
}
|
|
1139
839
|
|
|
840
|
+
// src/html_query.ts
|
|
841
|
+
init_define_import_meta_env();
|
|
842
|
+
var HTML_VOID_TAGS = /* @__PURE__ */ new Set([
|
|
843
|
+
"area",
|
|
844
|
+
"base",
|
|
845
|
+
"br",
|
|
846
|
+
"col",
|
|
847
|
+
"embed",
|
|
848
|
+
"hr",
|
|
849
|
+
"img",
|
|
850
|
+
"input",
|
|
851
|
+
"link",
|
|
852
|
+
"meta",
|
|
853
|
+
"param",
|
|
854
|
+
"source",
|
|
855
|
+
"track",
|
|
856
|
+
"wbr"
|
|
857
|
+
]);
|
|
858
|
+
var RAW_TEXT_TAGS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
859
|
+
function findTagEnd(html, startPos) {
|
|
860
|
+
let inQuote = null;
|
|
861
|
+
for (let i = startPos + 1; i < html.length; i++) {
|
|
862
|
+
const ch = html[i];
|
|
863
|
+
if (inQuote) {
|
|
864
|
+
if (ch === inQuote) inQuote = null;
|
|
865
|
+
} else {
|
|
866
|
+
if (ch === '"' || ch === "'") {
|
|
867
|
+
inQuote = ch;
|
|
868
|
+
} else if (ch === ">") {
|
|
869
|
+
return i;
|
|
870
|
+
} else if (ch === "<") {
|
|
871
|
+
return -1;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
return -1;
|
|
876
|
+
}
|
|
877
|
+
function findRawTextEnd(html, startPos, tag) {
|
|
878
|
+
const target = `</${tag}`;
|
|
879
|
+
const targetLen = target.length;
|
|
880
|
+
const limit = html.length - targetLen;
|
|
881
|
+
for (let i = startPos; i <= limit; i++) {
|
|
882
|
+
if (html[i] === "<" && html[i + 1] === "/") {
|
|
883
|
+
if (html.slice(i, i + targetLen).toLowerCase() === target) {
|
|
884
|
+
const nextChar = html[i + targetLen];
|
|
885
|
+
if (!nextChar || /\s|>|\//.test(nextChar)) {
|
|
886
|
+
return i;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
return html.length;
|
|
892
|
+
}
|
|
893
|
+
function parseHtml(html) {
|
|
894
|
+
const issues = [];
|
|
895
|
+
const tagCounts = {};
|
|
896
|
+
const root = {
|
|
897
|
+
tag: "#root",
|
|
898
|
+
attributes: {},
|
|
899
|
+
children: [],
|
|
900
|
+
parent: null,
|
|
901
|
+
text: "",
|
|
902
|
+
rawHtml: "",
|
|
903
|
+
startOffset: 0,
|
|
904
|
+
endOffset: html.length,
|
|
905
|
+
line: 1,
|
|
906
|
+
endLine: 1,
|
|
907
|
+
isVoid: false
|
|
908
|
+
};
|
|
909
|
+
let currentParent = root;
|
|
910
|
+
let currentLine = 1;
|
|
911
|
+
let pos = 0;
|
|
912
|
+
const len = html.length;
|
|
913
|
+
const seenIds = /* @__PURE__ */ new Map();
|
|
914
|
+
while (pos < len) {
|
|
915
|
+
if (html[pos] === "\n") {
|
|
916
|
+
currentLine++;
|
|
917
|
+
pos++;
|
|
918
|
+
continue;
|
|
919
|
+
}
|
|
920
|
+
if (html.startsWith("<!--", pos)) {
|
|
921
|
+
const endComment = html.indexOf("-->", pos + 4);
|
|
922
|
+
const commentEndPos = endComment !== -1 ? endComment + 3 : len;
|
|
923
|
+
const commentLines = (html.slice(pos, commentEndPos).match(/\n/g) || []).length;
|
|
924
|
+
currentLine += commentLines;
|
|
925
|
+
pos = commentEndPos;
|
|
926
|
+
continue;
|
|
927
|
+
}
|
|
928
|
+
if (html.startsWith("<!doctype", pos) || html.startsWith("<!DOCTYPE", pos)) {
|
|
929
|
+
const endDoc = html.indexOf(">", pos);
|
|
930
|
+
const docEndPos = endDoc !== -1 ? endDoc + 1 : len;
|
|
931
|
+
const docLines = (html.slice(pos, docEndPos).match(/\n/g) || []).length;
|
|
932
|
+
currentLine += docLines;
|
|
933
|
+
pos = docEndPos;
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
if (currentParent && RAW_TEXT_TAGS.has(currentParent.tag.toLowerCase())) {
|
|
937
|
+
const closeTag = `</${currentParent.tag}`;
|
|
938
|
+
if (!html.slice(pos, pos + closeTag.length).toLowerCase().startsWith(closeTag.toLowerCase())) {
|
|
939
|
+
const rawTextEnd = findRawTextEnd(html, pos, currentParent.tag.toLowerCase());
|
|
940
|
+
const textContent = html.slice(pos, rawTextEnd);
|
|
941
|
+
currentParent.text += textContent;
|
|
942
|
+
const textLines = (textContent.match(/\n/g) || []).length;
|
|
943
|
+
currentLine += textLines;
|
|
944
|
+
pos = rawTextEnd;
|
|
945
|
+
continue;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
if (html[pos] === "<") {
|
|
949
|
+
const tagStartLine = currentLine;
|
|
950
|
+
const closeBracket = findTagEnd(html, pos);
|
|
951
|
+
if (closeBracket === -1) {
|
|
952
|
+
issues.push({
|
|
953
|
+
line: tagStartLine,
|
|
954
|
+
type: "warning",
|
|
955
|
+
message: "Unescaped '<' character in text: consider '<'",
|
|
956
|
+
rule: "unescaped-angle-bracket"
|
|
957
|
+
});
|
|
958
|
+
if (currentParent) {
|
|
959
|
+
currentParent.text += "<";
|
|
960
|
+
}
|
|
961
|
+
pos++;
|
|
962
|
+
continue;
|
|
963
|
+
}
|
|
964
|
+
const tagSlice = html.slice(pos, closeBracket + 1);
|
|
965
|
+
const sliceLines = (tagSlice.match(/\n/g) || []).length;
|
|
966
|
+
if (html[pos + 1] === "/") {
|
|
967
|
+
const closeMatch = /^<\/([a-zA-Z][a-zA-Z0-9_-]*)\s*>$/i.exec(tagSlice.trim());
|
|
968
|
+
if (closeMatch) {
|
|
969
|
+
const closeTag = closeMatch[1].toLowerCase();
|
|
970
|
+
if (!tagCounts[closeTag]) tagCounts[closeTag] = { open: 0, close: 0, diff: 0 };
|
|
971
|
+
if (!HTML_VOID_TAGS.has(closeTag)) {
|
|
972
|
+
tagCounts[closeTag].close++;
|
|
973
|
+
}
|
|
974
|
+
if (HTML_VOID_TAGS.has(closeTag)) {
|
|
975
|
+
issues.push({
|
|
976
|
+
line: tagStartLine,
|
|
977
|
+
type: "warning",
|
|
978
|
+
message: `Void tag <${closeTag}> should not have a closing tag </${closeTag}>`,
|
|
979
|
+
rule: "void-tag-closing"
|
|
980
|
+
});
|
|
981
|
+
} else {
|
|
982
|
+
let matchNode = currentParent;
|
|
983
|
+
while (matchNode && matchNode.tag !== "#root" && matchNode.tag.toLowerCase() !== closeTag) {
|
|
984
|
+
matchNode = matchNode.parent;
|
|
985
|
+
}
|
|
986
|
+
if (matchNode && matchNode.tag !== "#root") {
|
|
987
|
+
let unclosed = currentParent;
|
|
988
|
+
while (unclosed && unclosed !== matchNode) {
|
|
989
|
+
if (!HTML_VOID_TAGS.has(unclosed.tag.toLowerCase())) {
|
|
990
|
+
issues.push({
|
|
991
|
+
line: unclosed.line,
|
|
992
|
+
type: "error",
|
|
993
|
+
message: `Unclosed tag <${unclosed.tag}> before closing </${closeTag}> on line ${tagStartLine}`,
|
|
994
|
+
rule: "unclosed-tag"
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
unclosed.endLine = tagStartLine;
|
|
998
|
+
unclosed.endOffset = pos;
|
|
999
|
+
unclosed = unclosed.parent;
|
|
1000
|
+
}
|
|
1001
|
+
matchNode.endLine = tagStartLine + sliceLines;
|
|
1002
|
+
matchNode.endOffset = closeBracket + 1;
|
|
1003
|
+
currentParent = matchNode.parent || root;
|
|
1004
|
+
} else {
|
|
1005
|
+
issues.push({
|
|
1006
|
+
line: tagStartLine,
|
|
1007
|
+
type: "error",
|
|
1008
|
+
message: `Unexpected closing tag </${closeTag}> with no matching opening tag`,
|
|
1009
|
+
rule: "stray-closing-tag"
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
} else {
|
|
1014
|
+
issues.push({ line: tagStartLine, type: "error", message: `Malformed closing tag: ${tagSlice}`, rule: "syntax" });
|
|
1015
|
+
}
|
|
1016
|
+
currentLine += sliceLines;
|
|
1017
|
+
pos = closeBracket + 1;
|
|
1018
|
+
continue;
|
|
1019
|
+
}
|
|
1020
|
+
let inner = tagSlice.slice(1, -1).trim();
|
|
1021
|
+
let selfClosing = false;
|
|
1022
|
+
if (inner.endsWith("/")) {
|
|
1023
|
+
selfClosing = true;
|
|
1024
|
+
inner = inner.slice(0, -1).trim();
|
|
1025
|
+
}
|
|
1026
|
+
const spaceIdx = inner.search(/\s/);
|
|
1027
|
+
const rawTagName = spaceIdx === -1 ? inner : inner.slice(0, spaceIdx);
|
|
1028
|
+
const attrStr = spaceIdx === -1 ? "" : inner.slice(spaceIdx + 1);
|
|
1029
|
+
if (/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(rawTagName)) {
|
|
1030
|
+
const tagName = rawTagName.toLowerCase();
|
|
1031
|
+
const isVoid = HTML_VOID_TAGS.has(tagName) || selfClosing;
|
|
1032
|
+
if (!tagCounts[tagName]) tagCounts[tagName] = { open: 0, close: 0, diff: 0 };
|
|
1033
|
+
tagCounts[tagName].open++;
|
|
1034
|
+
if (isVoid) {
|
|
1035
|
+
tagCounts[tagName].close++;
|
|
1036
|
+
}
|
|
1037
|
+
const attributes = {};
|
|
1038
|
+
const attrRegex = /([a-zA-Z0-9_:-]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+)))?/g;
|
|
1039
|
+
let attrMatch;
|
|
1040
|
+
while ((attrMatch = attrRegex.exec(attrStr)) !== null) {
|
|
1041
|
+
const attrName = attrMatch[1].toLowerCase();
|
|
1042
|
+
const attrVal = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
|
|
1043
|
+
attributes[attrName] = attrVal;
|
|
1044
|
+
if (attrName === "id" && attrVal) {
|
|
1045
|
+
const prevLine = seenIds.get(attrVal);
|
|
1046
|
+
if (prevLine !== void 0) {
|
|
1047
|
+
issues.push({
|
|
1048
|
+
line: tagStartLine,
|
|
1049
|
+
type: "error",
|
|
1050
|
+
message: `Duplicate ID '#${attrVal}' previously defined on line ${prevLine}`,
|
|
1051
|
+
rule: "duplicate-id"
|
|
1052
|
+
});
|
|
1053
|
+
} else {
|
|
1054
|
+
seenIds.set(attrVal, tagStartLine);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
const newNode = {
|
|
1059
|
+
tag: tagName,
|
|
1060
|
+
attributes,
|
|
1061
|
+
children: [],
|
|
1062
|
+
parent: currentParent,
|
|
1063
|
+
text: "",
|
|
1064
|
+
rawHtml: tagSlice,
|
|
1065
|
+
startOffset: pos,
|
|
1066
|
+
endOffset: closeBracket + 1,
|
|
1067
|
+
line: tagStartLine,
|
|
1068
|
+
endLine: tagStartLine + sliceLines,
|
|
1069
|
+
isVoid
|
|
1070
|
+
};
|
|
1071
|
+
currentParent.children.push(newNode);
|
|
1072
|
+
if (!isVoid) {
|
|
1073
|
+
currentParent = newNode;
|
|
1074
|
+
}
|
|
1075
|
+
currentLine += sliceLines;
|
|
1076
|
+
pos = closeBracket + 1;
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1079
|
+
issues.push({
|
|
1080
|
+
line: tagStartLine,
|
|
1081
|
+
type: "warning",
|
|
1082
|
+
message: "Unescaped '<' character in text: consider '<'",
|
|
1083
|
+
rule: "unescaped-angle-bracket"
|
|
1084
|
+
});
|
|
1085
|
+
if (currentParent) {
|
|
1086
|
+
currentParent.text += "<";
|
|
1087
|
+
}
|
|
1088
|
+
pos++;
|
|
1089
|
+
continue;
|
|
1090
|
+
}
|
|
1091
|
+
const nextBracket = html.indexOf("<", pos);
|
|
1092
|
+
const textChunkEnd = nextBracket !== -1 ? nextBracket : len;
|
|
1093
|
+
const textChunk = html.slice(pos, textChunkEnd);
|
|
1094
|
+
if (textChunk) {
|
|
1095
|
+
if (currentParent) {
|
|
1096
|
+
currentParent.text += textChunk;
|
|
1097
|
+
}
|
|
1098
|
+
currentLine += (textChunk.match(/\n/g) || []).length;
|
|
1099
|
+
}
|
|
1100
|
+
pos = textChunkEnd;
|
|
1101
|
+
}
|
|
1102
|
+
let dangling = currentParent;
|
|
1103
|
+
while (dangling && dangling.tag !== "#root") {
|
|
1104
|
+
if (!HTML_VOID_TAGS.has(dangling.tag.toLowerCase())) {
|
|
1105
|
+
issues.push({
|
|
1106
|
+
line: dangling.line,
|
|
1107
|
+
type: "error",
|
|
1108
|
+
message: `Unclosed tag <${dangling.tag}> at end of document`,
|
|
1109
|
+
rule: "unclosed-tag"
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
dangling.endOffset = len;
|
|
1113
|
+
dangling = dangling.parent;
|
|
1114
|
+
}
|
|
1115
|
+
for (const tag of Object.keys(tagCounts)) {
|
|
1116
|
+
const entry = tagCounts[tag];
|
|
1117
|
+
entry.diff = entry.open - entry.close;
|
|
1118
|
+
}
|
|
1119
|
+
root.endLine = currentLine;
|
|
1120
|
+
return { root, issues, tagCounts };
|
|
1121
|
+
}
|
|
1122
|
+
function lintHtml(htmlText) {
|
|
1123
|
+
const { issues, tagCounts } = parseHtml(htmlText);
|
|
1124
|
+
const errors = issues.filter((i) => i.type === "error");
|
|
1125
|
+
const warnings = issues.filter((i) => i.type === "warning");
|
|
1126
|
+
return {
|
|
1127
|
+
valid: errors.length === 0,
|
|
1128
|
+
errors,
|
|
1129
|
+
warnings,
|
|
1130
|
+
tagCounts
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
function outlineHtml(htmlText) {
|
|
1134
|
+
const { root } = parseHtml(htmlText);
|
|
1135
|
+
let title = null;
|
|
1136
|
+
let doctype = null;
|
|
1137
|
+
const docMatch = /<!doctype\s+(\S[^>]*)>/i.exec(htmlText);
|
|
1138
|
+
if (docMatch) doctype = docMatch[1].trim();
|
|
1139
|
+
let totalElements = 0;
|
|
1140
|
+
const uniqueTags = /* @__PURE__ */ new Set();
|
|
1141
|
+
let maxDepth = 0;
|
|
1142
|
+
const headings = [];
|
|
1143
|
+
const landmarks = [];
|
|
1144
|
+
const tables = [];
|
|
1145
|
+
const forms = [];
|
|
1146
|
+
let scripts = 0;
|
|
1147
|
+
let styles = 0;
|
|
1148
|
+
const landmarkTags = /* @__PURE__ */ new Set(["header", "nav", "main", "article", "section", "footer", "aside"]);
|
|
1149
|
+
function walk(node, depth) {
|
|
1150
|
+
if (node.tag !== "#root") {
|
|
1151
|
+
totalElements++;
|
|
1152
|
+
uniqueTags.add(node.tag);
|
|
1153
|
+
if (depth > maxDepth) maxDepth = depth;
|
|
1154
|
+
const tag = node.tag.toLowerCase();
|
|
1155
|
+
if (tag === "title" && !title) {
|
|
1156
|
+
title = node.text.trim();
|
|
1157
|
+
} else if (/^h[1-6]$/.test(tag)) {
|
|
1158
|
+
const level = parseInt(tag[1], 10);
|
|
1159
|
+
headings.push({ level, text: node.text.replace(/\s+/g, " ").trim().slice(0, 80), line: node.line });
|
|
1160
|
+
} else if (landmarkTags.has(tag)) {
|
|
1161
|
+
landmarks.push({
|
|
1162
|
+
tag,
|
|
1163
|
+
id: node.attributes["id"],
|
|
1164
|
+
class: node.attributes["class"],
|
|
1165
|
+
line: node.line
|
|
1166
|
+
});
|
|
1167
|
+
} else if (tag === "table") {
|
|
1168
|
+
const rows = node.children.flatMap((c) => c.tag === "tbody" || c.tag === "thead" ? c.children : [c]).filter((c) => c.tag === "tr").length;
|
|
1169
|
+
tables.push({ id: node.attributes["id"], class: node.attributes["class"], rows, line: node.line });
|
|
1170
|
+
} else if (tag === "form") {
|
|
1171
|
+
forms.push({ id: node.attributes["id"], action: node.attributes["action"], method: node.attributes["method"], line: node.line });
|
|
1172
|
+
} else if (tag === "script") {
|
|
1173
|
+
scripts++;
|
|
1174
|
+
} else if (tag === "style") {
|
|
1175
|
+
styles++;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
for (const child of node.children) {
|
|
1179
|
+
walk(child, depth + 1);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
walk(root, 0);
|
|
1183
|
+
return {
|
|
1184
|
+
title,
|
|
1185
|
+
doctype,
|
|
1186
|
+
totalElements,
|
|
1187
|
+
uniqueTags: Array.from(uniqueTags).sort(),
|
|
1188
|
+
maxDepth,
|
|
1189
|
+
headings,
|
|
1190
|
+
landmarks,
|
|
1191
|
+
tables,
|
|
1192
|
+
forms,
|
|
1193
|
+
scripts,
|
|
1194
|
+
styles
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
function formatHtmlOutline(summary) {
|
|
1198
|
+
const lines = [];
|
|
1199
|
+
lines.push(`HTML Document (${summary.totalElements} elements, ${summary.uniqueTags.length} unique tags, max depth ${summary.maxDepth})`);
|
|
1200
|
+
if (summary.title) lines.push(`Title: "${displaySafeText(summary.title)}"`);
|
|
1201
|
+
if (summary.doctype) lines.push(`DOCTYPE: ${displaySafeText(summary.doctype)}`);
|
|
1202
|
+
lines.push(`Assets: ${summary.scripts} scripts, ${summary.styles} stylesheets`);
|
|
1203
|
+
if (summary.headings.length > 0) {
|
|
1204
|
+
lines.push("", "Headings:");
|
|
1205
|
+
for (const h of summary.headings.slice(0, 30)) {
|
|
1206
|
+
lines.push(` ${" ".repeat(h.level - 1)}[h${h.level}] ${displaySafeText(h.text)} (line ${h.line})`);
|
|
1207
|
+
}
|
|
1208
|
+
if (summary.headings.length > 30) {
|
|
1209
|
+
lines.push(` ... (${summary.headings.length - 30} more headings elided)`);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
if (summary.landmarks.length > 0) {
|
|
1213
|
+
lines.push("", "Landmarks:");
|
|
1214
|
+
for (const l of summary.landmarks.slice(0, 25)) {
|
|
1215
|
+
const idStr = l.id ? `#${displaySafeText(l.id)}` : "";
|
|
1216
|
+
const classStr = l.class ? `.${displaySafeText(l.class.trim().split(/\s+/).join("."))}` : "";
|
|
1217
|
+
lines.push(` <${displaySafeText(l.tag)}${idStr}${classStr}> (line ${l.line})`);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
if (summary.tables.length > 0) {
|
|
1221
|
+
lines.push("", "Tables:");
|
|
1222
|
+
for (const t of summary.tables) {
|
|
1223
|
+
const idStr = t.id ? `#${displaySafeText(t.id)}` : "";
|
|
1224
|
+
lines.push(` <table${idStr}> with ~${t.rows} rows (line ${t.line})`);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
if (summary.forms.length > 0) {
|
|
1228
|
+
lines.push("", "Forms:");
|
|
1229
|
+
for (const f of summary.forms) {
|
|
1230
|
+
const idStr = f.id ? `#${displaySafeText(f.id)}` : "";
|
|
1231
|
+
lines.push(` <form${idStr} method="${displaySafeText(f.method || "GET")}" action="${displaySafeText(f.action || "")}"> (line ${f.line})`);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
return lines.join("\n");
|
|
1235
|
+
}
|
|
1236
|
+
function splitTopLevel(str, delimiter) {
|
|
1237
|
+
const results = [];
|
|
1238
|
+
let start = 0;
|
|
1239
|
+
let inQuote = null;
|
|
1240
|
+
let bracketDepth = 0;
|
|
1241
|
+
for (let i = 0; i < str.length; i++) {
|
|
1242
|
+
const ch = str[i];
|
|
1243
|
+
if (inQuote) {
|
|
1244
|
+
if (ch === inQuote) inQuote = null;
|
|
1245
|
+
} else {
|
|
1246
|
+
if (ch === '"' || ch === "'") {
|
|
1247
|
+
inQuote = ch;
|
|
1248
|
+
} else if (ch === "[") {
|
|
1249
|
+
bracketDepth++;
|
|
1250
|
+
} else if (ch === "]") {
|
|
1251
|
+
if (bracketDepth > 0) bracketDepth--;
|
|
1252
|
+
} else if (bracketDepth === 0 && ch === delimiter) {
|
|
1253
|
+
results.push(str.slice(start, i));
|
|
1254
|
+
start = i + 1;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
results.push(str.slice(start));
|
|
1259
|
+
return results;
|
|
1260
|
+
}
|
|
1261
|
+
function tokenizeSelector(sel) {
|
|
1262
|
+
const tokens = [];
|
|
1263
|
+
let i = 0;
|
|
1264
|
+
const n = sel.length;
|
|
1265
|
+
while (i < n) {
|
|
1266
|
+
while (i < n && /\s/.test(sel[i])) i++;
|
|
1267
|
+
if (i >= n) break;
|
|
1268
|
+
if (sel[i] === ">") {
|
|
1269
|
+
tokens.push(">");
|
|
1270
|
+
i++;
|
|
1271
|
+
continue;
|
|
1272
|
+
}
|
|
1273
|
+
const start = i;
|
|
1274
|
+
let inQuote = null;
|
|
1275
|
+
let bracketDepth = 0;
|
|
1276
|
+
while (i < n) {
|
|
1277
|
+
const ch = sel[i];
|
|
1278
|
+
if (inQuote) {
|
|
1279
|
+
if (ch === inQuote) inQuote = null;
|
|
1280
|
+
} else {
|
|
1281
|
+
if (ch === '"' || ch === "'") {
|
|
1282
|
+
inQuote = ch;
|
|
1283
|
+
} else if (ch === "[") {
|
|
1284
|
+
bracketDepth++;
|
|
1285
|
+
} else if (ch === "]") {
|
|
1286
|
+
if (bracketDepth > 0) bracketDepth--;
|
|
1287
|
+
} else if (bracketDepth === 0) {
|
|
1288
|
+
if (/\s/.test(ch) || ch === ">") {
|
|
1289
|
+
break;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
i++;
|
|
1294
|
+
}
|
|
1295
|
+
if (i > start) {
|
|
1296
|
+
tokens.push(sel.slice(start, i));
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
return tokens;
|
|
1300
|
+
}
|
|
1301
|
+
function parseCompoundSelector(sel) {
|
|
1302
|
+
const result = {
|
|
1303
|
+
ids: [],
|
|
1304
|
+
classes: [],
|
|
1305
|
+
attributes: []
|
|
1306
|
+
};
|
|
1307
|
+
let i = 0;
|
|
1308
|
+
const n = sel.length;
|
|
1309
|
+
if (sel[0] !== "#" && sel[0] !== "." && sel[0] !== "[") {
|
|
1310
|
+
const tagMatch = /^([a-zA-Z*][a-zA-Z0-9_-]*)/.exec(sel);
|
|
1311
|
+
if (tagMatch) {
|
|
1312
|
+
result.tag = tagMatch[1];
|
|
1313
|
+
i = tagMatch[0].length;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
while (i < n) {
|
|
1317
|
+
const ch = sel[i];
|
|
1318
|
+
if (ch === "#") {
|
|
1319
|
+
i++;
|
|
1320
|
+
const idMatch = /^([a-zA-Z0-9_-]+)/.exec(sel.slice(i));
|
|
1321
|
+
if (idMatch) {
|
|
1322
|
+
result.ids.push(idMatch[1]);
|
|
1323
|
+
i += idMatch[0].length;
|
|
1324
|
+
}
|
|
1325
|
+
} else if (ch === ".") {
|
|
1326
|
+
i++;
|
|
1327
|
+
const classMatch = /^([a-zA-Z0-9_-]+)/.exec(sel.slice(i));
|
|
1328
|
+
if (classMatch) {
|
|
1329
|
+
result.classes.push(classMatch[1]);
|
|
1330
|
+
i += classMatch[0].length;
|
|
1331
|
+
}
|
|
1332
|
+
} else if (ch === "[") {
|
|
1333
|
+
let endBracket = -1;
|
|
1334
|
+
let inQuote = null;
|
|
1335
|
+
for (let j = i + 1; j < n; j++) {
|
|
1336
|
+
const c = sel[j];
|
|
1337
|
+
if (inQuote) {
|
|
1338
|
+
if (c === inQuote) inQuote = null;
|
|
1339
|
+
} else {
|
|
1340
|
+
if (c === '"' || c === "'") inQuote = c;
|
|
1341
|
+
else if (c === "]") {
|
|
1342
|
+
endBracket = j;
|
|
1343
|
+
break;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
if (endBracket === -1) {
|
|
1348
|
+
break;
|
|
1349
|
+
}
|
|
1350
|
+
const inner = sel.slice(i + 1, endBracket).trim();
|
|
1351
|
+
i = endBracket + 1;
|
|
1352
|
+
const attrMatch = /^([a-zA-Z0-9_:-]+)(?:\s*([*^$!~]?=)\s*(?:"([^"]*)"|'([^']*)'|([^\s"'\]]+)))?$/.exec(inner);
|
|
1353
|
+
if (attrMatch) {
|
|
1354
|
+
const attrName = attrMatch[1].toLowerCase();
|
|
1355
|
+
const op = attrMatch[2];
|
|
1356
|
+
const val = attrMatch[3] ?? attrMatch[4] ?? attrMatch[5];
|
|
1357
|
+
result.attributes.push({ name: attrName, op, val });
|
|
1358
|
+
}
|
|
1359
|
+
} else {
|
|
1360
|
+
i++;
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
return result;
|
|
1364
|
+
}
|
|
1365
|
+
function matchesCompoundSelector(node, sel) {
|
|
1366
|
+
if (!sel || node.tag === "#root") return false;
|
|
1367
|
+
if (sel === "*") return true;
|
|
1368
|
+
const parsed = parseCompoundSelector(sel);
|
|
1369
|
+
if (parsed.tag && parsed.tag !== "*") {
|
|
1370
|
+
if (node.tag.toLowerCase() !== parsed.tag.toLowerCase()) return false;
|
|
1371
|
+
}
|
|
1372
|
+
for (const id of parsed.ids) {
|
|
1373
|
+
if (node.attributes["id"] !== id) return false;
|
|
1374
|
+
}
|
|
1375
|
+
if (parsed.classes.length > 0) {
|
|
1376
|
+
const nodeClasses = (node.attributes["class"] || "").split(/\s+/).filter(Boolean);
|
|
1377
|
+
for (const c of parsed.classes) {
|
|
1378
|
+
if (!nodeClasses.includes(c)) return false;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
for (const attr of parsed.attributes) {
|
|
1382
|
+
const hasAttr = Object.prototype.hasOwnProperty.call(node.attributes, attr.name);
|
|
1383
|
+
if (!hasAttr) {
|
|
1384
|
+
if (attr.op === "!=") continue;
|
|
1385
|
+
return false;
|
|
1386
|
+
}
|
|
1387
|
+
if (!attr.op) continue;
|
|
1388
|
+
const actual = node.attributes[attr.name] || "";
|
|
1389
|
+
const val = attr.val ?? "";
|
|
1390
|
+
if (attr.op === "=") {
|
|
1391
|
+
if (actual !== val) return false;
|
|
1392
|
+
} else if (attr.op === "^=") {
|
|
1393
|
+
if (!actual.startsWith(val)) return false;
|
|
1394
|
+
} else if (attr.op === "$=") {
|
|
1395
|
+
if (!actual.endsWith(val)) return false;
|
|
1396
|
+
} else if (attr.op === "*=") {
|
|
1397
|
+
if (!actual.includes(val)) return false;
|
|
1398
|
+
} else if (attr.op === "~=") {
|
|
1399
|
+
if (!actual.split(/\s+/).includes(val)) return false;
|
|
1400
|
+
} else if (attr.op === "!=") {
|
|
1401
|
+
if (actual === val) return false;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
return true;
|
|
1405
|
+
}
|
|
1406
|
+
function queryHtml(htmlText, selectorStr) {
|
|
1407
|
+
const { root } = parseHtml(htmlText);
|
|
1408
|
+
let selector = selectorStr.trim();
|
|
1409
|
+
let targetAttr;
|
|
1410
|
+
const attrAtMatch = /@([a-zA-Z0-9_:-]+)$/.exec(selector);
|
|
1411
|
+
if (attrAtMatch) {
|
|
1412
|
+
targetAttr = attrAtMatch[1].toLowerCase();
|
|
1413
|
+
selector = selector.slice(0, selector.length - attrAtMatch[0].length).trim();
|
|
1414
|
+
if (!selector) selector = "*";
|
|
1415
|
+
}
|
|
1416
|
+
const rawSubSelectors = splitTopLevel(selector, ",").map((s) => s.trim()).filter(Boolean);
|
|
1417
|
+
const matchedSet = /* @__PURE__ */ new Set();
|
|
1418
|
+
for (const subSel of rawSubSelectors) {
|
|
1419
|
+
let collectAll2 = function(node) {
|
|
1420
|
+
if (node.tag !== "#root") currentCandidates.push(node);
|
|
1421
|
+
for (const c of node.children) collectAll2(c);
|
|
1422
|
+
};
|
|
1423
|
+
var collectAll = collectAll2;
|
|
1424
|
+
const tokens = tokenizeSelector(subSel);
|
|
1425
|
+
let currentCandidates = [];
|
|
1426
|
+
collectAll2(root);
|
|
1427
|
+
let i = 0;
|
|
1428
|
+
while (i < tokens.length) {
|
|
1429
|
+
const token = tokens[i];
|
|
1430
|
+
if (token === ">") {
|
|
1431
|
+
const nextTarget = tokens[i + 1];
|
|
1432
|
+
if (!nextTarget) break;
|
|
1433
|
+
const nextCandidates = [];
|
|
1434
|
+
for (const parent of currentCandidates) {
|
|
1435
|
+
for (const child of parent.children) {
|
|
1436
|
+
if (nextTarget === "*" || matchesCompoundSelector(child, nextTarget)) {
|
|
1437
|
+
nextCandidates.push(child);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
currentCandidates = nextCandidates;
|
|
1442
|
+
i += 2;
|
|
1443
|
+
} else {
|
|
1444
|
+
if (i === 0) {
|
|
1445
|
+
currentCandidates = currentCandidates.filter((node) => token === "*" || matchesCompoundSelector(node, token));
|
|
1446
|
+
} else {
|
|
1447
|
+
const nextSet = /* @__PURE__ */ new Set();
|
|
1448
|
+
for (const ancestor of currentCandidates) {
|
|
1449
|
+
let findDescendants2 = function(node) {
|
|
1450
|
+
for (const child of node.children) {
|
|
1451
|
+
if (token === "*" || matchesCompoundSelector(child, token)) {
|
|
1452
|
+
nextSet.add(child);
|
|
1453
|
+
}
|
|
1454
|
+
findDescendants2(child);
|
|
1455
|
+
}
|
|
1456
|
+
};
|
|
1457
|
+
var findDescendants = findDescendants2;
|
|
1458
|
+
findDescendants2(ancestor);
|
|
1459
|
+
}
|
|
1460
|
+
currentCandidates = Array.from(nextSet);
|
|
1461
|
+
}
|
|
1462
|
+
i++;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
for (const match of currentCandidates) {
|
|
1466
|
+
matchedSet.add(match);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
const elements = Array.from(matchedSet);
|
|
1470
|
+
if (targetAttr !== void 0) {
|
|
1471
|
+
const attributeValues = [];
|
|
1472
|
+
for (const el of elements) {
|
|
1473
|
+
if (Object.prototype.hasOwnProperty.call(el.attributes, targetAttr)) {
|
|
1474
|
+
attributeValues.push(el.attributes[targetAttr]);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
return { elements, attributeValues, fanned: attributeValues.length > 1, sourceHtml: htmlText };
|
|
1478
|
+
}
|
|
1479
|
+
return { elements, fanned: elements.length > 1, sourceHtml: htmlText };
|
|
1480
|
+
}
|
|
1481
|
+
function extractNodeText(node, sourceHtml) {
|
|
1482
|
+
if (RAW_TEXT_TAGS.has(node.tag.toLowerCase())) return "";
|
|
1483
|
+
if (sourceHtml && node.startOffset !== void 0 && node.endOffset !== void 0) {
|
|
1484
|
+
const raw = sourceHtml.slice(node.startOffset, node.endOffset);
|
|
1485
|
+
const clean = raw.replace(/<!--[\s\S]*?-->/g, "").replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<style[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/ /g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'");
|
|
1486
|
+
return clean.replace(/\s+/g, " ").trim();
|
|
1487
|
+
}
|
|
1488
|
+
const parts = [];
|
|
1489
|
+
if (node.text.trim()) parts.push(node.text.trim());
|
|
1490
|
+
for (const child of node.children) {
|
|
1491
|
+
const t = extractNodeText(child);
|
|
1492
|
+
if (t) parts.push(t);
|
|
1493
|
+
}
|
|
1494
|
+
return parts.join(" ");
|
|
1495
|
+
}
|
|
1496
|
+
function serializeHtmlNode(node, indent = 0, sourceHtml) {
|
|
1497
|
+
if (node.tag === "#root") {
|
|
1498
|
+
return node.children.map((c) => serializeHtmlNode(c, indent, sourceHtml)).join("\n");
|
|
1499
|
+
}
|
|
1500
|
+
if (sourceHtml && node.startOffset !== void 0 && node.endOffset !== void 0) {
|
|
1501
|
+
return sourceHtml.slice(node.startOffset, node.endOffset);
|
|
1502
|
+
}
|
|
1503
|
+
const pad = " ".repeat(indent);
|
|
1504
|
+
const attrs = Object.entries(node.attributes).map(([k, v]) => v !== "" ? `${k}="${v.replace(/"/g, """)}"` : k).join(" ");
|
|
1505
|
+
const attrStr = attrs ? ` ${attrs}` : "";
|
|
1506
|
+
if (node.isVoid) {
|
|
1507
|
+
return `${pad}<${node.tag}${attrStr}>`;
|
|
1508
|
+
}
|
|
1509
|
+
if (node.children.length === 0) {
|
|
1510
|
+
const textTrimmed = node.text.trim();
|
|
1511
|
+
if (!textTrimmed) {
|
|
1512
|
+
return `${pad}<${node.tag}${attrStr}></${node.tag}>`;
|
|
1513
|
+
}
|
|
1514
|
+
if (!textTrimmed.includes("\n") && textTrimmed.length < 80) {
|
|
1515
|
+
return `${pad}<${node.tag}${attrStr}>${textTrimmed}</${node.tag}>`;
|
|
1516
|
+
}
|
|
1517
|
+
return `${pad}<${node.tag}${attrStr}>
|
|
1518
|
+
${pad} ${textTrimmed}
|
|
1519
|
+
${pad}</${node.tag}>`;
|
|
1520
|
+
}
|
|
1521
|
+
const inner = node.children.map((c) => serializeHtmlNode(c, indent + 1, sourceHtml)).join("\n");
|
|
1522
|
+
return `${pad}<${node.tag}${attrStr}>
|
|
1523
|
+
${inner}
|
|
1524
|
+
${pad}</${node.tag}>`;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1140
1527
|
// node_modules/js-yaml/dist/js-yaml.mjs
|
|
1141
1528
|
init_define_import_meta_env();
|
|
1142
1529
|
var NOT_RESOLVED = /* @__PURE__ */ Symbol("NOT_RESOLVED");
|
|
@@ -3712,17 +4099,17 @@ function findOperation(operations, key) {
|
|
|
3712
4099
|
return operations.find((op) => op.method === method && op.path === opPath);
|
|
3713
4100
|
}
|
|
3714
4101
|
function operationLabel(op) {
|
|
3715
|
-
return op.operationId !== void 0 ? `${op.operationId} (${op.method} ${op.path})` : `${op.method} ${op.path}`;
|
|
4102
|
+
return op.operationId !== void 0 ? `${displaySafeText(op.operationId)} (${displaySafeText(op.method)} ${displaySafeText(op.path)})` : `${displaySafeText(op.method)} ${displaySafeText(op.path)}`;
|
|
3716
4103
|
}
|
|
3717
4104
|
function indentedJson(value, indent) {
|
|
3718
4105
|
return JSON.stringify(value, null, 2).split("\n").map((line) => indent + line).join("\n");
|
|
3719
4106
|
}
|
|
3720
4107
|
function formatOperationDetail(op) {
|
|
3721
|
-
const lines = [`${op.method} ${op.path}`];
|
|
3722
|
-
if (op.operationId !== void 0) lines.push(`operationId: ${op.operationId}`);
|
|
3723
|
-
if (op.summary !== void 0) lines.push(`summary: ${op.summary}`);
|
|
3724
|
-
if (op.description !== void 0) lines.push(`description: ${op.description}`);
|
|
3725
|
-
if (op.tags !== void 0 && op.tags.length > 0) lines.push(`tags: ${op.tags.join(", ")}`);
|
|
4108
|
+
const lines = [`${displaySafeText(op.method)} ${displaySafeText(op.path)}`];
|
|
4109
|
+
if (op.operationId !== void 0) lines.push(`operationId: ${displaySafeText(op.operationId)}`);
|
|
4110
|
+
if (op.summary !== void 0) lines.push(`summary: ${displaySafeText(op.summary)}`);
|
|
4111
|
+
if (op.description !== void 0) lines.push(`description: ${displaySafeText(op.description)}`);
|
|
4112
|
+
if (op.tags !== void 0 && op.tags.length > 0) lines.push(`tags: ${op.tags.map(displaySafeText).join(", ")}`);
|
|
3726
4113
|
if (op.parameters.length > 0) {
|
|
3727
4114
|
lines.push("", "parameters:");
|
|
3728
4115
|
for (const paramRaw of op.parameters) {
|
|
@@ -3732,7 +4119,7 @@ function formatOperationDetail(op) {
|
|
|
3732
4119
|
const location = typeof param["in"] === "string" ? param["in"] : "?";
|
|
3733
4120
|
const required = param["required"] === true ? " required" : "";
|
|
3734
4121
|
const description = typeof param["description"] === "string" ? ` - ${param["description"]}` : "";
|
|
3735
|
-
lines.push(` ${name} (${location})${required}${description}`);
|
|
4122
|
+
lines.push(` ${displaySafeText(name)} (${displaySafeText(location)})${required}${displaySafeText(description)}`);
|
|
3736
4123
|
if (param["schema"] !== void 0) lines.push(indentedJson(param["schema"], " "));
|
|
3737
4124
|
}
|
|
3738
4125
|
}
|
|
@@ -4001,10 +4388,10 @@ function isSqliteFile(filePath) {
|
|
|
4001
4388
|
}
|
|
4002
4389
|
function openReadonlySqlite(filePath) {
|
|
4003
4390
|
if (!fs.existsSync(filePath)) {
|
|
4004
|
-
throw new Error(`file not found: ${filePath}`);
|
|
4391
|
+
throw new Error(`file not found: ${displaySafeText(filePath)}`);
|
|
4005
4392
|
}
|
|
4006
4393
|
if (!isSqliteFile(filePath)) {
|
|
4007
|
-
throw new Error(`not a valid SQLite database (bad file header): ${filePath}`);
|
|
4394
|
+
throw new Error(`not a valid SQLite database (bad file header): ${displaySafeText(filePath)}`);
|
|
4008
4395
|
}
|
|
4009
4396
|
try {
|
|
4010
4397
|
return new Database(filePath, { readonly: true, fileMustExist: true });
|
|
@@ -4057,12 +4444,12 @@ function formatSqliteSchema(result) {
|
|
|
4057
4444
|
const lines = [`${t.name} (${t.kind}${t.rowCount !== null ? `, ${t.rowCount} row${t.rowCount === 1 ? "" : "s"}` : ""})`];
|
|
4058
4445
|
for (const c of t.columns) {
|
|
4059
4446
|
const flags = [c.primaryKey ? "PK" : null, c.notNull ? "NOT NULL" : null, c.defaultValue !== null ? `DEFAULT ${c.defaultValue}` : null].filter((f) => f !== null).join(" ");
|
|
4060
|
-
lines.push(` ${c.name} ${c.type || "(untyped)"}${flags ? ` ${flags}` : ""}`);
|
|
4447
|
+
lines.push(` ${displaySafeText(c.name)} ${displaySafeText(c.type || "(untyped)")}${flags ? ` ${flags}` : ""}`);
|
|
4061
4448
|
}
|
|
4062
4449
|
if (t.indexes.length > 0) {
|
|
4063
4450
|
lines.push(" indexes:");
|
|
4064
4451
|
for (const idx of t.indexes) {
|
|
4065
|
-
lines.push(` ${idx.name}${idx.unique ? " (unique)" : ""}: ${idx.columns.join(", ")}`);
|
|
4452
|
+
lines.push(` ${displaySafeText(idx.name)}${idx.unique ? " (unique)" : ""}: ${displaySafeText(idx.columns.join(", "))}`);
|
|
4066
4453
|
}
|
|
4067
4454
|
}
|
|
4068
4455
|
if (t.foreignKeys.length > 0) {
|
|
@@ -4514,7 +4901,7 @@ function formatRanges(ranges) {
|
|
|
4514
4901
|
return ranges.map((r) => r.start === r.end ? String(r.start) : `${r.start}-${r.end}`).join(", ");
|
|
4515
4902
|
}
|
|
4516
4903
|
function formatFileGaps(f) {
|
|
4517
|
-
const lines = [f.filePath];
|
|
4904
|
+
const lines = [displaySafeText(f.filePath)];
|
|
4518
4905
|
lines.push(` lines: ${f.linesHit}/${f.linesTotal} functions: ${f.functionsHit}/${f.functionsTotal} branches: ${f.branchesHit}/${f.branchesTotal}`);
|
|
4519
4906
|
if (f.summaryOnly) {
|
|
4520
4907
|
lines.push(" (summary-only report -- no per-line/function/branch detail available)");
|
|
@@ -4525,7 +4912,7 @@ function formatFileGaps(f) {
|
|
|
4525
4912
|
}
|
|
4526
4913
|
if (f.uncoveredFunctions.length > 0) {
|
|
4527
4914
|
lines.push(" uncovered functions:");
|
|
4528
|
-
for (const fn of f.uncoveredFunctions) lines.push(` ${fn.name} (line ${fn.line})`);
|
|
4915
|
+
for (const fn of f.uncoveredFunctions) lines.push(` ${displaySafeText(fn.name)} (line ${fn.line})`);
|
|
4529
4916
|
}
|
|
4530
4917
|
if (f.uncoveredBranches.length > 0) {
|
|
4531
4918
|
const branchLines = [...new Set(f.uncoveredBranches.map((br) => br.line))].sort((a, b) => a - b);
|
|
@@ -4653,25 +5040,25 @@ function indentBlock(content) {
|
|
|
4653
5040
|
function formatSingleFileConflicts(result) {
|
|
4654
5041
|
const lines = [];
|
|
4655
5042
|
if (result.regions.length > 0) {
|
|
4656
|
-
lines.push(`${result.filePath} -- ${result.regions.length} conflict${result.regions.length === 1 ? "" : "s"}`);
|
|
5043
|
+
lines.push(`${displaySafeText(result.filePath)} -- ${result.regions.length} conflict${result.regions.length === 1 ? "" : "s"}`);
|
|
4657
5044
|
for (const r of result.regions) {
|
|
4658
5045
|
lines.push(` lines ${r.lineStart}-${r.lineEnd}`);
|
|
4659
|
-
lines.push(` <<<<<<< ${r.ours.label || "(ours)"}`);
|
|
5046
|
+
lines.push(` <<<<<<< ${displaySafeText(r.ours.label || "(ours)")}`);
|
|
4660
5047
|
lines.push(indentBlock(r.ours.content));
|
|
4661
5048
|
if (r.base !== null) {
|
|
4662
|
-
lines.push(` ||||||| ${r.base.label || "(base)"}`);
|
|
5049
|
+
lines.push(` ||||||| ${displaySafeText(r.base.label || "(base)")}`);
|
|
4663
5050
|
lines.push(indentBlock(r.base.content));
|
|
4664
5051
|
}
|
|
4665
5052
|
lines.push(" =======");
|
|
4666
5053
|
lines.push(indentBlock(r.theirs.content));
|
|
4667
|
-
lines.push(` >>>>>>> ${r.theirs.label || "(theirs)"}`);
|
|
5054
|
+
lines.push(` >>>>>>> ${displaySafeText(r.theirs.label || "(theirs)")}`);
|
|
4668
5055
|
}
|
|
4669
5056
|
} else {
|
|
4670
|
-
lines.push(`${result.filePath} -- no conflicts`);
|
|
5057
|
+
lines.push(`${displaySafeText(result.filePath)} -- no conflicts`);
|
|
4671
5058
|
}
|
|
4672
5059
|
if (result.warnings.length > 0) {
|
|
4673
5060
|
lines.push(" warnings:");
|
|
4674
|
-
for (const w of result.warnings) lines.push(` line ${w.line}: ${w.message}`);
|
|
5061
|
+
for (const w of result.warnings) lines.push(` line ${w.line}: ${displaySafeText(w.message)}`);
|
|
4675
5062
|
}
|
|
4676
5063
|
return lines.join("\n");
|
|
4677
5064
|
}
|
|
@@ -4683,17 +5070,17 @@ function formatConflicts(results) {
|
|
|
4683
5070
|
function formatSingleFileSummary(summary) {
|
|
4684
5071
|
const lines = [];
|
|
4685
5072
|
if (summary.conflictCount > 0) {
|
|
4686
|
-
lines.push(`${summary.filePath} -- ${summary.conflictCount} conflict${summary.conflictCount === 1 ? "" : "s"}`);
|
|
5073
|
+
lines.push(`${displaySafeText(summary.filePath)} -- ${summary.conflictCount} conflict${summary.conflictCount === 1 ? "" : "s"}`);
|
|
4687
5074
|
for (const r of summary.regions) {
|
|
4688
|
-
const baseText = r.baseLabel !== null ? ` base=${r.baseLabel || "(unlabeled)"}` : "";
|
|
4689
|
-
lines.push(` lines ${r.lineStart}-${r.lineEnd} ours=${r.oursLabel || "(unlabeled)"}${baseText} theirs=${r.theirsLabel || "(unlabeled)"}`);
|
|
5075
|
+
const baseText = r.baseLabel !== null ? ` base=${displaySafeText(r.baseLabel || "(unlabeled)")}` : "";
|
|
5076
|
+
lines.push(` lines ${r.lineStart}-${r.lineEnd} ours=${displaySafeText(r.oursLabel || "(unlabeled)")}${baseText} theirs=${displaySafeText(r.theirsLabel || "(unlabeled)")}`);
|
|
4690
5077
|
}
|
|
4691
5078
|
} else {
|
|
4692
|
-
lines.push(`${summary.filePath} -- no conflicts`);
|
|
5079
|
+
lines.push(`${displaySafeText(summary.filePath)} -- no conflicts`);
|
|
4693
5080
|
}
|
|
4694
5081
|
if (summary.warnings.length > 0) {
|
|
4695
5082
|
lines.push(" warnings:");
|
|
4696
|
-
for (const w of summary.warnings) lines.push(` line ${w.line}: ${w.message}`);
|
|
5083
|
+
for (const w of summary.warnings) lines.push(` line ${w.line}: ${displaySafeText(w.message)}`);
|
|
4697
5084
|
}
|
|
4698
5085
|
return lines.join("\n");
|
|
4699
5086
|
}
|
|
@@ -4765,36 +5152,12 @@ function resolveBrowserExecutablePath(explicit) {
|
|
|
4765
5152
|
}
|
|
4766
5153
|
return null;
|
|
4767
5154
|
}
|
|
4768
|
-
function isBlockedIpv4Octets(a, b) {
|
|
4769
|
-
if (a === 127) return true;
|
|
4770
|
-
if (a === 169 && b === 254) return true;
|
|
4771
|
-
if (a === 10) return true;
|
|
4772
|
-
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
4773
|
-
if (a === 192 && b === 168) return true;
|
|
4774
|
-
if (a === 0) return true;
|
|
4775
|
-
return false;
|
|
4776
|
-
}
|
|
4777
|
-
function isBlockedIpv6(groups) {
|
|
4778
|
-
if (groups.every((g) => g === 0)) return true;
|
|
4779
|
-
if (groups.slice(0, 7).every((g) => g === 0) && groups[7] === 1) return true;
|
|
4780
|
-
if (groups.slice(0, 5).every((g) => g === 0) && (groups[5] === 65535 || groups[5] === 0)) {
|
|
4781
|
-
const embedded = groups[6];
|
|
4782
|
-
return isBlockedIpv4Octets(embedded >> 8, embedded & 255);
|
|
4783
|
-
}
|
|
4784
|
-
if (groups[0] === 100 && groups[1] === 65435 && groups.slice(2, 6).every((g) => g === 0)) {
|
|
4785
|
-
const embedded = groups[6];
|
|
4786
|
-
return isBlockedIpv4Octets(embedded >> 8, embedded & 255);
|
|
4787
|
-
}
|
|
4788
|
-
if ((groups[0] & 65472) === 65152) return true;
|
|
4789
|
-
if ((groups[0] & 65024) === 64512) return true;
|
|
4790
|
-
return false;
|
|
4791
|
-
}
|
|
4792
5155
|
function isBlockedIpAddress(addr) {
|
|
4793
5156
|
const bare = addr.replace(/^\[/, "").replace(/\]$/, "");
|
|
4794
5157
|
const v4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(bare);
|
|
4795
|
-
if (v4) return
|
|
5158
|
+
if (v4) return isPrivateIpv4Octets(Number(v4[1]), Number(v4[2]), Number(v4[3]));
|
|
4796
5159
|
const groups = parseIpv6Groups(bare);
|
|
4797
|
-
return groups !== null &&
|
|
5160
|
+
return groups !== null && isPrivateIpv6Groups(groups);
|
|
4798
5161
|
}
|
|
4799
5162
|
function blockedAddressAmong(addresses) {
|
|
4800
5163
|
return addresses.find((addr) => isBlockedIpAddress(addr)) ?? null;
|
|
@@ -5063,11 +5426,11 @@ function bodyFromSource(entry) {
|
|
|
5063
5426
|
}
|
|
5064
5427
|
}
|
|
5065
5428
|
function symbolNamesInFile(filePath, dbPath = globalDbPath()) {
|
|
5066
|
-
const symbols = querySymbols({ filePath, limit:
|
|
5429
|
+
const symbols = querySymbols({ filePath, limit: -1 }, dbPath);
|
|
5067
5430
|
return [...new Set(symbols.map((s) => s.name))].sort();
|
|
5068
5431
|
}
|
|
5069
5432
|
function computeFileFingerprint(filePath, dbPath = globalDbPath()) {
|
|
5070
|
-
const symbols = querySymbols({ filePath, limit:
|
|
5433
|
+
const symbols = querySymbols({ filePath, limit: -1 }, dbPath);
|
|
5071
5434
|
const manifest = symbols.map((s) => `${s.name}:${s.kind}:${s.lineStart}-${s.lineEnd}`).sort().join("\n");
|
|
5072
5435
|
return fingerprintContent(manifest);
|
|
5073
5436
|
}
|
|
@@ -5291,6 +5654,39 @@ function findIdentifierNearPosition(ts, sourceFile, line0, position, name) {
|
|
|
5291
5654
|
}
|
|
5292
5655
|
|
|
5293
5656
|
// src/read_commands.ts
|
|
5657
|
+
var STATEMENT_ADAPTER_IMPORTS = new Map([
|
|
5658
|
+
[".abap", extractAbap],
|
|
5659
|
+
[".sas", extractSas],
|
|
5660
|
+
[".pli", extractPli],
|
|
5661
|
+
[".pl1", extractPli],
|
|
5662
|
+
[".rpgle", extractRpg],
|
|
5663
|
+
[".sqlrpgle", extractRpg],
|
|
5664
|
+
[".jcl", extractJcl],
|
|
5665
|
+
...[".f", ".for", ".f77", ".f90", ".f95", ".f03", ".f08"].map((e) => [e, extractFortran]),
|
|
5666
|
+
...[".pas", ".dpr", ".dpk", ".lpr"].map((e) => [e, extractPascal]),
|
|
5667
|
+
[".cmake", extractCmake],
|
|
5668
|
+
...[".s", ".asm", ".nasm"].map((e) => [e, extractAsm]),
|
|
5669
|
+
...[".bat", ".cmd"].map((e) => [e, extractBatch]),
|
|
5670
|
+
...[".erl", ".hrl"].map((e) => [e, extractErlang])
|
|
5671
|
+
]);
|
|
5672
|
+
var BRACE_ADAPTER_IMPORTS = new Map([
|
|
5673
|
+
[".mm", extractObjc],
|
|
5674
|
+
[".groovy", extractGroovy],
|
|
5675
|
+
[".gvy", extractGroovy],
|
|
5676
|
+
[".gradle", extractGroovy],
|
|
5677
|
+
[".pm", extractPerl],
|
|
5678
|
+
[".sol", extractSolidity],
|
|
5679
|
+
[".thrift", extractThrift],
|
|
5680
|
+
...[".glsl", ".vert", ".frag", ".comp", ".geom", ".tesc", ".tese", ".hlsl", ".hlsli", ".metal"].map((e) => [e, extractCShader])
|
|
5681
|
+
]);
|
|
5682
|
+
function braceAdapterImportsFor(e, text) {
|
|
5683
|
+
if (e === ".m") return isObjcSource(text) ? extractObjc : isMatlabSource(text) ? extractMatlab : void 0;
|
|
5684
|
+
if (e === ".pp") return isPascalSource(text) ? extractPascal : void 0;
|
|
5685
|
+
if (e === ".h") return isObjcHeader(text) ? extractObjc : void 0;
|
|
5686
|
+
if (e === ".pl") return isPrologSource(text) ? void 0 : extractPerl;
|
|
5687
|
+
if (e === ".t") return isPerlSource(text) ? extractPerl : void 0;
|
|
5688
|
+
return BRACE_ADAPTER_IMPORTS.get(e);
|
|
5689
|
+
}
|
|
5294
5690
|
var DIDYOUMEAN_LIMIT = 5;
|
|
5295
5691
|
var SYMBOL_PREVIEW_LINES = 5;
|
|
5296
5692
|
var AMBIGUOUS_HEADING_LIMIT = 10;
|
|
@@ -5482,6 +5878,24 @@ function healStaleIndex(resolvedPath) {
|
|
|
5482
5878
|
if (err instanceof ConfinementIdentityError) throw err;
|
|
5483
5879
|
}
|
|
5484
5880
|
}
|
|
5881
|
+
var STALE_CHECK_FILE_CAP = 25;
|
|
5882
|
+
function warnIfFilesStale(filePaths) {
|
|
5883
|
+
const checked = /* @__PURE__ */ new Set();
|
|
5884
|
+
let staleCount = 0;
|
|
5885
|
+
for (const raw of filePaths) {
|
|
5886
|
+
if (checked.size >= STALE_CHECK_FILE_CAP) break;
|
|
5887
|
+
if (checked.has(raw)) continue;
|
|
5888
|
+
checked.add(raw);
|
|
5889
|
+
if (staleWarning(raw) === "") continue;
|
|
5890
|
+
staleCount++;
|
|
5891
|
+
healStaleIndex(raw);
|
|
5892
|
+
}
|
|
5893
|
+
if (staleCount > 0) {
|
|
5894
|
+
console.warn(
|
|
5895
|
+
`token-goat: ${countNoun(staleCount, "file")} behind these results changed on disk since the index last saw ${staleCount === 1 ? "it" : "them"} -- a reindex just ran, so a repeat of this command will reflect the current version.`
|
|
5896
|
+
);
|
|
5897
|
+
}
|
|
5898
|
+
}
|
|
5485
5899
|
function emit(text) {
|
|
5486
5900
|
const out = colorStdout() ? text : stripAnsi(text);
|
|
5487
5901
|
process.stdout.write(ensureNewline(out));
|
|
@@ -5499,6 +5913,9 @@ function guardText(text, command) {
|
|
|
5499
5913
|
function fenceGithubText(text) {
|
|
5500
5914
|
return fenceUntrusted(text, UNTRUSTED_GITHUB_TAG);
|
|
5501
5915
|
}
|
|
5916
|
+
function fenceHtmlText(text) {
|
|
5917
|
+
return fenceUntrusted(text, UNTRUSTED_HTML_TAG);
|
|
5918
|
+
}
|
|
5502
5919
|
function fenceGithubFieldIfMatched(text) {
|
|
5503
5920
|
const matches = scanAndRecord(text);
|
|
5504
5921
|
if (matches.length === 0) return text;
|
|
@@ -5642,7 +6059,7 @@ function formatBareNameSpecError(command, name, projectRoot) {
|
|
|
5642
6059
|
if (specs.length === 0) {
|
|
5643
6060
|
return `Invalid spec - expected "file::symbol", got: ${name}`;
|
|
5644
6061
|
}
|
|
5645
|
-
const lines = [`Not a file: '${name}'. Did you mean:`];
|
|
6062
|
+
const lines = [`Not a file: '${displaySafeText(name)}'. Did you mean:`];
|
|
5646
6063
|
for (const spec of specs.slice(0, DIDYOUMEAN_LIMIT)) {
|
|
5647
6064
|
lines.push(` - token-goat ${command} "${spec}"`);
|
|
5648
6065
|
}
|
|
@@ -5676,7 +6093,7 @@ function formatCrossFileLead(command, name, excludeFilePath, projectRoot) {
|
|
|
5676
6093
|
return lines.join("\n");
|
|
5677
6094
|
}
|
|
5678
6095
|
function resolveEnclosingSymbol(filePath, chunkStartLine) {
|
|
5679
|
-
const symbols = querySymbols({ filePath, limit:
|
|
6096
|
+
const symbols = querySymbols({ filePath, limit: -1 }, globalDbPath());
|
|
5680
6097
|
let best = null;
|
|
5681
6098
|
for (const s of symbols) {
|
|
5682
6099
|
if (s.lineStart <= chunkStartLine && chunkStartLine <= s.lineEnd) {
|
|
@@ -5685,7 +6102,7 @@ function resolveEnclosingSymbol(filePath, chunkStartLine) {
|
|
|
5685
6102
|
}
|
|
5686
6103
|
}
|
|
5687
6104
|
}
|
|
5688
|
-
return best === null ? null : { name: best.name, kind: best.kind };
|
|
6105
|
+
return best === null ? null : { name: best.name, kind: best.kind, lineStart: best.lineStart };
|
|
5689
6106
|
}
|
|
5690
6107
|
function trimBlankLines(lines) {
|
|
5691
6108
|
let start = 0;
|
|
@@ -5802,13 +6219,13 @@ function runSymbol(opts) {
|
|
|
5802
6219
|
const label = opts.name ?? opts.grep ?? "*";
|
|
5803
6220
|
const notice = `no non-test matches for '${label}' (${excludeTestsHiddenNote(hiddenByExcludeTests)})`;
|
|
5804
6221
|
if (opts.json === true) {
|
|
5805
|
-
return { text:
|
|
6222
|
+
return { text: displaySafeJson({ items: [], truncated: false, totalCount: 0 }), code: 0 };
|
|
5806
6223
|
}
|
|
5807
6224
|
return { text: `token-goat: ${notice}`, code: 0 };
|
|
5808
6225
|
}
|
|
5809
6226
|
if (matchesGrep !== void 0 && filtered.length === 0 && preFilterCount > 0) {
|
|
5810
6227
|
if (opts.json === true) {
|
|
5811
|
-
const text2 =
|
|
6228
|
+
const text2 = displaySafeJson({ items: [], truncated: false, totalCount: 0 });
|
|
5812
6229
|
return { text: text2, code: 0 };
|
|
5813
6230
|
}
|
|
5814
6231
|
return { text: grepFilteredToEmptyNotice(preFilterCount, opts.grep ?? "", "symbol", "symbols"), code: 0 };
|
|
@@ -5876,7 +6293,7 @@ ${emptyIndexMessage(emptyIndexRoot)}`;
|
|
|
5876
6293
|
...refCounts !== void 0 ? { refCount: refCounts.get(s.name) ?? 0, hasDoc: hasRealDocstring(s.docstring) } : {}
|
|
5877
6294
|
}));
|
|
5878
6295
|
const payload = { items, truncated: truncatedFlag, totalCount: trueTotal };
|
|
5879
|
-
const text2 =
|
|
6296
|
+
const text2 = displaySafeJson(payload);
|
|
5880
6297
|
recordReadStat("symbol_lookup", fullSourceBytes, text2, opts.name ?? opts.file ?? opts.grep);
|
|
5881
6298
|
return { text: text2, code: 0 };
|
|
5882
6299
|
}
|
|
@@ -5990,7 +6407,7 @@ function runLineRange(range, opts) {
|
|
|
5990
6407
|
const clampedEnd = Math.min(end, allLines.length);
|
|
5991
6408
|
const slice = allLines.slice(start - 1, clampedEnd);
|
|
5992
6409
|
if (opts.json === true) {
|
|
5993
|
-
return { text:
|
|
6410
|
+
return { text: displaySafeJson({ file, start, end: clampedEnd, lines: slice }), code: 0 };
|
|
5994
6411
|
}
|
|
5995
6412
|
const tok = Math.ceil(slice.join("\n").length / 4);
|
|
5996
6413
|
return {
|
|
@@ -6022,7 +6439,8 @@ function formatAmbiguity(symbol, file, candidates, explicitRoot, commandName = "
|
|
|
6022
6439
|
const multiFile = new Set(candidates.map((c) => c.filePath)).size > 1;
|
|
6023
6440
|
const displayRoot = getDisplayRoot(explicitRoot);
|
|
6024
6441
|
const lines = [
|
|
6025
|
-
|
|
6442
|
+
// A symbol name and a file name are chosen by the repository, and this sentence is token-goat instructing the reader what to do next, so a name shaped like a marker would read as part of that instruction.
|
|
6443
|
+
`Ambiguous symbol '${displaySafeText(symbol)}' in '${displaySafeText(file)}': ${countNoun(candidates.length, "definition")} match. Retry with one of the qualified commands below to pick one:`
|
|
6026
6444
|
];
|
|
6027
6445
|
const fileSymCache = /* @__PURE__ */ new Map();
|
|
6028
6446
|
const getFileSyms = (filePath) => {
|
|
@@ -6133,7 +6551,16 @@ function resolveSymbolSpec(spec, forceRefresh, projectRoot) {
|
|
|
6133
6551
|
if (cParent.toLowerCase() === symBaseLower) return true;
|
|
6134
6552
|
if (cParent === "" && c.docstring.toLowerCase() === symBaseLower) return true;
|
|
6135
6553
|
return containers.some(
|
|
6136
|
-
(cls) => cls.filePath === c.filePath &&
|
|
6554
|
+
(cls) => cls.filePath === c.filePath && // A container is never its own containment match (mirrors findParentName's `sameSpan`
|
|
6555
|
+
// exclusion above): without this, a same-named non-nesting pair on adjacent spans --
|
|
6556
|
+
// e.g. an HTML `heading` symbol and an unrelated `html_id` symbol that both happen to
|
|
6557
|
+
// be named "Overview" -- lets the OUTER one satisfy containment against ITSELF (its
|
|
6558
|
+
// own span trivially contains itself), so `Overview.Overview` (the exact qualifier
|
|
6559
|
+
// `formatAmbiguity` printed as the retry hint for the html_id candidate, since
|
|
6560
|
+
// findParentName resolved its enclosing heading's name to the same string) kept both
|
|
6561
|
+
// candidates in scope and reported ambiguous again -- a disambiguation hint that could
|
|
6562
|
+
// never resolve the ambiguity it was emitted for.
|
|
6563
|
+
!(cls.lineStart === c.lineStart && cls.lineEnd === c.lineEnd) && c.lineStart >= cls.lineStart && c.lineEnd <= cls.lineEnd
|
|
6137
6564
|
);
|
|
6138
6565
|
});
|
|
6139
6566
|
if (scoped.length > 0) candidates = scoped;
|
|
@@ -6186,13 +6613,17 @@ function runRead(opts) {
|
|
|
6186
6613
|
const closes = rankSimilarNames(scanned, symbol);
|
|
6187
6614
|
if (closes.length > 0) messages.push(didYouMean(closes));
|
|
6188
6615
|
else if (scanned.length > 0) messages.push(`Try: token-goat outline ${file}`);
|
|
6616
|
+
else if (fs4.existsSync(resolved)) {
|
|
6617
|
+
const gap = symbolExtractorGap(file, resolved);
|
|
6618
|
+
if (gap !== void 0) messages.push(gap);
|
|
6619
|
+
}
|
|
6189
6620
|
return { text: messages.join("\n"), code: 1 };
|
|
6190
6621
|
}
|
|
6191
6622
|
const match = resolution.entry;
|
|
6192
6623
|
const fullSourceBytes = sumFileSizes([match.filePath]);
|
|
6193
6624
|
const refCounts = opts.stats === true ? queryRefCounts([match.name], globalDbPath(), resolveProjectRoot({ project: opts.projectRoot ?? process.cwd() })) : void 0;
|
|
6194
6625
|
if (opts.json === true) {
|
|
6195
|
-
const text2 =
|
|
6626
|
+
const text2 = displaySafeJson(
|
|
6196
6627
|
{
|
|
6197
6628
|
...match,
|
|
6198
6629
|
body: resolveBody(match),
|
|
@@ -6200,9 +6631,7 @@ function runRead(opts) {
|
|
|
6200
6631
|
// would be the one surface that still passes a deleted file's body off as a live read.
|
|
6201
6632
|
...fileIsGone(match.filePath) ? { deleted: true } : {},
|
|
6202
6633
|
...refCounts !== void 0 ? { refCount: refCounts.get(match.name) ?? 0 } : {}
|
|
6203
|
-
}
|
|
6204
|
-
null,
|
|
6205
|
-
2
|
|
6634
|
+
}
|
|
6206
6635
|
);
|
|
6207
6636
|
if (opts.suppressStat !== true) recordReadStat("read_replacement", fullSourceBytes, text2, opts.spec);
|
|
6208
6637
|
return { text: text2, code: 0 };
|
|
@@ -6238,11 +6667,11 @@ ${sub.text}`);
|
|
|
6238
6667
|
}
|
|
6239
6668
|
if (anyFound) {
|
|
6240
6669
|
const fullSourceBytes = sumFileSizes(Array.from(distinctFiles, (f) => resolveIndexPath(f, opts.projectRoot ?? process.cwd())));
|
|
6241
|
-
const text2 = opts.json === true ?
|
|
6670
|
+
const text2 = opts.json === true ? displaySafeJson(jsonOut) : textBlocks.join("\n\n");
|
|
6242
6671
|
recordReadStat("read_replacement", fullSourceBytes, text2, opts.spec);
|
|
6243
6672
|
return { text: text2, code: 0 };
|
|
6244
6673
|
}
|
|
6245
|
-
const text = opts.json === true ?
|
|
6674
|
+
const text = opts.json === true ? displaySafeJson(jsonOut) : textBlocks.join("\n\n");
|
|
6246
6675
|
return { text, code: 1 };
|
|
6247
6676
|
}
|
|
6248
6677
|
function resolveAgainstProjectRoot(file, projectRoot) {
|
|
@@ -6308,7 +6737,7 @@ function runSection(opts) {
|
|
|
6308
6737
|
const kind = result.redirectedFrom !== void 0 ? "section_replacement" : "section_read";
|
|
6309
6738
|
const fullSourceBytes = sumFileSizes([filePath]);
|
|
6310
6739
|
if (opts.json === true) {
|
|
6311
|
-
const text2 =
|
|
6740
|
+
const text2 = displaySafeJson(result);
|
|
6312
6741
|
if (opts.suppressStat !== true) recordReadStat(kind, fullSourceBytes, text2, heading);
|
|
6313
6742
|
return { text: text2, code: 0 };
|
|
6314
6743
|
}
|
|
@@ -6336,7 +6765,7 @@ function runSectionMulti(specFilePath, resolvedFilePath, headings, opts) {
|
|
|
6336
6765
|
${sub.text}`);
|
|
6337
6766
|
}
|
|
6338
6767
|
const fullSourceBytes = sumFileSizes([resolvedFilePath]);
|
|
6339
|
-
const text = opts.json === true ?
|
|
6768
|
+
const text = opts.json === true ? displaySafeJson(jsonOut) : textBlocks.join("\n\n");
|
|
6340
6769
|
if (anyFound) recordReadStat("section_read", fullSourceBytes, text, opts.spec);
|
|
6341
6770
|
return { text, code: anyFound ? 0 : 1 };
|
|
6342
6771
|
}
|
|
@@ -6358,7 +6787,7 @@ function runSectionCrossFile(pairs, opts) {
|
|
|
6358
6787
|
${sub.text}`);
|
|
6359
6788
|
}
|
|
6360
6789
|
const resolvePath = (f) => opts.projectRoot !== void 0 && !path4.isAbsolute(f) ? path4.resolve(opts.projectRoot, f) : f;
|
|
6361
|
-
const text = opts.json === true ?
|
|
6790
|
+
const text = opts.json === true ? displaySafeJson(jsonOut) : textBlocks.join("\n\n");
|
|
6362
6791
|
if (anyFound) {
|
|
6363
6792
|
const fullSourceBytes = sumFileSizes(Array.from(distinctFiles, resolvePath));
|
|
6364
6793
|
recordReadStat("section_read", fullSourceBytes, text, opts.spec);
|
|
@@ -6378,7 +6807,7 @@ function refsJsonItems(items, contextLines) {
|
|
|
6378
6807
|
}
|
|
6379
6808
|
function renderRefLines(ref, contextLines, indent = " ") {
|
|
6380
6809
|
const displayPath = refsDisplayPath(ref.filePath);
|
|
6381
|
-
const base = `${indent}${displayPath}:${ref.line}: ${ref.context}`;
|
|
6810
|
+
const base = `${indent}${displaySafeText(displayPath)}:${ref.line}: ${displaySafeText(ref.context)}`;
|
|
6382
6811
|
const window = buildContextWindow(ref.filePath, ref.line, contextLines);
|
|
6383
6812
|
if (window === null) return [base];
|
|
6384
6813
|
return [base, ...renderContextWindow(displayPath, ref.line, window, "", `${indent} `)];
|
|
@@ -6501,9 +6930,10 @@ function renderRefsTargets(targets, opts, {
|
|
|
6501
6930
|
if (notice !== null) lines.push(` token-goat: ${notice}`);
|
|
6502
6931
|
}
|
|
6503
6932
|
}
|
|
6933
|
+
warnIfFilesStale(refRows.map((r) => r.filePath));
|
|
6504
6934
|
const fullSourceBytes = refsSearchBaselineBytes(refRows);
|
|
6505
6935
|
if (opts.json === true) {
|
|
6506
|
-
const text2 =
|
|
6936
|
+
const text2 = displaySafeJson(jsonOut);
|
|
6507
6937
|
emit(text2);
|
|
6508
6938
|
if (anyFound) recordReadStat("symbol_read", fullSourceBytes, text2, opts.spec);
|
|
6509
6939
|
return anyFound ? 0 : 1;
|
|
@@ -6591,7 +7021,7 @@ function runRefsSingle(opts) {
|
|
|
6591
7021
|
if (results.length === 0) {
|
|
6592
7022
|
if (matchesGrep !== void 0 && preGrepCount > 0) {
|
|
6593
7023
|
if (opts.json === true) {
|
|
6594
|
-
emit(
|
|
7024
|
+
emit(displaySafeJson({ items: [], truncated: false, totalCount: 0, hiddenByGrep: preGrepCount }));
|
|
6595
7025
|
return 0;
|
|
6596
7026
|
}
|
|
6597
7027
|
emit(grepFilteredToEmptyNotice(preGrepCount, opts.grep ?? "", "reference", "references"));
|
|
@@ -6611,7 +7041,7 @@ function runRefsSingle(opts) {
|
|
|
6611
7041
|
const defPaths = defFileHint !== void 0 ? [defFileHint] : defRows.map((r) => r.filePath);
|
|
6612
7042
|
const firstDefPath = defPaths[0];
|
|
6613
7043
|
if (firstDefPath !== void 0 && defPaths.every((fp) => !isRefIndexedFile(fp))) {
|
|
6614
|
-
emitErr(refBlindLanguageNotice(symName,
|
|
7044
|
+
emitErr(refBlindLanguageNotice(symName, detectLanguageOfFile(firstDefPath), refsDisplayPath(firstDefPath)));
|
|
6615
7045
|
return 1;
|
|
6616
7046
|
}
|
|
6617
7047
|
const kindRows = defFileHint !== void 0 ? querySymbols({ name: symName, filePath: defFileHint, rootDir: rootDir2, limit: REF_BLIND_DEF_PROBE_LIMIT }) : defRows;
|
|
@@ -6627,6 +7057,7 @@ function runRefsSingle(opts) {
|
|
|
6627
7057
|
}
|
|
6628
7058
|
return 1;
|
|
6629
7059
|
}
|
|
7060
|
+
warnIfFilesStale(results.map((r) => r.filePath));
|
|
6630
7061
|
const fullSourceBytes = refsSearchBaselineBytes(results);
|
|
6631
7062
|
if (opts.json === true) {
|
|
6632
7063
|
let payload;
|
|
@@ -6638,7 +7069,7 @@ function runRefsSingle(opts) {
|
|
|
6638
7069
|
payload = { items: refsJsonItems(capped.items, opts.context ?? 0), truncated: capped.truncated || trueTotal > results.length, totalCount: trueTotal };
|
|
6639
7070
|
}
|
|
6640
7071
|
const hiddenByGrep = matchesGrep !== void 0 ? preGrepCount - (filteredTotal ?? results.length) : 0;
|
|
6641
|
-
const text2 =
|
|
7072
|
+
const text2 = displaySafeJson({ ...payload, ...hiddenByGrep > 0 ? { hiddenByGrep } : {} });
|
|
6642
7073
|
emit(text2);
|
|
6643
7074
|
recordReadStat("symbol_read", fullSourceBytes, text2, symName);
|
|
6644
7075
|
return 0;
|
|
@@ -6690,24 +7121,34 @@ function renderCallerGroups(refs, contextLines = 0) {
|
|
|
6690
7121
|
const lines = [];
|
|
6691
7122
|
for (const [file, fileRefs] of byFile) {
|
|
6692
7123
|
const displayPath = refsDisplayPath(file);
|
|
6693
|
-
lines.push(`${displayPath}:`);
|
|
7124
|
+
lines.push(`${displaySafeText(displayPath)}:`);
|
|
6694
7125
|
for (const ref of fileRefs) {
|
|
6695
|
-
lines.push(` :${ref.line} ${ref.context !== "" ? ref.context : "(module scope)"}`);
|
|
7126
|
+
lines.push(` :${ref.line} ${ref.context !== "" ? displaySafeText(ref.context) : "(module scope)"}`);
|
|
6696
7127
|
const window = buildContextWindow(file, ref.line, contextLines);
|
|
6697
7128
|
if (window !== null) lines.push(...renderContextWindow(displayPath, ref.line, window, "", " "));
|
|
6698
7129
|
}
|
|
6699
7130
|
}
|
|
6700
7131
|
return lines;
|
|
6701
7132
|
}
|
|
7133
|
+
function symbolExtractorGap(displayPath, resolvedPath) {
|
|
7134
|
+
const ext = path4.extname(resolvedPath).toLowerCase();
|
|
7135
|
+
const named = unsupportedLanguageName(resolvedPath);
|
|
7136
|
+
const language = detectLanguageOfFile(resolvedPath);
|
|
7137
|
+
if (named !== void 0 || language === "unknown") {
|
|
7138
|
+
const what = named !== void 0 ? `${named}, ${ext}` : ext !== "" ? ext : "no extension";
|
|
7139
|
+
return `'${displayPath}': token-goat has no symbol extractor for this file type (${what}), so there are no symbols to list; grep, plain reads and \`token-goat tokens\` still work on it.
|
|
7140
|
+
` + supportRequestLine(named ?? (ext !== "" ? `${ext} file` : "this file type"));
|
|
7141
|
+
}
|
|
7142
|
+
if (TREE_SITTER_LANGUAGES.includes(language) && !isTreeSitterAvailable(language)) {
|
|
7143
|
+
return `No symbols found in '${displayPath}', but tree-sitter parsing for this file type (${ext}) is unavailable, so only a coarse regex fallback ran. Run \`token-goat doctor\` for the cause and the fix.`;
|
|
7144
|
+
}
|
|
7145
|
+
return void 0;
|
|
7146
|
+
}
|
|
6702
7147
|
function noSymbolsMessage(displayPath, resolvedPath) {
|
|
6703
7148
|
if (!fs4.existsSync(resolvedPath)) {
|
|
6704
7149
|
return `Could not read: ${displayPath}`;
|
|
6705
7150
|
}
|
|
6706
|
-
|
|
6707
|
-
if (lang !== void 0) {
|
|
6708
|
-
return `No indexed symbols found in '${displayPath}' -- ${lang} has no symbol extractor yet, so this file always indexes to 0 symbols regardless of its contents`;
|
|
6709
|
-
}
|
|
6710
|
-
return `No indexed symbols found in '${displayPath}'`;
|
|
7151
|
+
return symbolExtractorGap(displayPath, resolvedPath) ?? `No indexed symbols found in '${displayPath}'`;
|
|
6711
7152
|
}
|
|
6712
7153
|
var SKELETON_SYMBOL_CAP = 5e3;
|
|
6713
7154
|
function hasRealDocstring(docstring) {
|
|
@@ -6746,7 +7187,8 @@ function prepareSymbolListing(file, opts) {
|
|
|
6746
7187
|
);
|
|
6747
7188
|
const refCounts = opts.stats === true ? queryRefCounts(filtered.map((s) => s.name), globalDbPath(), resolveProjectRoot({ project: opts.projectRoot ?? process.cwd() })) : void 0;
|
|
6748
7189
|
const fullSourceBytes = sumFileSizes([resolved]);
|
|
6749
|
-
|
|
7190
|
+
const totalLines = symbols.length > 0 ? Math.max(...symbols.map((s) => s.lineEnd)) : 0;
|
|
7191
|
+
return { kind: "ok", resolved, displayRoot: getDisplayRoot(opts.projectRoot), filtered, preFilterCount: symbols.length, refCounts, fullSourceBytes, symbolsTruncated, trueSymbolCount, totalLines };
|
|
6750
7192
|
}
|
|
6751
7193
|
function runPerFileListing(files, run, json = false) {
|
|
6752
7194
|
const blocks = [];
|
|
@@ -6781,7 +7223,7 @@ function mergeListingJson(files, blocks, anyOk) {
|
|
|
6781
7223
|
totalCount += parsed.totalCount ?? parsed.items.length;
|
|
6782
7224
|
}
|
|
6783
7225
|
const payload = { items, truncated, totalCount, ...errors.length > 0 ? { errors } : {} };
|
|
6784
|
-
return { text:
|
|
7226
|
+
return { text: displaySafeJson(payload), code: anyOk ? 0 : 1 };
|
|
6785
7227
|
}
|
|
6786
7228
|
function symbolCountLabel(shown, truncated, trueCount) {
|
|
6787
7229
|
if (!truncated || trueCount === void 0 || trueCount <= shown) return countNoun(shown, "symbol");
|
|
@@ -6794,7 +7236,7 @@ function runSkeleton(opts) {
|
|
|
6794
7236
|
if (prep.kind === "confined" || prep.kind === "empty") {
|
|
6795
7237
|
return { text: prep.text, code: 1 };
|
|
6796
7238
|
}
|
|
6797
|
-
const { resolved, displayRoot, filtered, preFilterCount, refCounts, fullSourceBytes, symbolsTruncated, trueSymbolCount } = prep;
|
|
7239
|
+
const { resolved, displayRoot, filtered, preFilterCount, refCounts, fullSourceBytes, symbolsTruncated, trueSymbolCount, totalLines } = prep;
|
|
6798
7240
|
if (opts.json === true) {
|
|
6799
7241
|
const rows = filtered.map((s) => ({
|
|
6800
7242
|
...opts.includeFilePath === true ? { filePath: toDisplayPath(displayRoot, s.filePath) } : {},
|
|
@@ -6814,11 +7256,10 @@ function runSkeleton(opts) {
|
|
|
6814
7256
|
// tests/json_envelope_shape.test.ts pins.
|
|
6815
7257
|
...fileIsGone(resolved) ? { deleted: true } : {}
|
|
6816
7258
|
};
|
|
6817
|
-
const text2 =
|
|
7259
|
+
const text2 = displaySafeJson(payload);
|
|
6818
7260
|
recordReadStat("stub_view", fullSourceBytes, text2, opts.file);
|
|
6819
7261
|
return { text: text2, code: 0 };
|
|
6820
7262
|
}
|
|
6821
|
-
const totalLines = filtered.length > 0 ? Math.max(...filtered.map((s) => s.lineEnd)) : 0;
|
|
6822
7263
|
const lines = [`# Skeleton: ${opts.file} (${symbolCountLabel(filtered.length, symbolsTruncated, trueSymbolCount)}, ${countNoun(totalLines, "line")})`];
|
|
6823
7264
|
if (filtered.length === 0 && preFilterCount > 0) lines.push(filteredToEmptyNotice(preFilterCount, opts.minLines, opts.grep));
|
|
6824
7265
|
for (const sym of filtered) {
|
|
@@ -6879,7 +7320,7 @@ function runOutline(opts) {
|
|
|
6879
7320
|
// Same envelope-level flag, and same reason, as runSkeleton's payload above.
|
|
6880
7321
|
...fileIsGone(resolved) ? { deleted: true } : {}
|
|
6881
7322
|
};
|
|
6882
|
-
const text2 =
|
|
7323
|
+
const text2 = displaySafeJson(payload);
|
|
6883
7324
|
recordReadStat("outline", fullSourceBytes, text2, opts.file);
|
|
6884
7325
|
return { text: text2, code: 0 };
|
|
6885
7326
|
}
|
|
@@ -6921,7 +7362,7 @@ function runCsvQuery(opts) {
|
|
|
6921
7362
|
...opts.noHeader === true ? { noHeader: true } : {}
|
|
6922
7363
|
});
|
|
6923
7364
|
if (result.header.length === 0) {
|
|
6924
|
-
emit(`No data rows found in ${opts.file}`);
|
|
7365
|
+
emit(`No data rows found in ${displaySafeText(opts.file)}`);
|
|
6925
7366
|
return 0;
|
|
6926
7367
|
}
|
|
6927
7368
|
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
@@ -6929,7 +7370,7 @@ function runCsvQuery(opts) {
|
|
|
6929
7370
|
const rowsJson = result.rows.map((r) => Object.fromEntries(result.header.map((h, i) => [h, r[i]])));
|
|
6930
7371
|
const headTruncated = result.rows.length < result.totalRows;
|
|
6931
7372
|
const capped = guardJsonRows(rowsJson);
|
|
6932
|
-
const jsonText =
|
|
7373
|
+
const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated || headTruncated, totalCount: result.totalRows, ...result.totalRows === 0 && result.preFilterRows > 0 ? { filteredFromRows: result.preFilterRows } : {} }, 0);
|
|
6933
7374
|
emit(jsonText);
|
|
6934
7375
|
recordReadStat("csv_query", fullSourceBytes, jsonText, opts.file);
|
|
6935
7376
|
} else {
|
|
@@ -6955,7 +7396,7 @@ function runCsvProfile(opts) {
|
|
|
6955
7396
|
...opts.noHeader === true ? { noHeader: true } : {}
|
|
6956
7397
|
});
|
|
6957
7398
|
if (profiles.length === 0) {
|
|
6958
|
-
emit(`No data rows found in ${opts.file}`);
|
|
7399
|
+
emit(`No data rows found in ${displaySafeText(opts.file)}`);
|
|
6959
7400
|
return 0;
|
|
6960
7401
|
}
|
|
6961
7402
|
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
@@ -6984,7 +7425,7 @@ function runOutlineCommand(opts, parse, formatLabel, kind) {
|
|
|
6984
7425
|
const outline = outlineJson(data);
|
|
6985
7426
|
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
6986
7427
|
if (opts.json === true) {
|
|
6987
|
-
const jsonText =
|
|
7428
|
+
const jsonText = displaySafeJson(outline, 0);
|
|
6988
7429
|
emit(jsonText);
|
|
6989
7430
|
recordReadStat(kind, fullSourceBytes, jsonText, opts.file);
|
|
6990
7431
|
} else {
|
|
@@ -7022,7 +7463,7 @@ function runQueryCommand(opts, parse, formatLabel, guardTag, kind) {
|
|
|
7022
7463
|
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
7023
7464
|
if (!result.fanned) {
|
|
7024
7465
|
const value = result.items[0];
|
|
7025
|
-
const valueText = opts.json === true ?
|
|
7466
|
+
const valueText = opts.json === true ? displaySafeJson(value, 0) : displaySafeJson(value);
|
|
7026
7467
|
emit(valueText);
|
|
7027
7468
|
recordReadStat(kind, fullSourceBytes, valueText, opts.file);
|
|
7028
7469
|
return 0;
|
|
@@ -7032,11 +7473,11 @@ function runQueryCommand(opts, parse, formatLabel, guardTag, kind) {
|
|
|
7032
7473
|
const headTruncated = limited.length < totalCount;
|
|
7033
7474
|
if (opts.json === true) {
|
|
7034
7475
|
const capped = guardJsonRows(limited);
|
|
7035
|
-
const jsonText =
|
|
7476
|
+
const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated || headTruncated, totalCount }, 0);
|
|
7036
7477
|
emit(jsonText);
|
|
7037
7478
|
recordReadStat(kind, fullSourceBytes, jsonText, opts.file);
|
|
7038
7479
|
} else {
|
|
7039
|
-
const lines = limited.map((item) =>
|
|
7480
|
+
const lines = limited.map((item) => displaySafeJson(item, 0));
|
|
7040
7481
|
if (headTruncated) {
|
|
7041
7482
|
lines.push(`...(${totalCount - limited.length} more items elided; use --head to see more)`);
|
|
7042
7483
|
}
|
|
@@ -7101,7 +7542,7 @@ ${extractErrorMessage(e)}`);
|
|
|
7101
7542
|
}
|
|
7102
7543
|
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
7103
7544
|
if (opts.json === true) {
|
|
7104
|
-
const jsonText =
|
|
7545
|
+
const jsonText = displaySafeJson(summary);
|
|
7105
7546
|
emit(jsonText);
|
|
7106
7547
|
recordReadStat("xml_outline", fullSourceBytes, jsonText, opts.file);
|
|
7107
7548
|
} else {
|
|
@@ -7130,17 +7571,17 @@ function runXmlQuery(opts) {
|
|
|
7130
7571
|
if (result.attributeValues !== void 0) {
|
|
7131
7572
|
if (result.attributeValues.length === 0) {
|
|
7132
7573
|
if (opts.json === true) {
|
|
7133
|
-
const jsonText =
|
|
7574
|
+
const jsonText = displaySafeJson({ items: [], truncated: false, totalCount: 0 }, 0);
|
|
7134
7575
|
emit(jsonText);
|
|
7135
7576
|
recordReadStat("xml_query", fullSourceBytes, jsonText, opts.file);
|
|
7136
7577
|
} else {
|
|
7137
|
-
emit(`No attributes matched path: '${opts.path}'`);
|
|
7578
|
+
emit(`No attributes matched path: '${displaySafeText(opts.path)}'`);
|
|
7138
7579
|
}
|
|
7139
7580
|
return 0;
|
|
7140
7581
|
}
|
|
7141
7582
|
if (!result.fanned) {
|
|
7142
7583
|
const val = result.attributeValues[0] ?? "";
|
|
7143
|
-
const outText = opts.json === true ?
|
|
7584
|
+
const outText = opts.json === true ? displaySafeJson(val, 0) : val;
|
|
7144
7585
|
emit(outText);
|
|
7145
7586
|
recordReadStat("xml_query", fullSourceBytes, outText, opts.file);
|
|
7146
7587
|
return 0;
|
|
@@ -7150,7 +7591,7 @@ function runXmlQuery(opts) {
|
|
|
7150
7591
|
const headTruncated2 = limited2.length < totalCount2;
|
|
7151
7592
|
if (opts.json === true) {
|
|
7152
7593
|
const capped = guardJsonRows(limited2);
|
|
7153
|
-
const jsonText =
|
|
7594
|
+
const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated || headTruncated2, totalCount: totalCount2 }, 0);
|
|
7154
7595
|
emit(jsonText);
|
|
7155
7596
|
recordReadStat("xml_query", fullSourceBytes, jsonText, opts.file);
|
|
7156
7597
|
} else {
|
|
@@ -7166,11 +7607,11 @@ function runXmlQuery(opts) {
|
|
|
7166
7607
|
}
|
|
7167
7608
|
if (result.items.length === 0) {
|
|
7168
7609
|
if (opts.json === true) {
|
|
7169
|
-
const jsonText =
|
|
7610
|
+
const jsonText = displaySafeJson({ items: [], truncated: false, totalCount: 0 }, 0);
|
|
7170
7611
|
emit(jsonText);
|
|
7171
7612
|
recordReadStat("xml_query", fullSourceBytes, jsonText, opts.file);
|
|
7172
7613
|
} else {
|
|
7173
|
-
emit(`No elements matched path: '${opts.path}'`);
|
|
7614
|
+
emit(`No elements matched path: '${displaySafeText(opts.path)}'`);
|
|
7174
7615
|
}
|
|
7175
7616
|
return 0;
|
|
7176
7617
|
}
|
|
@@ -7178,7 +7619,7 @@ function runXmlQuery(opts) {
|
|
|
7178
7619
|
const node = result.items[0];
|
|
7179
7620
|
if (opts.json === true) {
|
|
7180
7621
|
const jsonVal = xmlNodeToJson(node);
|
|
7181
|
-
const jsonText =
|
|
7622
|
+
const jsonText = displaySafeJson(jsonVal);
|
|
7182
7623
|
emit(jsonText);
|
|
7183
7624
|
recordReadStat("xml_query", fullSourceBytes, jsonText, opts.file);
|
|
7184
7625
|
} else {
|
|
@@ -7194,7 +7635,7 @@ function runXmlQuery(opts) {
|
|
|
7194
7635
|
if (opts.json === true) {
|
|
7195
7636
|
const jsonItems = limited.map(xmlNodeToJson);
|
|
7196
7637
|
const capped = guardJsonRows(jsonItems);
|
|
7197
|
-
const jsonText =
|
|
7638
|
+
const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated || headTruncated, totalCount }, 0);
|
|
7198
7639
|
emit(jsonText);
|
|
7199
7640
|
recordReadStat("xml_query", fullSourceBytes, jsonText, opts.file);
|
|
7200
7641
|
} else {
|
|
@@ -7212,6 +7653,160 @@ function runXmlQuery(opts) {
|
|
|
7212
7653
|
return 1;
|
|
7213
7654
|
}
|
|
7214
7655
|
}
|
|
7656
|
+
function runHtmlOutline(opts) {
|
|
7657
|
+
const text = readFileText(opts.file);
|
|
7658
|
+
if (text === null) {
|
|
7659
|
+
emitErr(`Could not read: ${opts.file}`);
|
|
7660
|
+
return 1;
|
|
7661
|
+
}
|
|
7662
|
+
const summary = outlineHtml(text);
|
|
7663
|
+
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
7664
|
+
if (opts.json === true) {
|
|
7665
|
+
const jsonText = displaySafeJson(summary);
|
|
7666
|
+
emit(jsonText);
|
|
7667
|
+
recordReadStat("html_outline", fullSourceBytes, jsonText, opts.file);
|
|
7668
|
+
} else {
|
|
7669
|
+
const outlineText = formatHtmlOutline(summary);
|
|
7670
|
+
emitGuarded(outlineText, "html-outline");
|
|
7671
|
+
recordReadStat("html_outline", fullSourceBytes, outlineText, opts.file);
|
|
7672
|
+
}
|
|
7673
|
+
return 0;
|
|
7674
|
+
}
|
|
7675
|
+
function runHtmlQuery(opts) {
|
|
7676
|
+
const text = readFileText(opts.file);
|
|
7677
|
+
if (text === null) {
|
|
7678
|
+
emitErr(`Could not read: ${opts.file}`);
|
|
7679
|
+
return 1;
|
|
7680
|
+
}
|
|
7681
|
+
let head;
|
|
7682
|
+
try {
|
|
7683
|
+
head = opts.head !== void 0 ? requireNonNegativeStrictInt("--head", opts.head) : void 0;
|
|
7684
|
+
} catch (e) {
|
|
7685
|
+
emitErr(extractErrorMessage(e));
|
|
7686
|
+
return 1;
|
|
7687
|
+
}
|
|
7688
|
+
try {
|
|
7689
|
+
const querySelector = opts.attr ? `${opts.selector}@${opts.attr}` : opts.selector;
|
|
7690
|
+
const result = queryHtml(text, querySelector);
|
|
7691
|
+
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
7692
|
+
if (result.attributeValues !== void 0) {
|
|
7693
|
+
if (result.attributeValues.length === 0) {
|
|
7694
|
+
if (opts.json === true) {
|
|
7695
|
+
const jsonText = displaySafeJson({ items: [], truncated: false, totalCount: 0 }, 0);
|
|
7696
|
+
emit(jsonText);
|
|
7697
|
+
recordReadStat("html_query", fullSourceBytes, jsonText, opts.file);
|
|
7698
|
+
} else {
|
|
7699
|
+
emit(`No attributes matched selector: '${displaySafeText(opts.selector)}'`);
|
|
7700
|
+
}
|
|
7701
|
+
return 0;
|
|
7702
|
+
}
|
|
7703
|
+
const totalCount2 = result.attributeValues.length;
|
|
7704
|
+
const limited2 = head !== void 0 ? result.attributeValues.slice(0, head) : result.attributeValues;
|
|
7705
|
+
const headTruncated2 = limited2.length < totalCount2;
|
|
7706
|
+
if (opts.json === true) {
|
|
7707
|
+
const capped = guardJsonRows(limited2);
|
|
7708
|
+
const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated || headTruncated2, totalCount: totalCount2 }, 0);
|
|
7709
|
+
emit(jsonText);
|
|
7710
|
+
recordReadStat("html_query", fullSourceBytes, jsonText, opts.file);
|
|
7711
|
+
} else {
|
|
7712
|
+
const lines = limited2.map((item) => item);
|
|
7713
|
+
if (headTruncated2) {
|
|
7714
|
+
lines.push(`...(${totalCount2 - limited2.length} more items elided; use --head to see more)`);
|
|
7715
|
+
}
|
|
7716
|
+
const plainText = lines.join("\n");
|
|
7717
|
+
emitGuarded(fenceHtmlText(plainText), "html-query");
|
|
7718
|
+
recordReadStat("html_query", fullSourceBytes, plainText, opts.file);
|
|
7719
|
+
}
|
|
7720
|
+
return 0;
|
|
7721
|
+
}
|
|
7722
|
+
if (result.elements.length === 0) {
|
|
7723
|
+
if (opts.json === true) {
|
|
7724
|
+
const jsonText = displaySafeJson({ items: [], truncated: false, totalCount: 0 }, 0);
|
|
7725
|
+
emit(jsonText);
|
|
7726
|
+
recordReadStat("html_query", fullSourceBytes, jsonText, opts.file);
|
|
7727
|
+
} else {
|
|
7728
|
+
emit(`No elements matched selector: '${displaySafeText(opts.selector)}'`);
|
|
7729
|
+
}
|
|
7730
|
+
return 0;
|
|
7731
|
+
}
|
|
7732
|
+
const totalCount = result.elements.length;
|
|
7733
|
+
const limited = head !== void 0 ? result.elements.slice(0, head) : result.elements;
|
|
7734
|
+
const headTruncated = limited.length < totalCount;
|
|
7735
|
+
if (opts.json === true) {
|
|
7736
|
+
const jsonItems = limited.map((n) => ({
|
|
7737
|
+
tag: n.tag,
|
|
7738
|
+
attributes: n.attributes,
|
|
7739
|
+
text: extractNodeText(n, text),
|
|
7740
|
+
line: n.line,
|
|
7741
|
+
endLine: n.endLine
|
|
7742
|
+
}));
|
|
7743
|
+
const capped = guardJsonRows(jsonItems);
|
|
7744
|
+
const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated || headTruncated, totalCount });
|
|
7745
|
+
emit(jsonText);
|
|
7746
|
+
recordReadStat("html_query", fullSourceBytes, jsonText, opts.file);
|
|
7747
|
+
} else if (opts.text === true) {
|
|
7748
|
+
const textLines = limited.map((n) => extractNodeText(n, text)).filter(Boolean);
|
|
7749
|
+
if (headTruncated) {
|
|
7750
|
+
textLines.push(`...(${totalCount - limited.length} more elements elided; use --head to see more)`);
|
|
7751
|
+
}
|
|
7752
|
+
const plainText = textLines.join("\n\n");
|
|
7753
|
+
emitGuarded(fenceHtmlText(plainText), "html-query");
|
|
7754
|
+
recordReadStat("html_query", fullSourceBytes, plainText, opts.file);
|
|
7755
|
+
} else {
|
|
7756
|
+
const blocks = limited.map((node) => serializeHtmlNode(node, 0, text));
|
|
7757
|
+
if (headTruncated) {
|
|
7758
|
+
blocks.push(`...(${totalCount - limited.length} more elements elided; use --head to see more)`);
|
|
7759
|
+
}
|
|
7760
|
+
const plainText = blocks.join("\n\n");
|
|
7761
|
+
emitGuarded(fenceHtmlText(plainText), "html-query");
|
|
7762
|
+
recordReadStat("html_query", fullSourceBytes, plainText, opts.file);
|
|
7763
|
+
}
|
|
7764
|
+
return 0;
|
|
7765
|
+
} catch (e) {
|
|
7766
|
+
emitErr(extractErrorMessage(e));
|
|
7767
|
+
return 1;
|
|
7768
|
+
}
|
|
7769
|
+
}
|
|
7770
|
+
function runHtmlLint(opts) {
|
|
7771
|
+
const text = readFileText(opts.file);
|
|
7772
|
+
if (text === null) {
|
|
7773
|
+
emitErr(`Could not read: ${opts.file}`);
|
|
7774
|
+
return 1;
|
|
7775
|
+
}
|
|
7776
|
+
const report = lintHtml(text);
|
|
7777
|
+
const isClean = opts.strict ? report.errors.length === 0 && report.warnings.length === 0 : report.errors.length === 0;
|
|
7778
|
+
if (opts.json === true) {
|
|
7779
|
+
emit(displaySafeJson(report));
|
|
7780
|
+
return isClean ? 0 : 1;
|
|
7781
|
+
}
|
|
7782
|
+
if (report.errors.length === 0 && report.warnings.length === 0) {
|
|
7783
|
+
emit(`\u2713 ${displaySafeText(opts.file)}: HTML structure is valid (all tags balanced, no duplicate IDs, void elements respected).`);
|
|
7784
|
+
return 0;
|
|
7785
|
+
}
|
|
7786
|
+
const lines = [];
|
|
7787
|
+
if (report.errors.length > 0) {
|
|
7788
|
+
lines.push(`Errors found in ${displaySafeText(opts.file)} (${report.errors.length}):`);
|
|
7789
|
+
for (const err of report.errors) {
|
|
7790
|
+
lines.push(` line ${err.line}: [${err.rule}] ${displaySafeText(err.message)}`);
|
|
7791
|
+
}
|
|
7792
|
+
}
|
|
7793
|
+
if (report.warnings.length > 0) {
|
|
7794
|
+
if (lines.length > 0) lines.push("");
|
|
7795
|
+
lines.push(`Warnings in ${displaySafeText(opts.file)} (${report.warnings.length}):`);
|
|
7796
|
+
for (const warn of report.warnings) {
|
|
7797
|
+
lines.push(` line ${warn.line}: [${warn.rule}] ${displaySafeText(warn.message)}`);
|
|
7798
|
+
}
|
|
7799
|
+
}
|
|
7800
|
+
const unbalanced = Object.entries(report.tagCounts).filter(([, c]) => c.diff !== 0);
|
|
7801
|
+
if (unbalanced.length > 0) {
|
|
7802
|
+
lines.push("", "Unbalanced tags:");
|
|
7803
|
+
for (const [tag, counts] of unbalanced) {
|
|
7804
|
+
lines.push(` <${tag}>: open=${counts.open}, close=${counts.close}, diff=${counts.diff}`);
|
|
7805
|
+
}
|
|
7806
|
+
}
|
|
7807
|
+
emit(lines.join("\n"));
|
|
7808
|
+
return isClean ? 0 : 1;
|
|
7809
|
+
}
|
|
7215
7810
|
function loadOpenApiOperations(file) {
|
|
7216
7811
|
const text = readFileText(file);
|
|
7217
7812
|
if (text === null) {
|
|
@@ -7232,7 +7827,7 @@ function runOpenApiOutline(opts) {
|
|
|
7232
7827
|
if (operations === null) return 1;
|
|
7233
7828
|
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
7234
7829
|
if (opts.json === true) {
|
|
7235
|
-
const jsonText =
|
|
7830
|
+
const jsonText = displaySafeJson(operations, 0);
|
|
7236
7831
|
emit(jsonText);
|
|
7237
7832
|
recordReadStat("openapi_outline", fullSourceBytes, jsonText, opts.file);
|
|
7238
7833
|
} else {
|
|
@@ -7256,7 +7851,7 @@ function runOpenApiOp(opts) {
|
|
|
7256
7851
|
}
|
|
7257
7852
|
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
7258
7853
|
if (opts.json === true) {
|
|
7259
|
-
const jsonText =
|
|
7854
|
+
const jsonText = displaySafeJson(match, 0);
|
|
7260
7855
|
emit(jsonText);
|
|
7261
7856
|
recordReadStat("openapi_op", fullSourceBytes, jsonText, opts.operation);
|
|
7262
7857
|
} else {
|
|
@@ -7294,7 +7889,7 @@ async function runZipList(opts) {
|
|
|
7294
7889
|
}
|
|
7295
7890
|
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
7296
7891
|
if (opts.json === true) {
|
|
7297
|
-
const jsonText =
|
|
7892
|
+
const jsonText = displaySafeJson(entries, 0);
|
|
7298
7893
|
emit(jsonText);
|
|
7299
7894
|
recordReadStat("zip_list", fullSourceBytes, jsonText, opts.file);
|
|
7300
7895
|
} else {
|
|
@@ -7345,7 +7940,7 @@ async function runZipRead(opts) {
|
|
|
7345
7940
|
const text = isValidUtf8(buf) ? buf.toString("utf-8") : "[binary content elided by token-goat]";
|
|
7346
7941
|
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
7347
7942
|
if (opts.json === true) {
|
|
7348
|
-
const jsonText =
|
|
7943
|
+
const jsonText = displaySafeJson({ path: opts.entry, text }, 0);
|
|
7349
7944
|
emit(jsonText);
|
|
7350
7945
|
recordReadStat("zip_read", fullSourceBytes, jsonText, opts.entry);
|
|
7351
7946
|
} else {
|
|
@@ -7399,7 +7994,7 @@ function runPrSlice(opts) {
|
|
|
7399
7994
|
const fullSourceBytes = Buffer.byteLength(JSON.stringify(files), "utf8");
|
|
7400
7995
|
if (opts.json === true) {
|
|
7401
7996
|
const capped = guardJsonRows(files);
|
|
7402
|
-
const jsonText =
|
|
7997
|
+
const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }, 0);
|
|
7403
7998
|
emit(jsonText);
|
|
7404
7999
|
recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} files`);
|
|
7405
8000
|
} else {
|
|
@@ -7411,14 +8006,15 @@ function runPrSlice(opts) {
|
|
|
7411
8006
|
}
|
|
7412
8007
|
case "diff": {
|
|
7413
8008
|
const diffText = fetchPrDiff(opts.pr, repo);
|
|
7414
|
-
const
|
|
7415
|
-
if (
|
|
8009
|
+
const rawFileDiff = extractFileDiff(diffText, parsed.path);
|
|
8010
|
+
if (rawFileDiff === null) {
|
|
7416
8011
|
emitErr(`No diff found for '${parsed.path}' in PR #${opts.pr}`);
|
|
7417
8012
|
return 1;
|
|
7418
8013
|
}
|
|
8014
|
+
const fileDiff = redactSecrets(rawFileDiff).text;
|
|
7419
8015
|
const fullSourceBytes = Buffer.byteLength(diffText, "utf8");
|
|
7420
8016
|
if (opts.json === true) {
|
|
7421
|
-
const jsonText =
|
|
8017
|
+
const jsonText = displaySafeJson({ path: parsed.path, diff: fenceGithubFieldIfMatched(fileDiff) }, 0);
|
|
7422
8018
|
emit(jsonText);
|
|
7423
8019
|
recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} diff:${parsed.path}`);
|
|
7424
8020
|
} else {
|
|
@@ -7428,12 +8024,17 @@ function runPrSlice(opts) {
|
|
|
7428
8024
|
return 0;
|
|
7429
8025
|
}
|
|
7430
8026
|
case "comments": {
|
|
7431
|
-
const
|
|
7432
|
-
const fullSourceBytes = Buffer.byteLength(JSON.stringify(
|
|
8027
|
+
const rawComments = fetchPrComments(opts.pr, repo);
|
|
8028
|
+
const fullSourceBytes = Buffer.byteLength(JSON.stringify(rawComments), "utf8");
|
|
8029
|
+
const comments = rawComments.map((c) => ({
|
|
8030
|
+
...c,
|
|
8031
|
+
body: redactSecrets(c.body).text,
|
|
8032
|
+
...c.diffHunk !== void 0 ? { diffHunk: redactSecrets(c.diffHunk).text } : {}
|
|
8033
|
+
}));
|
|
7433
8034
|
if (opts.json === true) {
|
|
7434
8035
|
const fencedComments = comments.map((c) => ({ ...c, body: fenceGithubFieldIfMatched(c.body) }));
|
|
7435
8036
|
const capped = guardJsonRows(fencedComments);
|
|
7436
|
-
const jsonText =
|
|
8037
|
+
const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }, 0);
|
|
7437
8038
|
emit(jsonText);
|
|
7438
8039
|
recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} comments`);
|
|
7439
8040
|
} else {
|
|
@@ -7444,15 +8045,20 @@ function runPrSlice(opts) {
|
|
|
7444
8045
|
return 0;
|
|
7445
8046
|
}
|
|
7446
8047
|
case "description": {
|
|
7447
|
-
const
|
|
7448
|
-
const fullSourceBytes = Buffer.byteLength(JSON.stringify(
|
|
8048
|
+
const rawDesc = fetchPrDescription(opts.pr, repo);
|
|
8049
|
+
const fullSourceBytes = Buffer.byteLength(JSON.stringify(rawDesc), "utf8");
|
|
8050
|
+
const desc = {
|
|
8051
|
+
...rawDesc,
|
|
8052
|
+
title: redactSecrets(rawDesc.title).text,
|
|
8053
|
+
body: rawDesc.body !== null ? redactSecrets(rawDesc.body).text : null
|
|
8054
|
+
};
|
|
7449
8055
|
if (opts.json === true) {
|
|
7450
8056
|
const fencedDesc = {
|
|
7451
8057
|
...desc,
|
|
7452
8058
|
title: fenceGithubFieldIfMatched(desc.title),
|
|
7453
8059
|
body: desc.body !== null ? fenceGithubFieldIfMatched(desc.body) : null
|
|
7454
8060
|
};
|
|
7455
|
-
const jsonText =
|
|
8061
|
+
const jsonText = displaySafeJson(fencedDesc, 0);
|
|
7456
8062
|
emit(jsonText);
|
|
7457
8063
|
recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} description`);
|
|
7458
8064
|
} else {
|
|
@@ -7473,7 +8079,7 @@ function runSqliteSchema(opts) {
|
|
|
7473
8079
|
const schema = getSqliteSchema(opts.file);
|
|
7474
8080
|
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
7475
8081
|
if (opts.json === true) {
|
|
7476
|
-
const jsonText =
|
|
8082
|
+
const jsonText = displaySafeJson(schema, 0);
|
|
7477
8083
|
emit(jsonText);
|
|
7478
8084
|
recordReadStat("sqlite_schema", fullSourceBytes, jsonText, opts.file);
|
|
7479
8085
|
} else {
|
|
@@ -7502,22 +8108,22 @@ function runSqliteQuery(opts) {
|
|
|
7502
8108
|
const rows = head !== void 0 ? result.rows.slice(0, head) : result.rows;
|
|
7503
8109
|
if (opts.json === true) {
|
|
7504
8110
|
const capped = guardJsonRows(rows);
|
|
7505
|
-
const jsonText =
|
|
8111
|
+
const jsonText = displaySafeJson({
|
|
7506
8112
|
columns: result.columns,
|
|
7507
8113
|
items: capped.items,
|
|
7508
8114
|
truncated: capped.truncated || headTruncated || result.rowCapped,
|
|
7509
8115
|
totalCount,
|
|
7510
8116
|
rowCapped: result.rowCapped
|
|
7511
|
-
});
|
|
8117
|
+
}, 0);
|
|
7512
8118
|
emit(jsonText);
|
|
7513
8119
|
const uncappedFull = guardJsonRows(result.rows);
|
|
7514
|
-
const baselineJsonText =
|
|
8120
|
+
const baselineJsonText = displaySafeJson({
|
|
7515
8121
|
columns: result.columns,
|
|
7516
8122
|
items: uncappedFull.items,
|
|
7517
8123
|
truncated: uncappedFull.truncated || result.rowCapped,
|
|
7518
8124
|
totalCount,
|
|
7519
8125
|
rowCapped: result.rowCapped
|
|
7520
|
-
});
|
|
8126
|
+
}, 0);
|
|
7521
8127
|
recordReadStat("sqlite_query", Buffer.byteLength(baselineJsonText, "utf8"), jsonText, opts.file);
|
|
7522
8128
|
} else {
|
|
7523
8129
|
const text = formatSqliteQueryTable({ ...result, rows }, { headTruncated });
|
|
@@ -7548,7 +8154,7 @@ ${extractErrorMessage(e)}`);
|
|
|
7548
8154
|
const scoped = opts.fileFilter !== void 0 ? filterCoverageGapsByFile(report, opts.fileFilter) : report;
|
|
7549
8155
|
const fullSourceBytes = sumFileSizes([opts.file]);
|
|
7550
8156
|
if (opts.json === true) {
|
|
7551
|
-
const jsonText =
|
|
8157
|
+
const jsonText = displaySafeJson(scoped, 0);
|
|
7552
8158
|
emit(jsonText);
|
|
7553
8159
|
recordReadStat("coverage_report_gaps", fullSourceBytes, jsonText, opts.file);
|
|
7554
8160
|
} else {
|
|
@@ -7583,7 +8189,7 @@ function runConflicts(opts) {
|
|
|
7583
8189
|
const fullSourceBytes = sumFileSizes(files);
|
|
7584
8190
|
const detail = opts.path ?? ".";
|
|
7585
8191
|
if (opts.json === true) {
|
|
7586
|
-
const jsonText =
|
|
8192
|
+
const jsonText = displaySafeJson(opts.summary === true ? results.map(summarizeFileConflicts) : results, 0);
|
|
7587
8193
|
emit(jsonText);
|
|
7588
8194
|
recordReadStat("conflicts", fullSourceBytes, jsonText, detail);
|
|
7589
8195
|
} else if (opts.summary === true) {
|
|
@@ -7597,34 +8203,24 @@ function runConflicts(opts) {
|
|
|
7597
8203
|
}
|
|
7598
8204
|
return 0;
|
|
7599
8205
|
}
|
|
7600
|
-
async function
|
|
8206
|
+
async function readPdfBytes(file) {
|
|
7601
8207
|
if (!fileExists(file)) {
|
|
7602
8208
|
throw new Error(`Could not read: ${file}`);
|
|
7603
8209
|
}
|
|
7604
|
-
|
|
7605
|
-
|
|
8210
|
+
return readPdfFileWithinBounds(file);
|
|
8211
|
+
}
|
|
8212
|
+
async function runPdfExtractText(file, pagesSpec, layout = false) {
|
|
8213
|
+
const result = await extractPdfText(await readPdfBytes(file), pagesSpec, layout);
|
|
7606
8214
|
return result.text;
|
|
7607
8215
|
}
|
|
7608
8216
|
async function runPdfOutline(file) {
|
|
7609
|
-
|
|
7610
|
-
throw new Error(`Could not read: ${file}`);
|
|
7611
|
-
}
|
|
7612
|
-
const data = fs4.readFileSync(file);
|
|
7613
|
-
return extractPdfOutline(new Uint8Array(data));
|
|
8217
|
+
return extractPdfOutline(await readPdfBytes(file));
|
|
7614
8218
|
}
|
|
7615
8219
|
async function runPdfMeta(file) {
|
|
7616
|
-
|
|
7617
|
-
throw new Error(`Could not read: ${file}`);
|
|
7618
|
-
}
|
|
7619
|
-
const data = fs4.readFileSync(file);
|
|
7620
|
-
return extractPdfMeta(new Uint8Array(data));
|
|
8220
|
+
return extractPdfMeta(await readPdfBytes(file));
|
|
7621
8221
|
}
|
|
7622
8222
|
async function runPdfLocate(file, pattern, opts) {
|
|
7623
|
-
|
|
7624
|
-
throw new Error(`Could not read: ${file}`);
|
|
7625
|
-
}
|
|
7626
|
-
const data = fs4.readFileSync(file);
|
|
7627
|
-
return locatePdfPages(new Uint8Array(data), pattern, opts);
|
|
8223
|
+
return locatePdfPages(await readPdfBytes(file), pattern, opts);
|
|
7628
8224
|
}
|
|
7629
8225
|
async function runImageMeta(file) {
|
|
7630
8226
|
if (!fileExists(file)) {
|
|
@@ -7745,14 +8341,15 @@ ${emptyIndexMessage(rootDir2)}`, code: 1 };
|
|
|
7745
8341
|
...hiddenByGrep > 0 ? { hiddenByGrep } : {},
|
|
7746
8342
|
section
|
|
7747
8343
|
};
|
|
7748
|
-
const jsonText =
|
|
8344
|
+
const jsonText = displaySafeJson(result);
|
|
7749
8345
|
if (opts.suppressStat !== true) recordReadStat("brief_view", fullSourceBytes, jsonText, opts.spec);
|
|
7750
8346
|
return { text: jsonText, code: 0 };
|
|
7751
8347
|
}
|
|
7752
8348
|
const body = resolveBody(match);
|
|
7753
8349
|
const bodyLen = match.lineEnd - match.lineStart + 1;
|
|
7754
8350
|
const lines = [
|
|
7755
|
-
|
|
8351
|
+
// This header is token-goat's own line quoting a repo-chosen name, kind and path, so it is escaped. `body` below it is the source the reader asked for and stays byte-for-byte.
|
|
8352
|
+
`# ${displaySafeText(match.name)} ${displaySafeText(match.kind)} ${displaySafeText(toDisplayPath(rootDir, match.filePath))}:${match.lineStart}-${match.lineEnd}`,
|
|
7756
8353
|
`# ${countNoun(bodyLen, "line")} (~${Math.ceil(body.length / 4)} tok)`,
|
|
7757
8354
|
body,
|
|
7758
8355
|
""
|
|
@@ -7795,7 +8392,7 @@ function runBriefMulti(file, symbols, opts) {
|
|
|
7795
8392
|
${sub.text}`);
|
|
7796
8393
|
}
|
|
7797
8394
|
const fullSourceBytes = sumFileSizes([resolveIndexPath(file, opts.projectRoot ?? process.cwd())]);
|
|
7798
|
-
const text = opts.json === true ?
|
|
8395
|
+
const text = opts.json === true ? displaySafeJson(jsonOut) : textBlocks.join("\n\n");
|
|
7799
8396
|
if (anyFound) recordReadStat("brief_view", fullSourceBytes, text, opts.spec);
|
|
7800
8397
|
return { text, code: anyFound ? 0 : 1 };
|
|
7801
8398
|
}
|
|
@@ -7817,7 +8414,7 @@ function runBriefCrossFile(pairs, opts) {
|
|
|
7817
8414
|
${sub.text}`);
|
|
7818
8415
|
}
|
|
7819
8416
|
const fullSourceBytes = sumFileSizes([...distinctFiles].map((f) => resolveIndexPath(f, opts.projectRoot ?? process.cwd())));
|
|
7820
|
-
const text = opts.json === true ?
|
|
8417
|
+
const text = opts.json === true ? displaySafeJson(jsonOut) : textBlocks.join("\n\n");
|
|
7821
8418
|
if (anyFound) recordReadStat("brief_view", fullSourceBytes, text, opts.spec);
|
|
7822
8419
|
return { text, code: anyFound ? 0 : 1 };
|
|
7823
8420
|
}
|
|
@@ -7874,7 +8471,7 @@ function runFind(opts) {
|
|
|
7874
8471
|
}
|
|
7875
8472
|
if (opts.json === true) {
|
|
7876
8473
|
const fuzzyPayload = fuzzyNames.length > 0 ? { fuzzy: true, matchedNames: fuzzyNames } : {};
|
|
7877
|
-
emit(
|
|
8474
|
+
emit(displaySafeJson({ files, truncated, totalCount: allFiles.length, ...fuzzyPayload }));
|
|
7878
8475
|
return 0;
|
|
7879
8476
|
}
|
|
7880
8477
|
if (fuzzyNames.length > 0) {
|
|
@@ -7914,7 +8511,7 @@ function runListSections(opts) {
|
|
|
7914
8511
|
const filtered = matchesGrep !== void 0 ? labelled.filter((_, i) => matchesGrep(sections[i] ?? "")) : labelled;
|
|
7915
8512
|
if (filtered.length === 0) {
|
|
7916
8513
|
if (opts.json === true) {
|
|
7917
|
-
emit(
|
|
8514
|
+
emit(displaySafeJson({ items: [], truncated: false, totalCount: 0 }));
|
|
7918
8515
|
return 0;
|
|
7919
8516
|
}
|
|
7920
8517
|
emit(grepFilteredToEmptyNotice(preFilterCount, opts.grep ?? "", "section", "sections"));
|
|
@@ -7922,7 +8519,7 @@ function runListSections(opts) {
|
|
|
7922
8519
|
}
|
|
7923
8520
|
if (opts.json === true) {
|
|
7924
8521
|
const capped = guardJsonRows(filtered);
|
|
7925
|
-
emit(
|
|
8522
|
+
emit(displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }));
|
|
7926
8523
|
return 0;
|
|
7927
8524
|
}
|
|
7928
8525
|
for (const heading of filtered) {
|
|
@@ -8022,7 +8619,7 @@ function runChanged(opts = {}) {
|
|
|
8022
8619
|
return 1;
|
|
8023
8620
|
}
|
|
8024
8621
|
const emptyEnvelope = () => {
|
|
8025
|
-
emit(
|
|
8622
|
+
emit(displaySafeJson({ items: [], truncated: false, totalCount: 0 }));
|
|
8026
8623
|
return 0;
|
|
8027
8624
|
};
|
|
8028
8625
|
if (changedFiles.length === 0) {
|
|
@@ -8083,14 +8680,14 @@ function runChanged(opts = {}) {
|
|
|
8083
8680
|
const symbolFullBytes = symbolDiffBaselineBytes;
|
|
8084
8681
|
if (opts.json === true) {
|
|
8085
8682
|
const capped = guardJsonRows(allSymbols);
|
|
8086
|
-
const text =
|
|
8683
|
+
const text = displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount });
|
|
8087
8684
|
emit(text);
|
|
8088
8685
|
recordReadStat("changed_lookup", symbolFullBytes, text, ref);
|
|
8089
8686
|
return 0;
|
|
8090
8687
|
}
|
|
8091
8688
|
const symbolText = allSymbols.map((s) => `${s.name} (${s.kind}) \u2014 ${toDisplayPath(projectRoot, s.filePath)}:${s.lineStart}`).join("\n");
|
|
8092
8689
|
for (const s of allSymbols) {
|
|
8093
|
-
emit(`${s.name} (${s.kind}) \u2014 ${toDisplayPath(projectRoot, s.filePath)}:${s.lineStart}`);
|
|
8690
|
+
emit(`${displaySafeText(s.name)} (${displaySafeText(s.kind)}) \u2014 ${displaySafeText(toDisplayPath(projectRoot, s.filePath))}:${s.lineStart}`);
|
|
8094
8691
|
}
|
|
8095
8692
|
recordReadStat("changed_lookup", symbolFullBytes, symbolText, ref);
|
|
8096
8693
|
return 0;
|
|
@@ -8098,7 +8695,7 @@ function runChanged(opts = {}) {
|
|
|
8098
8695
|
const fullBytes = changedDiffBaselineBytes(cwd, ref, changedFiles);
|
|
8099
8696
|
if (opts.json === true) {
|
|
8100
8697
|
const capped = guardJsonRows(changedFiles);
|
|
8101
|
-
const text =
|
|
8698
|
+
const text = displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount });
|
|
8102
8699
|
emit(text);
|
|
8103
8700
|
recordReadStat("changed_lookup", fullBytes, text, ref);
|
|
8104
8701
|
return 0;
|
|
@@ -8199,19 +8796,19 @@ function runDiff(opts) {
|
|
|
8199
8796
|
return 1;
|
|
8200
8797
|
}
|
|
8201
8798
|
if (diffResult.stdout.trim() === "") {
|
|
8202
|
-
emit(`No changes to '${match.name}' in '${toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)}'.`);
|
|
8799
|
+
emit(`No changes to '${displaySafeText(match.name)}' in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
|
|
8203
8800
|
return 0;
|
|
8204
8801
|
}
|
|
8205
8802
|
const { hunks } = splitDiffHunks(diffResult.stdout);
|
|
8206
8803
|
const overlapping = hunks.filter((h) => h.start <= match.lineEnd && h.end >= match.lineStart);
|
|
8207
8804
|
if (overlapping.length === 0) {
|
|
8208
|
-
emit(`No changes to '${match.name}' (lines ${match.lineStart}-${match.lineEnd}) in '${toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)}'.`);
|
|
8805
|
+
emit(`No changes to '${displaySafeText(match.name)}' (lines ${match.lineStart}-${match.lineEnd}) in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
|
|
8209
8806
|
return 0;
|
|
8210
8807
|
}
|
|
8211
8808
|
if (opts.json === true) {
|
|
8212
8809
|
const capped = guardJsonRows(overlapping.map((h) => ({ start: h.start, end: h.end, text: h.text })));
|
|
8213
8810
|
emit(
|
|
8214
|
-
|
|
8811
|
+
displaySafeJson(
|
|
8215
8812
|
{
|
|
8216
8813
|
symbol: match.name,
|
|
8217
8814
|
file: match.filePath,
|
|
@@ -8220,14 +8817,12 @@ function runDiff(opts) {
|
|
|
8220
8817
|
hunks: capped.items,
|
|
8221
8818
|
truncated: capped.truncated,
|
|
8222
8819
|
totalCount: capped.totalCount
|
|
8223
|
-
}
|
|
8224
|
-
null,
|
|
8225
|
-
2
|
|
8820
|
+
}
|
|
8226
8821
|
)
|
|
8227
8822
|
);
|
|
8228
8823
|
return 0;
|
|
8229
8824
|
}
|
|
8230
|
-
const header = `# ${match.name} (${match.kind}) \u2014 ${toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)}:${match.lineStart}-${match.lineEnd}`;
|
|
8825
|
+
const header = `# ${displaySafeText(match.name)} (${displaySafeText(match.kind)}) \u2014 ${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}:${match.lineStart}-${match.lineEnd}`;
|
|
8231
8826
|
emit(guardText([header, ...overlapping.map((h) => h.text)].join("\n"), "diff"));
|
|
8232
8827
|
return 0;
|
|
8233
8828
|
}
|
|
@@ -8292,17 +8887,17 @@ function runLog(opts) {
|
|
|
8292
8887
|
return 1;
|
|
8293
8888
|
}
|
|
8294
8889
|
if (logResult.exitCode !== 0) {
|
|
8295
|
-
emitErr(`git log failed: ${logResult.stderr}`);
|
|
8890
|
+
emitErr(`git log failed: ${displaySafeText(logResult.stderr)}`);
|
|
8296
8891
|
return 1;
|
|
8297
8892
|
}
|
|
8298
8893
|
if (logResult.stdout.trim() === "") {
|
|
8299
|
-
emit(`No history for '${match.name}' (lines ${match.lineStart}-${match.lineEnd}) in '${toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)}'.`);
|
|
8894
|
+
emit(`No history for '${displaySafeText(match.name)}' (lines ${match.lineStart}-${match.lineEnd}) in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
|
|
8300
8895
|
return 0;
|
|
8301
8896
|
}
|
|
8302
8897
|
if (opts.json === true) {
|
|
8303
8898
|
const capped = guardJsonRows(parseLogDashLOutput(logResult.stdout));
|
|
8304
8899
|
emit(
|
|
8305
|
-
|
|
8900
|
+
displaySafeJson(
|
|
8306
8901
|
{
|
|
8307
8902
|
symbol: match.name,
|
|
8308
8903
|
file: match.filePath,
|
|
@@ -8311,32 +8906,30 @@ function runLog(opts) {
|
|
|
8311
8906
|
commits: capped.items,
|
|
8312
8907
|
truncated: capped.truncated,
|
|
8313
8908
|
totalCount: capped.totalCount
|
|
8314
|
-
}
|
|
8315
|
-
null,
|
|
8316
|
-
2
|
|
8909
|
+
}
|
|
8317
8910
|
)
|
|
8318
8911
|
);
|
|
8319
8912
|
return 0;
|
|
8320
8913
|
}
|
|
8321
|
-
const header = `# ${match.name} (${match.kind}) \u2014 ${toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)}:${match.lineStart}-${match.lineEnd}`;
|
|
8914
|
+
const header = `# ${displaySafeText(match.name)} (${displaySafeText(match.kind)}) \u2014 ${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}:${match.lineStart}-${match.lineEnd}`;
|
|
8322
8915
|
emit(guardText([header, logResult.stdout].join("\n"), "diff"));
|
|
8323
8916
|
return 0;
|
|
8324
8917
|
}
|
|
8325
8918
|
function foldRealpath(p) {
|
|
8326
8919
|
const n = normalizePath(p);
|
|
8327
|
-
return process.platform === "win32" ? n
|
|
8920
|
+
return process.platform === "win32" ? foldCaseForContainment(n) : n;
|
|
8328
8921
|
}
|
|
8329
8922
|
function runGrep(opts) {
|
|
8330
|
-
const
|
|
8923
|
+
const anchorSearchPath = (p) => opts.projectRoot === void 0 || path4.isAbsolute(p) ? p : path4.resolve(opts.projectRoot, p);
|
|
8924
|
+
const searchPaths = opts.path === void 0 ? [opts.projectRoot ?? process.cwd()] : (Array.isArray(opts.path) ? opts.path : [opts.path]).map(anchorSearchPath);
|
|
8331
8925
|
const maxLines = opts.maxLines ?? GREP_MAX_LINES;
|
|
8332
8926
|
const contextLines = opts.context ?? 0;
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
regex
|
|
8336
|
-
} catch {
|
|
8337
|
-
emitErr(`Invalid regex: ${opts.pattern}`);
|
|
8927
|
+
const guarded = compileGuardedRegex(opts.pattern);
|
|
8928
|
+
if (!guarded.ok) {
|
|
8929
|
+
emitErr(`Invalid regex: ${opts.pattern} -- ${guarded.reason}`);
|
|
8338
8930
|
return 1;
|
|
8339
8931
|
}
|
|
8932
|
+
const regex = guarded.re;
|
|
8340
8933
|
const hits = [];
|
|
8341
8934
|
function searchFile(filePath) {
|
|
8342
8935
|
try {
|
|
@@ -8464,7 +9057,7 @@ function runGrep(opts) {
|
|
|
8464
9057
|
}
|
|
8465
9058
|
if (opts.json === true) {
|
|
8466
9059
|
const payload = { items: truncated, truncated: hits.length > maxLines, totalCount: hits.length };
|
|
8467
|
-
emit(
|
|
9060
|
+
emit(displaySafeJson(payload));
|
|
8468
9061
|
return 0;
|
|
8469
9062
|
}
|
|
8470
9063
|
for (const hit of truncated) {
|
|
@@ -8472,7 +9065,7 @@ function runGrep(opts) {
|
|
|
8472
9065
|
if (hit.context !== void 0) {
|
|
8473
9066
|
for (const line of renderContextWindow(hit.file, hit.line, hit.context, symbolTag)) emit(line);
|
|
8474
9067
|
} else {
|
|
8475
|
-
emit(`${hit.file}:${hit.line}: ${hit.text}${symbolTag}`);
|
|
9068
|
+
emit(`${displaySafeText(hit.file)}:${hit.line}: ${hit.text}${symbolTag}`);
|
|
8476
9069
|
}
|
|
8477
9070
|
}
|
|
8478
9071
|
if (hits.length > maxLines) {
|
|
@@ -8577,7 +9170,7 @@ function runConfigGet(opts) {
|
|
|
8577
9170
|
return 1;
|
|
8578
9171
|
}
|
|
8579
9172
|
}
|
|
8580
|
-
emit(
|
|
9173
|
+
emit(displaySafeJson(obj, 0));
|
|
8581
9174
|
return 0;
|
|
8582
9175
|
} catch {
|
|
8583
9176
|
emitErr(`Failed to parse JSON: ${opts.file}`);
|
|
@@ -8673,7 +9266,7 @@ function runExports(opts) {
|
|
|
8673
9266
|
return 1;
|
|
8674
9267
|
}
|
|
8675
9268
|
const diskPath = resolveAgainstProjectRoot(opts.file, opts.projectRoot);
|
|
8676
|
-
const symbols = querySymbols({ filePath: resolveIndexPath(diskPath), limit:
|
|
9269
|
+
const symbols = querySymbols({ filePath: resolveIndexPath(diskPath), limit: -1 });
|
|
8677
9270
|
const kindOf = (name) => symbols.find((s) => s.name === name)?.kind ?? "export";
|
|
8678
9271
|
const locOf = (name) => {
|
|
8679
9272
|
const s = symbols.find((sym) => sym.name === name);
|
|
@@ -8698,7 +9291,7 @@ function runExports(opts) {
|
|
|
8698
9291
|
for (const n of extractExportNames(text, ext)) if (!names.includes(n)) names.push(n);
|
|
8699
9292
|
}
|
|
8700
9293
|
if (names.length === 0) {
|
|
8701
|
-
emit(`No exported symbols found in '${opts.file}'`);
|
|
9294
|
+
emit(`No exported symbols found in '${displaySafeText(opts.file)}'`);
|
|
8702
9295
|
return 0;
|
|
8703
9296
|
}
|
|
8704
9297
|
const preFilterCount = names.length;
|
|
@@ -8707,7 +9300,7 @@ function runExports(opts) {
|
|
|
8707
9300
|
const fullSourceBytes = sumFileSizes([diskPath]);
|
|
8708
9301
|
if (filteredNames.length === 0) {
|
|
8709
9302
|
if (opts.json === true) {
|
|
8710
|
-
const jsonText =
|
|
9303
|
+
const jsonText = displaySafeJson([]);
|
|
8711
9304
|
emit(jsonText);
|
|
8712
9305
|
recordReadStat("exports", fullSourceBytes, jsonText, opts.file);
|
|
8713
9306
|
return 0;
|
|
@@ -8718,13 +9311,11 @@ function runExports(opts) {
|
|
|
8718
9311
|
return 0;
|
|
8719
9312
|
}
|
|
8720
9313
|
if (opts.json === true) {
|
|
8721
|
-
const jsonText =
|
|
9314
|
+
const jsonText = displaySafeJson(
|
|
8722
9315
|
filteredNames.map((n) => {
|
|
8723
9316
|
const loc = locOf(n);
|
|
8724
9317
|
return { name: n, kind: kindOf(n), lineStart: loc?.lineStart ?? null, lineEnd: loc?.lineEnd ?? null };
|
|
8725
|
-
})
|
|
8726
|
-
null,
|
|
8727
|
-
2
|
|
9318
|
+
})
|
|
8728
9319
|
);
|
|
8729
9320
|
emit(jsonText);
|
|
8730
9321
|
recordReadStat("exports", fullSourceBytes, jsonText, opts.file);
|
|
@@ -8929,6 +9520,27 @@ function extractImports(text, ext) {
|
|
|
8929
9520
|
let m;
|
|
8930
9521
|
while ((m = re.exec(line)) !== null) push(m[1]);
|
|
8931
9522
|
}
|
|
9523
|
+
} else if (e === ".vb" || e === ".bas" || e === ".vbs") {
|
|
9524
|
+
for (const line of lines) {
|
|
9525
|
+
const m = /^\s*Imports\s+([^'<][^']*)/i.exec(line);
|
|
9526
|
+
if (!m) continue;
|
|
9527
|
+
for (const clause of m[1].split(",")) {
|
|
9528
|
+
const c = clause.trim();
|
|
9529
|
+
if (c === "" || c.startsWith("<")) continue;
|
|
9530
|
+
const alias = /^[A-Za-z_]\w*\s*=\s*([\w.]+(?:\(Of[^)]*\))?)/i.exec(c);
|
|
9531
|
+
push(alias ? alias[1] : (/^[\w.]+/.exec(c) ?? [void 0])[0]);
|
|
9532
|
+
}
|
|
9533
|
+
}
|
|
9534
|
+
} else if (/^\.(?:cbl|cob|cpy|cobol)$/i.test(e)) {
|
|
9535
|
+
for (const imp of extractCobol(text, `imports${e}`).imports) push(imp.target);
|
|
9536
|
+
} else if (/^\.ns[pnsalgch]$/i.test(e)) {
|
|
9537
|
+
for (const imp of extractNatural(text, `imports${e}`).imports) push(imp.target);
|
|
9538
|
+
} else if (STATEMENT_ADAPTER_IMPORTS.has(e)) {
|
|
9539
|
+
for (const imp of STATEMENT_ADAPTER_IMPORTS.get(e)(text, `imports${e}`).imports) push(imp.target);
|
|
9540
|
+
} else if (braceAdapterImportsFor(e, text) !== void 0) {
|
|
9541
|
+
for (const imp of braceAdapterImportsFor(e, text)(text, `imports${e}`).imports) push(imp.target);
|
|
9542
|
+
} else if ((e === ".p" || e === ".w" || e === ".cls") && isAblSource(text)) {
|
|
9543
|
+
for (const imp of extractAbl(text, `imports${e}`).imports) push(imp.target);
|
|
8932
9544
|
} else if (e === ".lua") {
|
|
8933
9545
|
for (const line of lines) {
|
|
8934
9546
|
const re = /\brequire\s*\(?\s*["']([^"']+)["']/g;
|
|
@@ -9022,9 +9634,9 @@ function extractImports(text, ext) {
|
|
|
9022
9634
|
return found;
|
|
9023
9635
|
}
|
|
9024
9636
|
function importsExtensionFor(filePath) {
|
|
9025
|
-
const
|
|
9026
|
-
if (
|
|
9027
|
-
return
|
|
9637
|
+
const ext = path4.extname(filePath);
|
|
9638
|
+
if (ext === "" || FILENAME_LANGUAGE.has(path4.basename(filePath).toLowerCase())) return basenameImportsExtension(detectLanguage(filePath)) ?? ext;
|
|
9639
|
+
return ext;
|
|
9028
9640
|
}
|
|
9029
9641
|
function runImports(opts) {
|
|
9030
9642
|
const multiFiles = parseMultiFileSpec(opts.file);
|
|
@@ -9037,7 +9649,7 @@ function runImports(opts) {
|
|
|
9037
9649
|
}
|
|
9038
9650
|
const imports = extractImports(text, importsExtensionFor(opts.file));
|
|
9039
9651
|
if (imports.length === 0) {
|
|
9040
|
-
emit(`No imports found in '${opts.file}'`);
|
|
9652
|
+
emit(`No imports found in '${displaySafeText(opts.file)}'`);
|
|
9041
9653
|
return 0;
|
|
9042
9654
|
}
|
|
9043
9655
|
const preFilterCount = imports.length;
|
|
@@ -9046,7 +9658,7 @@ function runImports(opts) {
|
|
|
9046
9658
|
const fullSourceBytes = sumFileSizes([diskPath]);
|
|
9047
9659
|
if (filteredImports.length === 0) {
|
|
9048
9660
|
if (opts.json === true) {
|
|
9049
|
-
const jsonText =
|
|
9661
|
+
const jsonText = displaySafeJson({ items: [], truncated: false, totalCount: 0 });
|
|
9050
9662
|
emit(jsonText);
|
|
9051
9663
|
recordReadStat("imports", fullSourceBytes, jsonText, opts.file);
|
|
9052
9664
|
return 0;
|
|
@@ -9058,7 +9670,7 @@ function runImports(opts) {
|
|
|
9058
9670
|
}
|
|
9059
9671
|
if (opts.json === true) {
|
|
9060
9672
|
const capped = guardJsonRows(filteredImports);
|
|
9061
|
-
const jsonText =
|
|
9673
|
+
const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount });
|
|
9062
9674
|
emit(jsonText);
|
|
9063
9675
|
recordReadStat("imports", fullSourceBytes, jsonText, opts.file);
|
|
9064
9676
|
return 0;
|
|
@@ -9110,7 +9722,7 @@ async function runSemantic(query, opts) {
|
|
|
9110
9722
|
if (opts.limit !== void 0 && opts.limit <= 0) {
|
|
9111
9723
|
const message = `--limit must be a positive number, got: ${opts.limit}`;
|
|
9112
9724
|
if (opts.json === true) {
|
|
9113
|
-
return { text:
|
|
9725
|
+
return { text: displaySafeJson({ error: message }), code: 1 };
|
|
9114
9726
|
}
|
|
9115
9727
|
return { text: message, code: 1 };
|
|
9116
9728
|
}
|
|
@@ -9119,32 +9731,39 @@ async function runSemantic(query, opts) {
|
|
|
9119
9731
|
if (!path4.isAbsolute(opts.projectRoot) || !fs4.existsSync(opts.projectRoot) || !fs4.statSync(opts.projectRoot).isDirectory()) {
|
|
9120
9732
|
const message = `token-goat: projectRoot must be an absolute, existing directory, got '${opts.projectRoot}'`;
|
|
9121
9733
|
if (opts.json === true) {
|
|
9122
|
-
return { text:
|
|
9734
|
+
return { text: displaySafeJson({ error: message }), code: 1 };
|
|
9123
9735
|
}
|
|
9124
9736
|
return { text: message, code: 1 };
|
|
9125
9737
|
}
|
|
9126
9738
|
}
|
|
9127
9739
|
const rootDir = opts.projectRoot ?? resolveProjectRoot({ project: process.cwd() });
|
|
9128
|
-
|
|
9740
|
+
const embeddingsEnabled = loadConfig().indexing?.embeddings_enabled ?? true;
|
|
9741
|
+
if (embeddingsEnabled && !isAvailable()) {
|
|
9129
9742
|
console.warn(
|
|
9130
9743
|
"Matching on meaning is off (onnxruntime-node is not installed); these results come from keyword search alone. Install it with: npm install -g onnxruntime-node (drop -g if token-goat is a project dependency)"
|
|
9131
9744
|
);
|
|
9745
|
+
} else if (!embeddingsEnabled) {
|
|
9746
|
+
console.warn(
|
|
9747
|
+
"Matching on meaning is off (indexing.embeddings_enabled / TOKEN_GOAT_EMBEDDINGS_ENABLED is disabled); these results come from keyword search alone."
|
|
9748
|
+
);
|
|
9132
9749
|
}
|
|
9133
9750
|
const overFetchForMerge = Math.min(MAX_OVER_FETCH, n * OVER_FETCH_FACTOR);
|
|
9134
9751
|
let rawHits = [];
|
|
9135
|
-
|
|
9136
|
-
|
|
9137
|
-
|
|
9138
|
-
|
|
9139
|
-
|
|
9140
|
-
|
|
9141
|
-
|
|
9142
|
-
|
|
9143
|
-
|
|
9144
|
-
|
|
9145
|
-
|
|
9146
|
-
|
|
9147
|
-
|
|
9752
|
+
if (embeddingsEnabled) {
|
|
9753
|
+
try {
|
|
9754
|
+
rawHits = await searchSemantic(
|
|
9755
|
+
getDb(globalDbPath()),
|
|
9756
|
+
query,
|
|
9757
|
+
overFetchForMerge,
|
|
9758
|
+
void 0,
|
|
9759
|
+
void 0,
|
|
9760
|
+
rootDir
|
|
9761
|
+
);
|
|
9762
|
+
} catch (e) {
|
|
9763
|
+
console.warn(
|
|
9764
|
+
`Matching on meaning is off (${extractErrorMessage(e)}); these results come from keyword search alone.`
|
|
9765
|
+
);
|
|
9766
|
+
}
|
|
9148
9767
|
}
|
|
9149
9768
|
if (rawHits.length === 0 && isAvailable()) {
|
|
9150
9769
|
try {
|
|
@@ -9164,7 +9783,7 @@ async function runSemantic(query, opts) {
|
|
|
9164
9783
|
const fused = /* @__PURE__ */ new Map();
|
|
9165
9784
|
mergedHits.forEach((h, denseRank) => {
|
|
9166
9785
|
const enclosing = resolveEnclosingSymbol(h.filePath, h.startLine);
|
|
9167
|
-
const key = enclosing !== null ? `${h.filePath}::${enclosing.name}` : `${h.filePath}::L${h.startLine}`;
|
|
9786
|
+
const key = enclosing !== null ? `${h.filePath}::${enclosing.name}@${enclosing.lineStart}` : `${h.filePath}::L${h.startLine}`;
|
|
9168
9787
|
fused.set(key, {
|
|
9169
9788
|
filePath: h.filePath,
|
|
9170
9789
|
startLine: h.startLine,
|
|
@@ -9177,7 +9796,7 @@ async function runSemantic(query, opts) {
|
|
|
9177
9796
|
});
|
|
9178
9797
|
});
|
|
9179
9798
|
ftsRows.forEach((s, ftsRank) => {
|
|
9180
|
-
const key = `${s.filePath}::${s.name}`;
|
|
9799
|
+
const key = `${s.filePath}::${s.name}@${s.lineStart}`;
|
|
9181
9800
|
const existing = fused.get(key);
|
|
9182
9801
|
if (existing !== void 0) {
|
|
9183
9802
|
existing.rrf += 1 / (RRF_K + ftsRank);
|
|
@@ -9210,6 +9829,7 @@ async function runSemantic(query, opts) {
|
|
|
9210
9829
|
const hadDense = mergedHits.length > 0;
|
|
9211
9830
|
const hadFts = ftsRows.length > 0;
|
|
9212
9831
|
const source = hadDense && hadFts ? "hybrid" : hadDense ? "embeddings" : "fts";
|
|
9832
|
+
warnIfFilesStale(hits.map((h) => h.filePath));
|
|
9213
9833
|
if (hits.length > 0) {
|
|
9214
9834
|
if (opts.json === true) {
|
|
9215
9835
|
const items = hits.map((h) => ({
|
|
@@ -9223,7 +9843,7 @@ async function runSemantic(query, opts) {
|
|
|
9223
9843
|
}));
|
|
9224
9844
|
const capped = guardJsonRows(items);
|
|
9225
9845
|
const limitTruncated = hits.length < eligibleCount;
|
|
9226
|
-
const text3 =
|
|
9846
|
+
const text3 = displaySafeJson({ source, ...capped, truncated: capped.truncated || limitTruncated, totalCount: eligibleCount, ...candidatesClipped ? { totalCountIsFloor: true } : {} });
|
|
9227
9847
|
recordReadStat("semantic_search", sumFileSizes(hits.map((h) => h.filePath)), text3, query);
|
|
9228
9848
|
return { text: text3, code: 0 };
|
|
9229
9849
|
}
|
|
@@ -9247,7 +9867,7 @@ ${previewLines(h.previewText, 3)}`;
|
|
|
9247
9867
|
const notice = grepFilteredToEmptyNotice(preFilterCount, opts.grep ?? "", "match", "matches");
|
|
9248
9868
|
if (opts.json === true) {
|
|
9249
9869
|
const payload = { source: "fts", items: [], truncated: false, totalCount: 0, grepFilteredToEmpty: true, hint: notice.trim() };
|
|
9250
|
-
return { text:
|
|
9870
|
+
return { text: displaySafeJson(payload), code: 0 };
|
|
9251
9871
|
}
|
|
9252
9872
|
return { text: `token-goat: ${notice.trim()}`, code: 0 };
|
|
9253
9873
|
}
|
|
@@ -9255,7 +9875,7 @@ ${previewLines(h.previewText, 3)}`;
|
|
|
9255
9875
|
const notice = `no non-test matches for '${query}' (${excludeTestsHiddenNote(suppressedTotal)})`;
|
|
9256
9876
|
if (opts.json === true) {
|
|
9257
9877
|
const payload = { source: "fts", items: [], truncated: false, totalCount: 0, excludeTestsFilteredToEmpty: true, hint: notice };
|
|
9258
|
-
return { text:
|
|
9878
|
+
return { text: displaySafeJson(payload), code: 0 };
|
|
9259
9879
|
}
|
|
9260
9880
|
return { text: `token-goat: ${notice}`, code: 0 };
|
|
9261
9881
|
}
|
|
@@ -9271,7 +9891,7 @@ ${previewLines(h.previewText, 3)}`;
|
|
|
9271
9891
|
cachedAt: entry.createdAt
|
|
9272
9892
|
}));
|
|
9273
9893
|
const capped = guardJsonRows(items);
|
|
9274
|
-
const text3 =
|
|
9894
|
+
const text3 = displaySafeJson({ source: "workspace-evidence", ...capped });
|
|
9275
9895
|
recordReadStat("semantic_search", evidenceFullBytes, text3, query);
|
|
9276
9896
|
return { text: text3, code: 0 };
|
|
9277
9897
|
}
|
|
@@ -9287,7 +9907,7 @@ ${previewLines(entry.text, 3)}`).join("\n\n"),
|
|
|
9287
9907
|
const indexEmpty = isIndexEmptyForProject(globalDbPath(), rootDir);
|
|
9288
9908
|
if (opts.json === true) {
|
|
9289
9909
|
const payload = indexEmpty ? { source: "fts", items: [], truncated: false, totalCount: 0, indexEmpty: true, hint: emptyIndexMessage(rootDir) } : { source: "fts", items: [], truncated: false, totalCount: 0 };
|
|
9290
|
-
const text2 =
|
|
9910
|
+
const text2 = displaySafeJson(payload);
|
|
9291
9911
|
return { text: text2, code: 1 };
|
|
9292
9912
|
}
|
|
9293
9913
|
const text = indexEmpty ? `token-goat: no matches for '${query}'
|
|
@@ -9313,7 +9933,7 @@ function runNoteGet(opts) {
|
|
|
9313
9933
|
createdAt: note.createdAt,
|
|
9314
9934
|
updatedAt: note.updatedAt
|
|
9315
9935
|
};
|
|
9316
|
-
const text2 =
|
|
9936
|
+
const text2 = displaySafeJson(payload);
|
|
9317
9937
|
recordStat("note_read");
|
|
9318
9938
|
return { text: text2, code: 0 };
|
|
9319
9939
|
}
|
|
@@ -9335,7 +9955,7 @@ function runNoteList(opts = {}) {
|
|
|
9335
9955
|
updatedAt: note.updatedAt
|
|
9336
9956
|
}));
|
|
9337
9957
|
recordStat("note_list");
|
|
9338
|
-
return { text:
|
|
9958
|
+
return { text: displaySafeJson(items), code: 0 };
|
|
9339
9959
|
}
|
|
9340
9960
|
recordStat("note_list");
|
|
9341
9961
|
if (filtered.length === 0) {
|
|
@@ -9670,7 +10290,7 @@ function renderModules(result, top) {
|
|
|
9670
10290
|
|
|
9671
10291
|
// src/graph_commands.ts
|
|
9672
10292
|
var DEFAULT_REF_QUERY_LIMIT = 500;
|
|
9673
|
-
var ALL_SYMBOLS_IN_FILE_LIMIT =
|
|
10293
|
+
var ALL_SYMBOLS_IN_FILE_LIMIT = -1;
|
|
9674
10294
|
var UNBOUNDED_REF_LIMIT = -1;
|
|
9675
10295
|
function emit2(text) {
|
|
9676
10296
|
const payload = colorStdout() ? text : stripAnsi(text);
|
|
@@ -9818,7 +10438,7 @@ function runCallers(opts) {
|
|
|
9818
10438
|
if (entries.length === 0) {
|
|
9819
10439
|
if (matchesGrep !== void 0 && preGrepCount > 0) {
|
|
9820
10440
|
if (opts.json === true) {
|
|
9821
|
-
emit2(
|
|
10441
|
+
emit2(displaySafeJson({ items: [], truncated: false, totalCount: 0, hiddenByGrep: preGrepCount }));
|
|
9822
10442
|
return 0;
|
|
9823
10443
|
}
|
|
9824
10444
|
emit2(grepFilteredToEmptyNotice(preGrepCount, opts.grep ?? "", "caller", "callers"));
|
|
@@ -9826,7 +10446,7 @@ function runCallers(opts) {
|
|
|
9826
10446
|
}
|
|
9827
10447
|
if (opts.excludeTests === true && suppressed > 0) {
|
|
9828
10448
|
if (opts.json === true) {
|
|
9829
|
-
emit2(
|
|
10449
|
+
emit2(displaySafeJson({ items: [], truncated: false, totalCount: 0, hiddenByExcludeTests: suppressed }));
|
|
9830
10450
|
return 1;
|
|
9831
10451
|
}
|
|
9832
10452
|
emitErr2(`No non-test references found for '${opts.symbol}' (${excludeTestsHiddenNote(suppressed)})`);
|
|
@@ -9841,7 +10461,7 @@ function runCallers(opts) {
|
|
|
9841
10461
|
const defPaths = fileHint !== void 0 ? [fileHint] : defRows.map((r) => r.filePath);
|
|
9842
10462
|
const firstDefPath = defPaths[0];
|
|
9843
10463
|
if (firstDefPath !== void 0 && defPaths.every((fp) => !isRefIndexedFile(fp))) {
|
|
9844
|
-
emitErr2(refBlindLanguageNotice(name,
|
|
10464
|
+
emitErr2(refBlindLanguageNotice(name, detectLanguageOfFile(firstDefPath), toDisplayPath(rootDir, firstDefPath)));
|
|
9845
10465
|
return 1;
|
|
9846
10466
|
}
|
|
9847
10467
|
const kindRows = fileHint !== void 0 ? querySymbols({ name, filePath: fileHint, limit: REF_BLIND_DEF_PROBE_LIMIT }) : defRows;
|
|
@@ -9865,7 +10485,7 @@ function runCallers(opts) {
|
|
|
9865
10485
|
const capped = guardJsonRows(rows);
|
|
9866
10486
|
const limitTruncated = entries.length < filtered.length || sqlTruncated;
|
|
9867
10487
|
const hiddenByGrep = preGrepCount - filtered.length;
|
|
9868
|
-
emit2(
|
|
10488
|
+
emit2(displaySafeJson({ items: capped.items, truncated: capped.truncated || limitTruncated, totalCount: filtered.length, ...hiddenByGrep > 0 ? { hiddenByGrep } : {}, ...opts.excludeTests === true && suppressed > 0 ? { hiddenByExcludeTests: suppressed } : {} }));
|
|
9869
10489
|
return 0;
|
|
9870
10490
|
}
|
|
9871
10491
|
if (opts.excludeTests === true && suppressed > 0) {
|
|
@@ -9933,8 +10553,8 @@ function runCallChain(opts) {
|
|
|
9933
10553
|
const hiddenByExcludeTests = noCallers && opts.excludeTests === true ? suppressedCount : 0;
|
|
9934
10554
|
const refBlindKinds = noCallers ? refBlindRootKinds().blindKinds : [];
|
|
9935
10555
|
const blindRootPath = noCallers ? refBlindRootPath() : void 0;
|
|
9936
|
-
const refBlindLanguage = blindRootPath !== void 0 ? { language:
|
|
9937
|
-
emit2(
|
|
10556
|
+
const refBlindLanguage = blindRootPath !== void 0 ? { language: detectLanguageOfFile(blindRootPath), definedIn: toDisplayPath(rootDir, blindRootPath) } : void 0;
|
|
10557
|
+
emit2(displaySafeJson({ chains: filteredChains, ...hiddenByGrep > 0 ? { hiddenByGrep } : {}, ...hiddenByExcludeTests > 0 ? { hiddenByExcludeTests } : {}, ...refBlindKinds.length > 0 ? { refBlindKinds } : {}, ...refBlindLanguage !== void 0 ? { refBlindLanguage } : {} }));
|
|
9938
10558
|
return 0;
|
|
9939
10559
|
}
|
|
9940
10560
|
if (noCallers) {
|
|
@@ -9944,7 +10564,7 @@ function runCallChain(opts) {
|
|
|
9944
10564
|
}
|
|
9945
10565
|
const blindRoot = refBlindRootPath();
|
|
9946
10566
|
if (blindRoot !== void 0) {
|
|
9947
|
-
emitErr2(refBlindLanguageNotice(name,
|
|
10567
|
+
emitErr2(refBlindLanguageNotice(name, detectLanguageOfFile(blindRoot), toDisplayPath(rootDir, blindRoot)));
|
|
9948
10568
|
emit2(`${name} (no callers recorded)`);
|
|
9949
10569
|
return 0;
|
|
9950
10570
|
}
|
|
@@ -10035,7 +10655,7 @@ function runImpact(opts) {
|
|
|
10035
10655
|
if (matchesGrep !== void 0 && sorted.length === 0 && allSorted.length > 0) {
|
|
10036
10656
|
if (opts.json === true) {
|
|
10037
10657
|
emitErr2(grepFilteredToEmptyNotice(allSorted.length, opts.grep, "impacted symbol", "impacted symbols"));
|
|
10038
|
-
emit2(
|
|
10658
|
+
emit2(displaySafeJson([]));
|
|
10039
10659
|
return 0;
|
|
10040
10660
|
}
|
|
10041
10661
|
emit2(grepFilteredToEmptyNotice(allSorted.length, opts.grep, "impacted symbol", "impacted symbols"));
|
|
@@ -10044,7 +10664,7 @@ function runImpact(opts) {
|
|
|
10044
10664
|
if (sorted.length === 0) {
|
|
10045
10665
|
if (opts.excludeTests === true && suppressedCount > 0) {
|
|
10046
10666
|
if (opts.json === true) {
|
|
10047
|
-
emit2(
|
|
10667
|
+
emit2(displaySafeJson([]));
|
|
10048
10668
|
return 1;
|
|
10049
10669
|
}
|
|
10050
10670
|
emitErr2(`No non-test impact found for '${opts.symbol}' (${excludeTestsHiddenNote(suppressedCount)})`);
|
|
@@ -10058,7 +10678,7 @@ function runImpact(opts) {
|
|
|
10058
10678
|
const defPaths = fileHint !== void 0 ? [fileHint] : defRows.map((r) => r.filePath);
|
|
10059
10679
|
const firstDefPath = defPaths[0];
|
|
10060
10680
|
if (firstDefPath !== void 0 && defPaths.every((fp) => !isRefIndexedFile(fp))) {
|
|
10061
|
-
emitErr2(refBlindLanguageNotice(rootName,
|
|
10681
|
+
emitErr2(refBlindLanguageNotice(rootName, detectLanguageOfFile(firstDefPath), toDisplayPath(rootDir, firstDefPath)));
|
|
10062
10682
|
return 1;
|
|
10063
10683
|
}
|
|
10064
10684
|
const kindRows = fileHint !== void 0 ? querySymbols({ name: rootName, filePath: fileHint, limit: REF_BLIND_DEF_PROBE_LIMIT }) : defRows;
|
|
@@ -10072,7 +10692,7 @@ function runImpact(opts) {
|
|
|
10072
10692
|
return 1;
|
|
10073
10693
|
}
|
|
10074
10694
|
if (opts.json === true) {
|
|
10075
|
-
emit2(
|
|
10695
|
+
emit2(displaySafeJson(sorted.map(([symbol, h]) => ({ symbol, hops: h }))));
|
|
10076
10696
|
return 0;
|
|
10077
10697
|
}
|
|
10078
10698
|
const MODULE_SCOPE_PREFIX = "(module scope) ";
|
|
@@ -10229,7 +10849,7 @@ function runDead(opts) {
|
|
|
10229
10849
|
}));
|
|
10230
10850
|
const topTruncated = sliced.length < grepped.length;
|
|
10231
10851
|
const hiddenByGrep = preGrepCount - grepped.length;
|
|
10232
|
-
emit2(
|
|
10852
|
+
emit2(displaySafeJson({ items: capped.items, truncated: capped.truncated || topTruncated, totalCount: grepped.length, ...hiddenByGrep > 0 ? { hiddenByGrep } : {}, ...opts.excludeTests === true && suppressed > 0 ? { hiddenByExcludeTests: suppressed } : {}, ...blindKinds.length > 0 ? { excludedKinds: blindKinds, excludedKindsReason: REF_BLIND_KIND_REASON } : {}, ...refBlindByLanguage > 0 ? { unassessableByLanguage: refBlindByLanguage } : {} }));
|
|
10233
10853
|
return 0;
|
|
10234
10854
|
}
|
|
10235
10855
|
if (sliced.length === 0) {
|
|
@@ -10249,7 +10869,7 @@ function runDead(opts) {
|
|
|
10249
10869
|
emit2(`${countNoun(sliced.length, "dead symbol")} (${excludeTestsHiddenNote(suppressed)})`);
|
|
10250
10870
|
}
|
|
10251
10871
|
for (const r of sliced) {
|
|
10252
|
-
emit2(`${r.name} ${toDisplayPath(rootDir, r.file)}:${r.line}`);
|
|
10872
|
+
emit2(`${displaySafeText(r.name)} ${displaySafeText(toDisplayPath(rootDir, r.file))}:${r.line}`);
|
|
10253
10873
|
}
|
|
10254
10874
|
return 0;
|
|
10255
10875
|
}
|
|
@@ -10326,7 +10946,7 @@ function runDeps(opts) {
|
|
|
10326
10946
|
const filteredExternal = matchesGrep !== void 0 ? external.filter((e) => matchesGrep(e)) : external;
|
|
10327
10947
|
if (opts.json === true) {
|
|
10328
10948
|
const hiddenByGrep = preFilterCount - (filteredInternal.length + filteredExternal.length);
|
|
10329
|
-
emit2(
|
|
10949
|
+
emit2(displaySafeJson({ file: toDisplayPath(rootDir, normalizePath(opts.file)), internal: filteredInternal, external: filteredExternal, ...hiddenByGrep > 0 ? { hiddenByGrep } : {} }));
|
|
10330
10950
|
return 0;
|
|
10331
10951
|
}
|
|
10332
10952
|
if (matchesGrep !== void 0 && preFilterCount > 0 && filteredInternal.length === 0 && filteredExternal.length === 0) {
|
|
@@ -10436,7 +11056,7 @@ function refBlindKindVerdict(rows) {
|
|
|
10436
11056
|
var CORE_SYMBOL_KINDS = [
|
|
10437
11057
|
.../* @__PURE__ */ new Set([...GENERIC_SYMBOL_KINDS, ...TYPE_KINDS, ...OTHER_ADAPTER_SYMBOL_KINDS])
|
|
10438
11058
|
];
|
|
10439
|
-
var TYPES_SCAN_LIMIT =
|
|
11059
|
+
var TYPES_SCAN_LIMIT = -1;
|
|
10440
11060
|
function runTypes(opts) {
|
|
10441
11061
|
if (opts.limit !== void 0 && opts.limit <= 0) {
|
|
10442
11062
|
emitErr2(`--limit must be a positive number, got: ${opts.limit}`);
|
|
@@ -10482,7 +11102,7 @@ function runTypes(opts) {
|
|
|
10482
11102
|
const ctx = opts.file !== void 0 ? ` in '${opts.file}'` : "";
|
|
10483
11103
|
if (excludeTests && suppressed > 0) {
|
|
10484
11104
|
if (opts.json === true) {
|
|
10485
|
-
emit2(
|
|
11105
|
+
emit2(displaySafeJson({ items: [], truncated: false, totalCount: 0, hiddenByExcludeTests: suppressed }));
|
|
10486
11106
|
return 0;
|
|
10487
11107
|
}
|
|
10488
11108
|
emit2(`No non-test type declarations found${ctx} (${excludeTestsHiddenNote(suppressed)})`);
|
|
@@ -10506,7 +11126,7 @@ function runTypes(opts) {
|
|
|
10506
11126
|
const cappedOut = eligibleCount - filtered.length;
|
|
10507
11127
|
if (filtered.length === 0) {
|
|
10508
11128
|
if (opts.json === true) {
|
|
10509
|
-
emit2(
|
|
11129
|
+
emit2(displaySafeJson({ items: [], truncated: false, totalCount: 0, hiddenByGrep: preFilterCount }));
|
|
10510
11130
|
return 0;
|
|
10511
11131
|
}
|
|
10512
11132
|
emit2(grepFilteredToEmptyNotice(preFilterCount, opts.grep ?? "", "type declaration", "type declarations"));
|
|
@@ -10515,14 +11135,14 @@ function runTypes(opts) {
|
|
|
10515
11135
|
if (opts.json === true) {
|
|
10516
11136
|
const capped = guardJsonRows(filtered.map((r) => ({ ...r, filePath: toDisplayPath(rootDir, r.filePath) })));
|
|
10517
11137
|
const hiddenByGrep = preFilterCount - eligibleCount;
|
|
10518
|
-
emit2(
|
|
11138
|
+
emit2(displaySafeJson({ items: capped.items, truncated: capped.truncated || cappedOut > 0, totalCount: eligibleCount, ...hiddenByGrep > 0 ? { hiddenByGrep } : {}, ...excludeTests && suppressed > 0 ? { hiddenByExcludeTests: suppressed } : {} }));
|
|
10519
11139
|
return 0;
|
|
10520
11140
|
}
|
|
10521
11141
|
if (excludeTests && suppressed > 0) {
|
|
10522
11142
|
emit2(`${countNoun(filtered.length, "type declaration")} (${excludeTestsHiddenNote(suppressed)})`);
|
|
10523
11143
|
}
|
|
10524
11144
|
for (const r of filtered) {
|
|
10525
|
-
emit2(`${r.name} ${r.kind} ${toDisplayPath(rootDir, r.filePath)}:${r.lineStart}`);
|
|
11145
|
+
emit2(`${displaySafeText(r.name)} ${displaySafeText(r.kind)} ${displaySafeText(toDisplayPath(rootDir, r.filePath))}:${r.lineStart}`);
|
|
10526
11146
|
}
|
|
10527
11147
|
if (cappedOut > 0) {
|
|
10528
11148
|
emitErr2(`Showing ${filtered.length} of ${eligibleCount} type declarations (--limit is per kind; raise it to see the rest).`);
|
|
@@ -10560,7 +11180,7 @@ function runScope(opts) {
|
|
|
10560
11180
|
return 1;
|
|
10561
11181
|
}
|
|
10562
11182
|
emitErr2(
|
|
10563
|
-
`No indexed symbols in '${file}' \u2014 the file exists but nothing is indexed for it, so every line looks empty`
|
|
11183
|
+
symbolExtractorGap(file, filePath) ?? `No indexed symbols in '${file}' \u2014 the file exists but nothing is indexed for it, so every line looks empty`
|
|
10564
11184
|
);
|
|
10565
11185
|
return 1;
|
|
10566
11186
|
}
|
|
@@ -10570,16 +11190,14 @@ function runScope(opts) {
|
|
|
10570
11190
|
const scopeDisplayRoot = getDisplayRoot();
|
|
10571
11191
|
if (opts.json === true) {
|
|
10572
11192
|
emit2(
|
|
10573
|
-
|
|
10574
|
-
enclosing.map((s) => ({ ...s, filePath: toDisplayPath(scopeDisplayRoot, s.filePath) }))
|
|
10575
|
-
null,
|
|
10576
|
-
2
|
|
11193
|
+
displaySafeJson(
|
|
11194
|
+
enclosing.map((s) => ({ ...s, filePath: toDisplayPath(scopeDisplayRoot, s.filePath) }))
|
|
10577
11195
|
)
|
|
10578
11196
|
);
|
|
10579
11197
|
return 0;
|
|
10580
11198
|
}
|
|
10581
11199
|
for (const s of enclosing) {
|
|
10582
|
-
emit2(`${s.name} ${s.kind} ${toDisplayPath(scopeDisplayRoot, s.filePath)}:${s.lineStart}-${s.lineEnd}`);
|
|
11200
|
+
emit2(`${displaySafeText(s.name)} ${displaySafeText(s.kind)} ${displaySafeText(toDisplayPath(scopeDisplayRoot, s.filePath))}:${s.lineStart}-${s.lineEnd}`);
|
|
10583
11201
|
}
|
|
10584
11202
|
return 0;
|
|
10585
11203
|
}
|
|
@@ -10709,10 +11327,10 @@ function runSimilar(opts) {
|
|
|
10709
11327
|
emitErr2(`Showing top ${results.length} of ${matches.length} similar symbols (raise --top to see the rest).`);
|
|
10710
11328
|
}
|
|
10711
11329
|
if (opts.json === true) {
|
|
10712
|
-
emit2(
|
|
11330
|
+
emit2(displaySafeJson(results.map((h) => ({ name: h.name, kind: h.kind, file: h.filePath, line: h.lineStart }))));
|
|
10713
11331
|
return 0;
|
|
10714
11332
|
}
|
|
10715
|
-
for (const h of results) emit2(`${h.name} ${h.kind} ${toDisplayPath(rootDir, h.filePath)}:${h.lineStart}`);
|
|
11333
|
+
for (const h of results) emit2(`${displaySafeText(h.name)} ${displaySafeText(h.kind)} ${displaySafeText(toDisplayPath(rootDir, h.filePath))}:${h.lineStart}`);
|
|
10716
11334
|
return 0;
|
|
10717
11335
|
}
|
|
10718
11336
|
function runContextFor(opts) {
|
|
@@ -10748,10 +11366,10 @@ function runContextFor(opts) {
|
|
|
10748
11366
|
if (moreBeyondTop) notices.push(`More matches exist beyond --top ${top} (raise it to see them).`);
|
|
10749
11367
|
for (const n of notices) emitErr2(n);
|
|
10750
11368
|
if (opts.json === true) {
|
|
10751
|
-
emit2(
|
|
11369
|
+
emit2(displaySafeJson(entries));
|
|
10752
11370
|
return 0;
|
|
10753
11371
|
}
|
|
10754
|
-
for (const e of entries) emit2(`token-goat read "${toDisplayPath(rootDir, e.file)}::${e.symbol}@${e.line}"`);
|
|
11372
|
+
for (const e of entries) emit2(`token-goat read "${displaySafeText(toDisplayPath(rootDir, e.file))}::${displaySafeText(e.symbol)}@${e.line}"`);
|
|
10755
11373
|
return 0;
|
|
10756
11374
|
}
|
|
10757
11375
|
function runTestFor(opts) {
|
|
@@ -10783,11 +11401,11 @@ function runTestFor(opts) {
|
|
|
10783
11401
|
}
|
|
10784
11402
|
if (opts.json === true) {
|
|
10785
11403
|
const capped = guardJsonRows(results.map((r) => ({ ...r, testFile: toDisplayPath(rootDir, r.testFile) })));
|
|
10786
|
-
emit2(
|
|
11404
|
+
emit2(displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }));
|
|
10787
11405
|
return 0;
|
|
10788
11406
|
}
|
|
10789
11407
|
if (results.length === 0) {
|
|
10790
|
-
emit2(`No test files found referencing symbols in '${opts.file}'`);
|
|
11408
|
+
emit2(`No test files found referencing symbols in '${displaySafeText(opts.file)}'`);
|
|
10791
11409
|
return 0;
|
|
10792
11410
|
}
|
|
10793
11411
|
for (const r of results) {
|
|
@@ -10819,7 +11437,7 @@ function runCoverageGaps(opts) {
|
|
|
10819
11437
|
emitErr2(`Showing top ${sliced.length} of ${gaps.length} coverage gaps (raise --top to see the rest).`);
|
|
10820
11438
|
}
|
|
10821
11439
|
if (opts.json === true) {
|
|
10822
|
-
emit2(
|
|
11440
|
+
emit2(displaySafeJson(sliced));
|
|
10823
11441
|
return 0;
|
|
10824
11442
|
}
|
|
10825
11443
|
if (sliced.length === 0) {
|
|
@@ -10827,7 +11445,7 @@ function runCoverageGaps(opts) {
|
|
|
10827
11445
|
if (isIndexEmptyForProject(globalDbPath(), rootDir)) emit2(emptyIndexMessage(rootDir));
|
|
10828
11446
|
return 0;
|
|
10829
11447
|
}
|
|
10830
|
-
for (const g of sliced) emit2(`${g.name} ${g.kind} ${toDisplayPath(rootDir, g.file)}:${g.line}`);
|
|
11448
|
+
for (const g of sliced) emit2(`${displaySafeText(g.name)} ${displaySafeText(g.kind)} ${displaySafeText(toDisplayPath(rootDir, g.file))}:${g.line}`);
|
|
10831
11449
|
return 0;
|
|
10832
11450
|
}
|
|
10833
11451
|
function runArch(opts) {
|
|
@@ -10852,13 +11470,13 @@ function runArch(opts) {
|
|
|
10852
11470
|
const moduleResult = opts.modules === true ? detectModules({ files, graph, importedBy, resolve: resolve5 }, cwd, top) : null;
|
|
10853
11471
|
if (opts.json === true) {
|
|
10854
11472
|
const modulePayload = moduleResult === null ? {} : { modules: moduleResult.modules, modulesTotal: moduleResult.modulesTotal, modulesTruncated: moduleResult.modules.length < moduleResult.modulesTotal, modularity: moduleResult.modularity, isolatedCount: moduleResult.isolatedCount, crossImports: moduleResult.crossImports, crossImportsTotal: moduleResult.crossImportsTotal, crossImportsTruncated: moduleResult.crossImports.length < moduleResult.crossImportsTotal, noImportEdges: moduleResult.noEdges };
|
|
10855
|
-
emit2(
|
|
11473
|
+
emit2(displaySafeJson({ hubs, hubsTotal, hubsTruncated: hubs.length < hubsTotal, entryPoints, entryPointsTotal, entryPointsTruncated: entryPoints.length < entryPointsTotal, cycles, ...cyclesTruncated ? { cyclesTruncated: true } : {}, ...modulePayload }));
|
|
10856
11474
|
return 0;
|
|
10857
11475
|
}
|
|
10858
11476
|
emit2(hubs.length < hubsTotal ? `hubs (top ${hubs.length} of ${hubsTotal} most-imported):` : `hubs (${hubsTotal} most-imported):`);
|
|
10859
|
-
for (const h of hubs) emit2(` ${h.importedBy} importers ${toDisplayPath(getDisplayRoot(opts.cwd), h.file)}`);
|
|
11477
|
+
for (const h of hubs) emit2(` ${h.importedBy} importers ${displaySafeText(toDisplayPath(getDisplayRoot(opts.cwd), h.file))}`);
|
|
10860
11478
|
emit2(entryPoints.length < entryPointsTotal ? `entry points (imported by nobody, top ${entryPoints.length} of ${entryPointsTotal}):` : `entry points (imported by nobody, ${entryPointsTotal} found):`);
|
|
10861
|
-
for (const e of entryPoints) emit2(` ${toDisplayPath(getDisplayRoot(opts.cwd), e.file)}`);
|
|
11479
|
+
for (const e of entryPoints) emit2(` ${displaySafeText(toDisplayPath(getDisplayRoot(opts.cwd), e.file))}`);
|
|
10862
11480
|
emit2(cyclesTruncated ? `cycles (first ${cycles.length}, truncated at the ${MAX_CYCLES}-cycle enumeration limit: more cycles exist):` : `cycles (${cycles.length} found):`);
|
|
10863
11481
|
for (const c of cycles) emit2(` ${c.map((f) => toDisplayPath(getDisplayRoot(opts.cwd), f)).join(" -> ")}`);
|
|
10864
11482
|
if (moduleResult !== null) for (const line of renderModules(moduleResult, top)) emit2(line);
|
|
@@ -10867,7 +11485,7 @@ function runArch(opts) {
|
|
|
10867
11485
|
function runBlame(opts) {
|
|
10868
11486
|
const sepIdx = opts.spec.lastIndexOf("::");
|
|
10869
11487
|
if (sepIdx < 0) {
|
|
10870
|
-
emitErr2(`Invalid spec - expected "file::symbol", got: ${opts.spec}`);
|
|
11488
|
+
emitErr2(`Invalid spec - expected "file::symbol", got: ${displaySafeText(opts.spec)}`);
|
|
10871
11489
|
return 1;
|
|
10872
11490
|
}
|
|
10873
11491
|
const cwd = opts.cwd ?? process.cwd();
|
|
@@ -10880,7 +11498,7 @@ function runBlame(opts) {
|
|
|
10880
11498
|
try {
|
|
10881
11499
|
const result = runGit(["blame", "-L", `${start},${end}`, "--", filePath], { cwd });
|
|
10882
11500
|
if (result.exitCode !== 0) {
|
|
10883
|
-
emitErr2(`git blame failed: ${result.stderr}`);
|
|
11501
|
+
emitErr2(`git blame failed: ${displaySafeText(result.stderr)}`);
|
|
10884
11502
|
return 1;
|
|
10885
11503
|
}
|
|
10886
11504
|
raw = result.stdout;
|
|
@@ -10894,11 +11512,11 @@ function runBlame(opts) {
|
|
|
10894
11512
|
if (!m) return { raw: l };
|
|
10895
11513
|
return { commit: m[2], boundary: m[1] === "^", author: (m[3] ?? "").trim(), date: (m[4] ?? "").trim(), line: Number.parseInt(m[5] ?? "0", 10), content: m[6] };
|
|
10896
11514
|
});
|
|
10897
|
-
emit2(
|
|
11515
|
+
emit2(displaySafeJson({ symbol: sym.name, file: filePath, lines }));
|
|
10898
11516
|
return 0;
|
|
10899
11517
|
}
|
|
10900
|
-
emit2(`${sym.name} ${toDisplayPath(getDisplayRoot(opts.cwd), filePath)}:${start}-${end}`);
|
|
10901
|
-
emit2(raw.trim());
|
|
11518
|
+
emit2(`${displaySafeText(sym.name)} ${displaySafeText(toDisplayPath(getDisplayRoot(opts.cwd), filePath))}:${start}-${end}`);
|
|
11519
|
+
emit2(fenceUntrusted(raw.trim(), UNTRUSTED_FILE_TAG));
|
|
10902
11520
|
return 0;
|
|
10903
11521
|
}
|
|
10904
11522
|
function runAsk(opts) {
|
|
@@ -10914,17 +11532,18 @@ function runAsk(opts) {
|
|
|
10914
11532
|
if (moreBeyondTop) {
|
|
10915
11533
|
emitErr2(`Answer is grounded in the top ${countNoun(top, "match", "matches")}; more matched (raise --top to widen the evidence).`);
|
|
10916
11534
|
}
|
|
11535
|
+
warnIfFilesStale(hits.map((h) => h.filePath));
|
|
10917
11536
|
const BACKEND_ENV = "TOKEN_GOAT_ASK_BACKEND";
|
|
10918
11537
|
const backendLabel = process.env[BACKEND_ENV] ?? "";
|
|
10919
11538
|
const entries = hits.map((h) => ({ file: h.filePath, symbol: h.name, kind: h.kind, line: h.lineStart, readCmd: `token-goat read "${h.filePath}::${h.name}@${h.lineStart}"` }));
|
|
10920
11539
|
const degrade = (reason, extraNote) => {
|
|
10921
11540
|
if (opts.json === true) {
|
|
10922
|
-
emit2(
|
|
11541
|
+
emit2(displaySafeJson({ degraded: true, note: reason, ...extraNote !== void 0 ? { hint: extraNote } : {}, context: entries }));
|
|
10923
11542
|
return 0;
|
|
10924
11543
|
}
|
|
10925
11544
|
emit2(`[degraded mode - ${reason}]`);
|
|
10926
11545
|
if (extraNote !== void 0) emit2(extraNote);
|
|
10927
|
-
for (const e of entries) emit2(`token-goat read "${toDisplayPath(rootDir, e.file)}::${e.symbol}@${e.line}"`);
|
|
11546
|
+
for (const e of entries) emit2(`token-goat read "${displaySafeText(toDisplayPath(rootDir, e.file))}::${displaySafeText(e.symbol)}@${e.line}"`);
|
|
10928
11547
|
return 0;
|
|
10929
11548
|
};
|
|
10930
11549
|
if (!backendLabel) return degrade(`set ${BACKEND_ENV}=claude|codex for LLM synthesis`);
|
|
@@ -10971,7 +11590,7 @@ ANSWER:`;
|
|
|
10971
11590
|
}
|
|
10972
11591
|
if (answer) {
|
|
10973
11592
|
if (opts.json === true) {
|
|
10974
|
-
emit2(
|
|
11593
|
+
emit2(displaySafeJson({ answer, context: entries }));
|
|
10975
11594
|
} else {
|
|
10976
11595
|
emit2(answer);
|
|
10977
11596
|
}
|
|
@@ -11113,9 +11732,8 @@ function resolveHandoff(name, opts = {}) {
|
|
|
11113
11732
|
}
|
|
11114
11733
|
|
|
11115
11734
|
export {
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
listSections,
|
|
11735
|
+
isAvailable2 as isAvailable,
|
|
11736
|
+
loadError,
|
|
11119
11737
|
buildImportGraph,
|
|
11120
11738
|
ALL_SYMBOLS_IN_FILE_LIMIT,
|
|
11121
11739
|
enclosingSymbol,
|
|
@@ -11139,8 +11757,6 @@ export {
|
|
|
11139
11757
|
symbolNamesInFile,
|
|
11140
11758
|
computeFileFingerprint,
|
|
11141
11759
|
upsertNote,
|
|
11142
|
-
isAvailable2 as isAvailable,
|
|
11143
|
-
loadError,
|
|
11144
11760
|
AMBIGUOUS_HEADING_LIMIT,
|
|
11145
11761
|
ConfinementIdentityError,
|
|
11146
11762
|
ABSENT_PIN,
|
|
@@ -11149,6 +11765,7 @@ export {
|
|
|
11149
11765
|
withPinnedReads,
|
|
11150
11766
|
resolveBody,
|
|
11151
11767
|
healStaleIndex,
|
|
11768
|
+
warnIfFilesStale,
|
|
11152
11769
|
findSpecSeparator,
|
|
11153
11770
|
rankSimilarNames,
|
|
11154
11771
|
filterSimilarHeadings,
|
|
@@ -11169,6 +11786,9 @@ export {
|
|
|
11169
11786
|
runYamlQuery,
|
|
11170
11787
|
runXmlOutline,
|
|
11171
11788
|
runXmlQuery,
|
|
11789
|
+
runHtmlOutline,
|
|
11790
|
+
runHtmlQuery,
|
|
11791
|
+
runHtmlLint,
|
|
11172
11792
|
runOpenApiOutline,
|
|
11173
11793
|
runOpenApiOp,
|
|
11174
11794
|
runZipList,
|