truecourse 0.7.0-next.4 → 0.7.0-next.5
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 +15 -3
- package/cli.mjs +1393 -682
- package/package.json +1 -1
- package/public/assets/{index-rfhWLMD4.js → index-CI8n7IHP.js} +231 -226
- package/public/index.html +1 -1
- package/roslyn-host/Humanizer.dll +0 -0
- package/roslyn-host/Microsoft.Bcl.AsyncInterfaces.dll +0 -0
- package/roslyn-host/Microsoft.Build.Locator.dll +0 -0
- package/roslyn-host/Microsoft.CodeAnalysis.CSharp.Workspaces.dll +0 -0
- package/roslyn-host/Microsoft.CodeAnalysis.CSharp.dll +0 -0
- package/roslyn-host/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.dll +0 -0
- package/roslyn-host/Microsoft.CodeAnalysis.Workspaces.MSBuild.dll +0 -0
- package/roslyn-host/Microsoft.CodeAnalysis.Workspaces.dll +0 -0
- package/roslyn-host/Microsoft.CodeAnalysis.dll +0 -0
- package/roslyn-host/Microsoft.Extensions.DependencyInjection.Abstractions.dll +0 -0
- package/roslyn-host/Microsoft.Extensions.Logging.Abstractions.dll +0 -0
- package/roslyn-host/Newtonsoft.Json.dll +0 -0
- package/roslyn-host/System.Composition.AttributedModel.dll +0 -0
- package/roslyn-host/System.Composition.Convention.dll +0 -0
- package/roslyn-host/System.Composition.Hosting.dll +0 -0
- package/roslyn-host/System.Composition.Runtime.dll +0 -0
- package/roslyn-host/System.Composition.TypedParts.dll +0 -0
- package/roslyn-host/System.IO.Pipelines.dll +0 -0
- package/roslyn-host/cs/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/cs/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/cs/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/cs/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/cs/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/roslyn-host/csharp-roslyn-host.deps.json +545 -0
- package/roslyn-host/csharp-roslyn-host.dll +0 -0
- package/roslyn-host/csharp-roslyn-host.dll.config +623 -0
- package/roslyn-host/csharp-roslyn-host.pdb +0 -0
- package/roslyn-host/csharp-roslyn-host.runtimeconfig.json +16 -0
- package/roslyn-host/de/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/de/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/de/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/de/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/de/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/roslyn-host/es/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/es/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/es/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/es/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/es/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/roslyn-host/fr/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/fr/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/fr/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/fr/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/fr/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/roslyn-host/it/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/it/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/it/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/it/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/it/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/roslyn-host/ja/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/ja/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/ja/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/ja/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/ja/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/roslyn-host/ko/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/ko/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/ko/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/ko/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/ko/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/roslyn-host/pl/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/pl/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/pl/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/pl/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/pl/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/roslyn-host/pt-BR/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/pt-BR/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/pt-BR/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/pt-BR/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/pt-BR/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/roslyn-host/ru/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/ru/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/ru/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/ru/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/ru/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/roslyn-host/tr/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/tr/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/tr/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/tr/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/tr/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/roslyn-host/zh-Hans/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/zh-Hans/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/zh-Hans/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/zh-Hans/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/zh-Hans/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/roslyn-host/zh-Hant/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll +0 -0
- package/roslyn-host/zh-Hant/Microsoft.CodeAnalysis.CSharp.resources.dll +0 -0
- package/roslyn-host/zh-Hant/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll +0 -0
- package/roslyn-host/zh-Hant/Microsoft.CodeAnalysis.Workspaces.resources.dll +0 -0
- package/roslyn-host/zh-Hant/Microsoft.CodeAnalysis.resources.dll +0 -0
- package/server.mjs +1018 -344
package/cli.mjs
CHANGED
|
@@ -973,7 +973,7 @@ var require_command = __commonJS({
|
|
|
973
973
|
var EventEmitter2 = __require("node:events").EventEmitter;
|
|
974
974
|
var childProcess = __require("node:child_process");
|
|
975
975
|
var path80 = __require("node:path");
|
|
976
|
-
var
|
|
976
|
+
var fs71 = __require("node:fs");
|
|
977
977
|
var process2 = __require("node:process");
|
|
978
978
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
979
979
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1906,10 +1906,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1906
1906
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1907
1907
|
function findFile(baseDir, baseName) {
|
|
1908
1908
|
const localBin = path80.resolve(baseDir, baseName);
|
|
1909
|
-
if (
|
|
1909
|
+
if (fs71.existsSync(localBin)) return localBin;
|
|
1910
1910
|
if (sourceExt.includes(path80.extname(baseName))) return void 0;
|
|
1911
1911
|
const foundExt = sourceExt.find(
|
|
1912
|
-
(ext2) =>
|
|
1912
|
+
(ext2) => fs71.existsSync(`${localBin}${ext2}`)
|
|
1913
1913
|
);
|
|
1914
1914
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1915
1915
|
return void 0;
|
|
@@ -1921,7 +1921,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1921
1921
|
if (this._scriptPath) {
|
|
1922
1922
|
let resolvedScriptPath;
|
|
1923
1923
|
try {
|
|
1924
|
-
resolvedScriptPath =
|
|
1924
|
+
resolvedScriptPath = fs71.realpathSync(this._scriptPath);
|
|
1925
1925
|
} catch (err) {
|
|
1926
1926
|
resolvedScriptPath = this._scriptPath;
|
|
1927
1927
|
}
|
|
@@ -17088,8 +17088,8 @@ function getMaxParameters(filePath) {
|
|
|
17088
17088
|
}
|
|
17089
17089
|
return 5;
|
|
17090
17090
|
}
|
|
17091
|
-
function isBootstrapEntry(
|
|
17092
|
-
return LANGUAGE_CONFIGS.some((c2) => c2.bootstrap.functionNames.includes(
|
|
17091
|
+
function isBootstrapEntry(functionName2, filePath) {
|
|
17092
|
+
return LANGUAGE_CONFIGS.some((c2) => c2.bootstrap.functionNames.includes(functionName2) && c2.bootstrap.filePattern.test(filePath));
|
|
17093
17093
|
}
|
|
17094
17094
|
function getLanguageConfig(language) {
|
|
17095
17095
|
const config2 = LANGUAGE_CONFIGS.find((c2) => c2.name === language);
|
|
@@ -21824,9 +21824,6 @@ function buildCSharpSymbolIndex(files, rootPath) {
|
|
|
21824
21824
|
}
|
|
21825
21825
|
function contributeCSharpEdges(files, rootPath) {
|
|
21826
21826
|
const index = buildCSharpSymbolIndex(files, rootPath);
|
|
21827
|
-
if (index.stats.ambiguousRefs > 0) {
|
|
21828
|
-
console.warn(`[TrueCourse] C# symbol index: ${index.stats.ambiguousRefs} ambiguous type reference(s) skipped (same type name visible from multiple namespaces)`);
|
|
21829
|
-
}
|
|
21830
21827
|
return index.edges;
|
|
21831
21828
|
}
|
|
21832
21829
|
var TYPE_DECL_KINDS;
|
|
@@ -27155,12 +27152,9 @@ var init_lsp_client = __esm({
|
|
|
27155
27152
|
this.process.stdout.on("data", (chunk3) => this.onData(chunk3));
|
|
27156
27153
|
this.process.stderr.on("data", (chunk3) => {
|
|
27157
27154
|
});
|
|
27158
|
-
this.process.on("error", (err) =>
|
|
27159
|
-
|
|
27160
|
-
|
|
27161
|
-
}
|
|
27162
|
-
this.pendingRequests.clear();
|
|
27163
|
-
});
|
|
27155
|
+
this.process.on("error", (err) => this.rejectAllPending(err));
|
|
27156
|
+
this.process.stdin.on("error", (err) => this.rejectAllPending(new Error(`${this.config.name} LSP stdin error: ${err.message}`)));
|
|
27157
|
+
this.process.on("exit", (code, signal) => this.rejectAllPending(new Error(`${this.config.name} LSP server exited (${signal ?? `code ${code}`}) before responding`)));
|
|
27164
27158
|
const initResult = await this.sendRequest("initialize", {
|
|
27165
27159
|
processId: process.pid,
|
|
27166
27160
|
capabilities: {
|
|
@@ -27339,17 +27333,33 @@ var init_lsp_client = __esm({
|
|
|
27339
27333
|
// -------------------------------------------------------------------------
|
|
27340
27334
|
// Internal: JSON-RPC transport
|
|
27341
27335
|
// -------------------------------------------------------------------------
|
|
27336
|
+
/** Reject and clear every in-flight request — used when the server dies. */
|
|
27337
|
+
rejectAllPending(err) {
|
|
27338
|
+
if (this.pendingRequests.size === 0)
|
|
27339
|
+
return;
|
|
27340
|
+
for (const pending of this.pendingRequests.values())
|
|
27341
|
+
pending.reject(err);
|
|
27342
|
+
this.pendingRequests.clear();
|
|
27343
|
+
}
|
|
27342
27344
|
sendRequest(method, params) {
|
|
27343
27345
|
return new Promise((resolve12, reject) => {
|
|
27344
27346
|
const id = ++this.requestId;
|
|
27345
27347
|
this.pendingRequests.set(id, { resolve: resolve12, reject });
|
|
27346
27348
|
const msg = { jsonrpc: "2.0", id, method, params };
|
|
27347
|
-
|
|
27349
|
+
try {
|
|
27350
|
+
this.process.stdin.write(encodeMessage(msg));
|
|
27351
|
+
} catch (err) {
|
|
27352
|
+
this.pendingRequests.delete(id);
|
|
27353
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
27354
|
+
}
|
|
27348
27355
|
});
|
|
27349
27356
|
}
|
|
27350
27357
|
sendNotification(method, params) {
|
|
27351
27358
|
const msg = { jsonrpc: "2.0", method, params };
|
|
27352
|
-
|
|
27359
|
+
try {
|
|
27360
|
+
this.process.stdin.write(encodeMessage(msg));
|
|
27361
|
+
} catch {
|
|
27362
|
+
}
|
|
27353
27363
|
}
|
|
27354
27364
|
onData(chunk3) {
|
|
27355
27365
|
this.buffer = Buffer.concat([this.buffer, chunk3]);
|
|
@@ -37834,7 +37844,8 @@ var init_deterministic4 = __esm({
|
|
|
37834
37844
|
description: "Function parameter is never referenced in the function body \u2014 remove it or prefix with `_`.",
|
|
37835
37845
|
enabled: true,
|
|
37836
37846
|
severity: "low",
|
|
37837
|
-
type: "deterministic"
|
|
37847
|
+
type: "deterministic",
|
|
37848
|
+
engine: "roslyn-host"
|
|
37838
37849
|
},
|
|
37839
37850
|
{
|
|
37840
37851
|
key: "code-quality/deterministic/hardcoded-url",
|
|
@@ -49118,6 +49129,94 @@ var init_production_debug_enabled = __esm({
|
|
|
49118
49129
|
});
|
|
49119
49130
|
|
|
49120
49131
|
// packages/analyzer/dist/rules/security/visitors/javascript/insecure-random.js
|
|
49132
|
+
function isSecuritySensitiveName(name) {
|
|
49133
|
+
const lower = name.toLowerCase();
|
|
49134
|
+
return SECURITY_KEYWORDS.some((kw) => lower.includes(kw));
|
|
49135
|
+
}
|
|
49136
|
+
function securityContextName(callNode) {
|
|
49137
|
+
let parent = callNode.parent;
|
|
49138
|
+
while (parent) {
|
|
49139
|
+
switch (parent.type) {
|
|
49140
|
+
case "variable_declarator":
|
|
49141
|
+
return leafName(parent.childForFieldName("name"));
|
|
49142
|
+
case "assignment_expression":
|
|
49143
|
+
case "augmented_assignment_expression":
|
|
49144
|
+
return leafName(parent.childForFieldName("left"));
|
|
49145
|
+
case "pair":
|
|
49146
|
+
return leafName(parent.childForFieldName("key"));
|
|
49147
|
+
case "public_field_definition":
|
|
49148
|
+
case "field_definition":
|
|
49149
|
+
return leafName(parent.childForFieldName("property") ?? parent.childForFieldName("name"));
|
|
49150
|
+
// The value is returned from the enclosing function (e.g.
|
|
49151
|
+
// `function generateToken() { return Math.random()... }`) — the
|
|
49152
|
+
// function name is the security context.
|
|
49153
|
+
case "return_statement":
|
|
49154
|
+
return enclosingFunctionName(parent);
|
|
49155
|
+
// Expression-bodied arrow returns the value directly, e.g.
|
|
49156
|
+
// `const genToken = () => Math.random()...`.
|
|
49157
|
+
case "arrow_function":
|
|
49158
|
+
return functionName(parent);
|
|
49159
|
+
// Structural boundaries: the random value is discarded or otherwise
|
|
49160
|
+
// not bound to a name.
|
|
49161
|
+
case "expression_statement":
|
|
49162
|
+
case "statement_block":
|
|
49163
|
+
case "if_statement":
|
|
49164
|
+
case "for_statement":
|
|
49165
|
+
case "for_in_statement":
|
|
49166
|
+
case "while_statement":
|
|
49167
|
+
case "do_statement":
|
|
49168
|
+
case "switch_statement":
|
|
49169
|
+
case "function_declaration":
|
|
49170
|
+
case "function_expression":
|
|
49171
|
+
case "method_definition":
|
|
49172
|
+
return null;
|
|
49173
|
+
}
|
|
49174
|
+
parent = parent.parent;
|
|
49175
|
+
}
|
|
49176
|
+
return null;
|
|
49177
|
+
}
|
|
49178
|
+
function enclosingFunctionName(node2) {
|
|
49179
|
+
let p2 = node2.parent;
|
|
49180
|
+
while (p2) {
|
|
49181
|
+
if (p2.type === "function_declaration" || p2.type === "generator_function_declaration" || p2.type === "method_definition" || p2.type === "arrow_function" || p2.type === "function_expression") {
|
|
49182
|
+
return functionName(p2);
|
|
49183
|
+
}
|
|
49184
|
+
p2 = p2.parent;
|
|
49185
|
+
}
|
|
49186
|
+
return null;
|
|
49187
|
+
}
|
|
49188
|
+
function functionName(fn) {
|
|
49189
|
+
const nameField = fn.childForFieldName("name");
|
|
49190
|
+
if (nameField)
|
|
49191
|
+
return leafName(nameField);
|
|
49192
|
+
const p2 = fn.parent;
|
|
49193
|
+
if (!p2)
|
|
49194
|
+
return null;
|
|
49195
|
+
if (p2.type === "variable_declarator")
|
|
49196
|
+
return leafName(p2.childForFieldName("name"));
|
|
49197
|
+
if (p2.type === "pair")
|
|
49198
|
+
return leafName(p2.childForFieldName("key"));
|
|
49199
|
+
if (p2.type === "assignment_expression")
|
|
49200
|
+
return leafName(p2.childForFieldName("left"));
|
|
49201
|
+
if (p2.type === "public_field_definition" || p2.type === "field_definition") {
|
|
49202
|
+
return leafName(p2.childForFieldName("property") ?? p2.childForFieldName("name"));
|
|
49203
|
+
}
|
|
49204
|
+
return null;
|
|
49205
|
+
}
|
|
49206
|
+
function leafName(node2) {
|
|
49207
|
+
if (!node2)
|
|
49208
|
+
return null;
|
|
49209
|
+
if (node2.type === "identifier" || node2.type === "property_identifier" || node2.type === "shorthand_property_identifier") {
|
|
49210
|
+
return node2.text;
|
|
49211
|
+
}
|
|
49212
|
+
if (node2.type === "member_expression") {
|
|
49213
|
+
return node2.childForFieldName("property")?.text ?? null;
|
|
49214
|
+
}
|
|
49215
|
+
if (node2.type === "string") {
|
|
49216
|
+
return node2.text.slice(1, -1);
|
|
49217
|
+
}
|
|
49218
|
+
return node2.text;
|
|
49219
|
+
}
|
|
49121
49220
|
function isFixtureOrTestFile(filePath) {
|
|
49122
49221
|
const lower = filePath.toLowerCase();
|
|
49123
49222
|
return /[\\/]seeds?[\\/]/.test(lower) || /[\\/](?:seed|seeds)\.(?:ts|tsx|js|jsx|mts|cts|mjs|cjs)$/.test(lower) || /\.seed\.(?:ts|tsx|js|jsx|mts|cts|mjs|cjs)$/.test(lower) || /[\\/]__tests__[\\/]/.test(lower) || /\.(?:test|spec)\.(?:ts|tsx|js|jsx|mts|cts|mjs|cjs)$/.test(lower);
|
|
@@ -49148,19 +49247,9 @@ var init_insecure_random = __esm({
|
|
|
49148
49247
|
if (/\.length\b/.test(parentText))
|
|
49149
49248
|
return null;
|
|
49150
49249
|
}
|
|
49151
|
-
|
|
49152
|
-
|
|
49153
|
-
|
|
49154
|
-
if (SECURITY_KEYWORDS.some((kw) => parentText.includes(kw))) {
|
|
49155
|
-
const immediateParent = node2.parent;
|
|
49156
|
-
if (immediateParent?.type === "binary_expression" && /\.length\b/.test(immediateParent.text)) {
|
|
49157
|
-
return null;
|
|
49158
|
-
}
|
|
49159
|
-
return makeViolation(this.ruleKey, node2, filePath, "high", "Insecure random number generator", "Math.random() is not cryptographically secure. Do not use it for tokens, keys, or secrets.", sourceCode, "Use crypto.randomBytes() or crypto.randomUUID() instead.");
|
|
49160
|
-
}
|
|
49161
|
-
if (parent.type === "expression_statement" || parent.type === "variable_declaration" || parent.type === "assignment_expression" || parent.type === "lexical_declaration")
|
|
49162
|
-
break;
|
|
49163
|
-
parent = parent.parent;
|
|
49250
|
+
const contextName = securityContextName(node2);
|
|
49251
|
+
if (contextName && isSecuritySensitiveName(contextName)) {
|
|
49252
|
+
return makeViolation(this.ruleKey, node2, filePath, "high", "Insecure random number generator", "Math.random() is not cryptographically secure. Do not use it for tokens, keys, or secrets.", sourceCode, "Use crypto.randomBytes() or crypto.randomUUID() instead.");
|
|
49164
49253
|
}
|
|
49165
49254
|
}
|
|
49166
49255
|
}
|
|
@@ -49589,6 +49678,11 @@ var init_unverified_cross_origin_message = __esm({
|
|
|
49589
49678
|
}
|
|
49590
49679
|
if (methodName3 !== "addEventListener")
|
|
49591
49680
|
return null;
|
|
49681
|
+
if (fn.type === "member_expression") {
|
|
49682
|
+
const receiver = fn.childForFieldName("object")?.text ?? "";
|
|
49683
|
+
if (receiver !== "window" && receiver !== "self" && receiver !== "globalThis")
|
|
49684
|
+
return null;
|
|
49685
|
+
}
|
|
49592
49686
|
const args = node2.childForFieldName("arguments");
|
|
49593
49687
|
if (!args)
|
|
49594
49688
|
return null;
|
|
@@ -50071,7 +50165,11 @@ var init_timing_attack_comparison = __esm({
|
|
|
50071
50165
|
return null;
|
|
50072
50166
|
const leftLeaf = leafIdentifier(left);
|
|
50073
50167
|
const rightLeaf = leafIdentifier(right);
|
|
50074
|
-
|
|
50168
|
+
const leftIsLiteral = left.type === "string" || left.type === "template_string";
|
|
50169
|
+
const rightIsLiteral = right.type === "string" || right.type === "template_string";
|
|
50170
|
+
const leftMatches = !leftIsLiteral && SENSITIVE_COMPARISON_PATTERNS.test(leftLeaf);
|
|
50171
|
+
const rightMatches = !rightIsLiteral && SENSITIVE_COMPARISON_PATTERNS.test(rightLeaf);
|
|
50172
|
+
if (leftMatches || rightMatches) {
|
|
50075
50173
|
if (sourceCode.includes("timingSafeEqual"))
|
|
50076
50174
|
return null;
|
|
50077
50175
|
return makeViolation(this.ruleKey, node2, filePath, "medium", "Timing attack via string comparison", `Using ${operator.text} to compare what may be a secret/token. This is vulnerable to timing attacks.`, sourceCode, "Use crypto.timingSafeEqual() for comparing secrets and tokens.");
|
|
@@ -50658,6 +50756,14 @@ var init_mixed_http_methods = __esm({
|
|
|
50658
50756
|
});
|
|
50659
50757
|
|
|
50660
50758
|
// packages/analyzer/dist/rules/security/visitors/javascript/process-signaling.js
|
|
50759
|
+
function isOwnedProcessPid(node2) {
|
|
50760
|
+
if (node2.type !== "member_expression")
|
|
50761
|
+
return false;
|
|
50762
|
+
if (node2.childForFieldName("property")?.text !== "pid")
|
|
50763
|
+
return false;
|
|
50764
|
+
const obj = node2.childForFieldName("object");
|
|
50765
|
+
return obj?.type === "member_expression" && obj.childForFieldName("property")?.text === "process";
|
|
50766
|
+
}
|
|
50661
50767
|
var processSignalingVisitor;
|
|
50662
50768
|
var init_process_signaling = __esm({
|
|
50663
50769
|
"packages/analyzer/dist/rules/security/visitors/javascript/process-signaling.js"() {
|
|
@@ -50685,6 +50791,8 @@ var init_process_signaling = __esm({
|
|
|
50685
50791
|
const pidArg = args.namedChildren[0];
|
|
50686
50792
|
if (!pidArg)
|
|
50687
50793
|
return null;
|
|
50794
|
+
if (isOwnedProcessPid(pidArg))
|
|
50795
|
+
return null;
|
|
50688
50796
|
if (pidArg.type !== "number") {
|
|
50689
50797
|
return makeViolation(this.ruleKey, node2, filePath, "high", "Sending signals to arbitrary processes", "process.kill() called with a non-literal PID. If the PID is user-controlled, this enables process manipulation.", sourceCode, "Validate and sanitize the PID before passing it to process.kill().");
|
|
50690
50798
|
}
|
|
@@ -52038,8 +52146,8 @@ var init_sql_injection2 = __esm({
|
|
|
52038
52146
|
if (!firstArg)
|
|
52039
52147
|
return null;
|
|
52040
52148
|
if (firstArg.type === "string" && firstArg.text.startsWith("f")) {
|
|
52041
|
-
const
|
|
52042
|
-
if (
|
|
52149
|
+
const hasInterpolation = firstArg.namedChildren.some((c2) => c2.type === "interpolation");
|
|
52150
|
+
if (hasInterpolation) {
|
|
52043
52151
|
const queryText = firstArg.text;
|
|
52044
52152
|
if (/:[a-z_]\w*|%s|%\(\w+\)s/.test(queryText))
|
|
52045
52153
|
return null;
|
|
@@ -52549,17 +52657,17 @@ var init_eval_usage2 = __esm({
|
|
|
52549
52657
|
funcName = attr.text;
|
|
52550
52658
|
const receiver = fn.childForFieldName("object");
|
|
52551
52659
|
if (receiver) {
|
|
52552
|
-
let
|
|
52660
|
+
let leafName3 = null;
|
|
52553
52661
|
if (receiver.type === "identifier") {
|
|
52554
|
-
|
|
52662
|
+
leafName3 = receiver.text;
|
|
52555
52663
|
} else if (receiver.type === "attribute") {
|
|
52556
52664
|
const attrChild = receiver.childForFieldName("attribute");
|
|
52557
52665
|
if (attrChild) {
|
|
52558
|
-
|
|
52666
|
+
leafName3 = attrChild.text.replace(/^_+/, "");
|
|
52559
52667
|
}
|
|
52560
52668
|
}
|
|
52561
|
-
if (
|
|
52562
|
-
const expectedSources = SAFE_RECEIVER_IMPORT_SOURCES[
|
|
52669
|
+
if (leafName3 && SAFE_METHOD_RECEIVERS.has(leafName3)) {
|
|
52670
|
+
const expectedSources = SAFE_RECEIVER_IMPORT_SOURCES[leafName3];
|
|
52563
52671
|
if (expectedSources) {
|
|
52564
52672
|
const sources = getPythonImportSources(node2);
|
|
52565
52673
|
for (const src of sources) {
|
|
@@ -56531,6 +56639,12 @@ var init_exclusions = __esm({
|
|
|
56531
56639
|
/^https?:\/\/(?!hooks\.slack\.com|[a-z0-9]+\.webhook\.office\.com)/,
|
|
56532
56640
|
// Docker / container image references
|
|
56533
56641
|
/^(?:docker|ghcr|quay|gcr|ecr)\.io\//,
|
|
56642
|
+
// PostHog public project API key (phc_…) — intentionally client-exposed,
|
|
56643
|
+
// embedded in frontend code to send analytics events. Its 40+ char base62
|
|
56644
|
+
// body collides with the generic Cohere-token shape, but it is not a
|
|
56645
|
+
// private credential. Private PostHog keys use the phx_/phs_ prefixes and
|
|
56646
|
+
// are deliberately NOT allowlisted here.
|
|
56647
|
+
/^phc_[A-Za-z0-9]{30,}$/,
|
|
56534
56648
|
// Common config patterns that aren't secrets
|
|
56535
56649
|
/^\*+$/,
|
|
56536
56650
|
// All asterisks (masked values)
|
|
@@ -58346,10 +58460,33 @@ var init_secret_scanner = __esm({
|
|
|
58346
58460
|
});
|
|
58347
58461
|
|
|
58348
58462
|
// packages/analyzer/dist/rules/security/visitors/universal.js
|
|
58463
|
+
function hasPasswordToken(text4) {
|
|
58464
|
+
const lower = text4.toLowerCase();
|
|
58465
|
+
return lower.includes("password") || lower.includes("passwd");
|
|
58466
|
+
}
|
|
58467
|
+
function isPasswordHashingContext(node2) {
|
|
58468
|
+
let stmt = node2.parent;
|
|
58469
|
+
while (stmt && !STATEMENT_NODE_TYPES2.has(stmt.type) && !FUNCTION_NODE_TYPES3.has(stmt.type)) {
|
|
58470
|
+
stmt = stmt.parent;
|
|
58471
|
+
}
|
|
58472
|
+
if (stmt && STATEMENT_NODE_TYPES2.has(stmt.type) && hasPasswordToken(stmt.text))
|
|
58473
|
+
return true;
|
|
58474
|
+
let fnNode = node2.parent;
|
|
58475
|
+
while (fnNode && !FUNCTION_NODE_TYPES3.has(fnNode.type))
|
|
58476
|
+
fnNode = fnNode.parent;
|
|
58477
|
+
if (fnNode) {
|
|
58478
|
+
const nameNode = fnNode.childForFieldName("name");
|
|
58479
|
+
const paramsNode = fnNode.childForFieldName("parameters") ?? fnNode.childForFieldName("parameter_list");
|
|
58480
|
+
const signature = `${nameNode?.text ?? ""} ${paramsNode?.text ?? ""}`;
|
|
58481
|
+
if (hasPasswordToken(signature))
|
|
58482
|
+
return true;
|
|
58483
|
+
}
|
|
58484
|
+
return false;
|
|
58485
|
+
}
|
|
58349
58486
|
function stripCommentMarkers(text4) {
|
|
58350
58487
|
return text4.replace(/^\/{2,3}\s?/, "").replace(/^\/\*\s?/, "").replace(/\s?\*\/$/, "").replace(/^\s*\*\s?/gm, "").replace(/^#\s?/gm, "").trim();
|
|
58351
58488
|
}
|
|
58352
|
-
var STRING_NODE_TYPES, hardcodedSecretVisitor, IPV4_REGEX, EXCLUDED_IPS, hardcodedIpVisitor, CLEARTEXT_PROTOCOLS, LOCALHOST_PREFIXES, clearTextProtocolVisitor, BIP39_COMMON_WORDS, hardcodedBlockchainMnemonicVisitor, DB_URL_PATTERN, DB_PASSWORD_KV_PATTERNS, NON_LITERAL_PASSWORD_SEGMENT, PLACEHOLDER_PASSWORDS, hardcodedDatabasePasswordVisitor, ldapUnauthenticatedVisitor, passwordStoredPlaintextVisitor, HASH_FUNCTIONS_NEEDING_SALT, unpredictableSaltMissingVisitor, sensitiveFileVisitor, hardcodedSecretInCommentVisitor, SECURITY_UNIVERSAL_VISITORS;
|
|
58489
|
+
var STRING_NODE_TYPES, hardcodedSecretVisitor, IPV4_REGEX, EXCLUDED_IPS, hardcodedIpVisitor, CLEARTEXT_PROTOCOLS, LOCALHOST_PREFIXES, clearTextProtocolVisitor, BIP39_COMMON_WORDS, hardcodedBlockchainMnemonicVisitor, DB_URL_PATTERN, DB_PASSWORD_KV_PATTERNS, NON_LITERAL_PASSWORD_SEGMENT, PLACEHOLDER_PASSWORDS, hardcodedDatabasePasswordVisitor, ldapUnauthenticatedVisitor, passwordStoredPlaintextVisitor, HASH_FUNCTIONS_NEEDING_SALT, STATEMENT_NODE_TYPES2, FUNCTION_NODE_TYPES3, unpredictableSaltMissingVisitor, sensitiveFileVisitor, hardcodedSecretInCommentVisitor, SECURITY_UNIVERSAL_VISITORS;
|
|
58353
58490
|
var init_universal = __esm({
|
|
58354
58491
|
"packages/analyzer/dist/rules/security/visitors/universal.js"() {
|
|
58355
58492
|
"use strict";
|
|
@@ -59529,6 +59666,29 @@ var init_universal = __esm({
|
|
|
59529
59666
|
"sha256",
|
|
59530
59667
|
"sha512"
|
|
59531
59668
|
]);
|
|
59669
|
+
STATEMENT_NODE_TYPES2 = /* @__PURE__ */ new Set([
|
|
59670
|
+
"expression_statement",
|
|
59671
|
+
"return_statement",
|
|
59672
|
+
"lexical_declaration",
|
|
59673
|
+
"variable_declaration",
|
|
59674
|
+
"variable_declarator",
|
|
59675
|
+
"local_declaration_statement",
|
|
59676
|
+
"assignment",
|
|
59677
|
+
"augmented_assignment",
|
|
59678
|
+
"assignment_expression",
|
|
59679
|
+
"augmented_assignment_expression"
|
|
59680
|
+
]);
|
|
59681
|
+
FUNCTION_NODE_TYPES3 = /* @__PURE__ */ new Set([
|
|
59682
|
+
"function_declaration",
|
|
59683
|
+
"function_expression",
|
|
59684
|
+
"arrow_function",
|
|
59685
|
+
"generator_function_declaration",
|
|
59686
|
+
"method_definition",
|
|
59687
|
+
"function_definition",
|
|
59688
|
+
"method_declaration",
|
|
59689
|
+
"local_function_statement",
|
|
59690
|
+
"constructor_declaration"
|
|
59691
|
+
]);
|
|
59532
59692
|
unpredictableSaltMissingVisitor = {
|
|
59533
59693
|
ruleKey: "security/deterministic/unpredictable-salt-missing",
|
|
59534
59694
|
nodeTypes: ["call_expression", "call", "invocation_expression"],
|
|
@@ -59546,21 +59706,12 @@ var init_universal = __esm({
|
|
|
59546
59706
|
}
|
|
59547
59707
|
if (!HASH_FUNCTIONS_NEEDING_SALT.has(methodName3))
|
|
59548
59708
|
return null;
|
|
59549
|
-
|
|
59550
|
-
|
|
59551
|
-
|
|
59552
|
-
|
|
59553
|
-
|
|
59554
|
-
|
|
59555
|
-
return makeViolation(this.ruleKey, node2, filePath, "high", "Missing salt in hash", `${methodName3}() called without a salt in a password context. This allows rainbow table attacks.`, sourceCode, "Use a password hashing function like bcrypt, argon2, or PBKDF2 which handle salting automatically.");
|
|
59556
|
-
}
|
|
59557
|
-
return null;
|
|
59558
|
-
}
|
|
59559
|
-
if (parent.type === "function_declaration" || parent.type === "function_definition" || parent.type === "method_definition" || parent.type === "program" || parent.type === "method_declaration" || parent.type === "compilation_unit")
|
|
59560
|
-
break;
|
|
59561
|
-
parent = parent.parent;
|
|
59562
|
-
}
|
|
59563
|
-
return null;
|
|
59709
|
+
const args = node2.childForFieldName("arguments");
|
|
59710
|
+
if (!args || args.namedChildren.length >= 2)
|
|
59711
|
+
return null;
|
|
59712
|
+
if (!isPasswordHashingContext(node2))
|
|
59713
|
+
return null;
|
|
59714
|
+
return makeViolation(this.ruleKey, node2, filePath, "high", "Missing salt in hash", `${methodName3}() called without a salt in a password context. This allows rainbow table attacks.`, sourceCode, "Use a password hashing function like bcrypt, argon2, or PBKDF2 which handle salting automatically.");
|
|
59564
59715
|
}
|
|
59565
59716
|
};
|
|
59566
59717
|
sensitiveFileVisitor = {
|
|
@@ -59653,7 +59804,7 @@ function isLiteralNode(n) {
|
|
|
59653
59804
|
}
|
|
59654
59805
|
return false;
|
|
59655
59806
|
}
|
|
59656
|
-
var JS_LANGUAGES, TS_LANGUAGES, COMPARISON_OPERATORS, CONSTANT_LITERALS, TERMINAL_TYPES, VALID_TYPEOF_VALUES, LITERAL_TYPES, ARRAY_METHODS_REQUIRING_RETURN, PRIMITIVE_TYPES, PURE_ARRAY_METHODS, KNOWN_ARG_ORDERS, VOID_RETURNING_METHODS, VOID_RETURNING_GLOBALS, NON_CONSTRUCTORS, PROTOTYPE_BUILTINS, NON_CALLABLE_GLOBALS, READ_ONLY_GLOBALS, RESTRICTED_NAMES, THROWABLE_TYPES;
|
|
59807
|
+
var JS_LANGUAGES, TS_LANGUAGES, COMPARISON_OPERATORS, CONSTANT_LITERALS, TERMINAL_TYPES, VALID_TYPEOF_VALUES, LITERAL_TYPES, ARRAY_METHODS_REQUIRING_RETURN, PRIMITIVE_TYPES, PURE_ARRAY_METHODS, SOCKET_IO_RECEIVERS, KNOWN_ARG_ORDERS, VOID_RETURNING_METHODS, VOID_RETURNING_GLOBALS, NON_CONSTRUCTORS, PROTOTYPE_BUILTINS, NON_CALLABLE_GLOBALS, READ_ONLY_GLOBALS, RESTRICTED_NAMES, THROWABLE_TYPES;
|
|
59657
59808
|
var init_helpers2 = __esm({
|
|
59658
59809
|
"packages/analyzer/dist/rules/bugs/visitors/javascript/_helpers.js"() {
|
|
59659
59810
|
"use strict";
|
|
@@ -59711,6 +59862,7 @@ var init_helpers2 = __esm({
|
|
|
59711
59862
|
"reduce",
|
|
59712
59863
|
"reduceRight"
|
|
59713
59864
|
]);
|
|
59865
|
+
SOCKET_IO_RECEIVERS = /* @__PURE__ */ new Set(["socket", "sockets"]);
|
|
59714
59866
|
KNOWN_ARG_ORDERS = [
|
|
59715
59867
|
{ fn: "startsWith", params: [["prefix", "str", "string", "start", "needle", "search"]] },
|
|
59716
59868
|
{ fn: "endsWith", params: [["suffix", "str", "string", "end", "needle", "search"]] },
|
|
@@ -60347,6 +60499,15 @@ var init_loss_of_precision = __esm({
|
|
|
60347
60499
|
const num = Number(text4);
|
|
60348
60500
|
if (!Number.isFinite(num))
|
|
60349
60501
|
return null;
|
|
60502
|
+
const parent = node2.parent;
|
|
60503
|
+
if (parent?.type === "arguments") {
|
|
60504
|
+
const call = parent.parent;
|
|
60505
|
+
if (call?.type === "call_expression") {
|
|
60506
|
+
const fn = call.childForFieldName("function");
|
|
60507
|
+
if (fn?.type === "identifier" && fn.text === "BigInt")
|
|
60508
|
+
return null;
|
|
60509
|
+
}
|
|
60510
|
+
}
|
|
60350
60511
|
if (!Number.isSafeInteger(num)) {
|
|
60351
60512
|
return makeViolation(this.ruleKey, node2, filePath, "high", "Loss of precision", `\`${text4}\` exceeds Number.MAX_SAFE_INTEGER and will lose precision at runtime.`, sourceCode, `Use BigInt (\`${text4}n\`) or restructure to avoid large integer literals.`);
|
|
60352
60513
|
}
|
|
@@ -62618,6 +62779,17 @@ var init_useless_increment = __esm({
|
|
|
62618
62779
|
});
|
|
62619
62780
|
|
|
62620
62781
|
// packages/analyzer/dist/rules/bugs/visitors/javascript/ignored-return-value.js
|
|
62782
|
+
function receiverBaseName(obj) {
|
|
62783
|
+
if (!obj)
|
|
62784
|
+
return null;
|
|
62785
|
+
if (obj.type === "identifier")
|
|
62786
|
+
return obj.text.toLowerCase();
|
|
62787
|
+
if (obj.type === "member_expression") {
|
|
62788
|
+
const prop = obj.childForFieldName("property");
|
|
62789
|
+
return prop ? prop.text.toLowerCase() : null;
|
|
62790
|
+
}
|
|
62791
|
+
return null;
|
|
62792
|
+
}
|
|
62621
62793
|
var ignoredReturnValueVisitor;
|
|
62622
62794
|
var init_ignored_return_value = __esm({
|
|
62623
62795
|
"packages/analyzer/dist/rules/bugs/visitors/javascript/ignored-return-value.js"() {
|
|
@@ -62638,6 +62810,11 @@ var init_ignored_return_value = __esm({
|
|
|
62638
62810
|
const prop = fn.childForFieldName("property");
|
|
62639
62811
|
if (!prop || !PURE_ARRAY_METHODS.has(prop.text))
|
|
62640
62812
|
return null;
|
|
62813
|
+
if (prop.text === "join") {
|
|
62814
|
+
const base2 = receiverBaseName(fn.childForFieldName("object"));
|
|
62815
|
+
if (base2 && SOCKET_IO_RECEIVERS.has(base2))
|
|
62816
|
+
return null;
|
|
62817
|
+
}
|
|
62641
62818
|
return makeViolation(this.ruleKey, expr, filePath, "high", "Ignored return value", `The return value of \`.${prop.text}()\` is ignored \u2014 this method does not mutate the array in place; the result must be used.`, sourceCode, `Assign the result: \`const result = arr.${prop.text}(...)\`.`);
|
|
62642
62819
|
}
|
|
62643
62820
|
};
|
|
@@ -63299,7 +63476,12 @@ var init_global_this_usage = __esm({
|
|
|
63299
63476
|
let current = node2.parent;
|
|
63300
63477
|
while (current) {
|
|
63301
63478
|
const t2 = current.type;
|
|
63302
|
-
if (t2 === "function_declaration" || t2 === "function" ||
|
|
63479
|
+
if (t2 === "function_declaration" || t2 === "function" || // Modern tree-sitter-javascript names a `function () {}` expression
|
|
63480
|
+
// `function_expression` (only the legacy grammar used bare `function`).
|
|
63481
|
+
// Without it, `this` inside any function-expression callback / IIFE /
|
|
63482
|
+
// prototype-assigned method walks up to program scope and is wrongly
|
|
63483
|
+
// reported as a global reference.
|
|
63484
|
+
t2 === "function_expression" || t2 === "generator_function" || t2 === "generator_function_declaration" || t2 === "method_definition" || t2 === "class_declaration" || t2 === "class") {
|
|
63303
63485
|
return null;
|
|
63304
63486
|
}
|
|
63305
63487
|
if (t2 === "arrow_function") {
|
|
@@ -65965,6 +66147,9 @@ var init_missing_await = __esm({
|
|
|
65965
66147
|
return null;
|
|
65966
66148
|
if (!isInsideAsyncFunction(node2))
|
|
65967
66149
|
return null;
|
|
66150
|
+
const declaredName = node2.childForFieldName("name");
|
|
66151
|
+
if (declaredName?.type === "identifier" && /Promise$/.test(declaredName.text))
|
|
66152
|
+
return null;
|
|
65968
66153
|
const isPromise = typeQuery.isPromiseLike(filePath, value.startPosition.row, value.startPosition.column, value.endPosition.row, value.endPosition.column);
|
|
65969
66154
|
if (!isPromise)
|
|
65970
66155
|
return null;
|
|
@@ -66541,25 +66726,26 @@ var init_unbound_method = __esm({
|
|
|
66541
66726
|
let classBody = node2.parent;
|
|
66542
66727
|
while (classBody && classBody.type !== "class_body")
|
|
66543
66728
|
classBody = classBody.parent;
|
|
66544
|
-
if (classBody)
|
|
66545
|
-
|
|
66546
|
-
|
|
66547
|
-
|
|
66548
|
-
|
|
66549
|
-
|
|
66550
|
-
|
|
66551
|
-
|
|
66552
|
-
|
|
66553
|
-
|
|
66554
|
-
|
|
66555
|
-
|
|
66556
|
-
|
|
66557
|
-
|
|
66558
|
-
|
|
66559
|
-
|
|
66560
|
-
}
|
|
66729
|
+
if (!classBody)
|
|
66730
|
+
return null;
|
|
66731
|
+
let resolvesToMethod = false;
|
|
66732
|
+
for (const member of classBody.namedChildren) {
|
|
66733
|
+
if (member.type === "method_definition") {
|
|
66734
|
+
const nameNode = member.childForFieldName("name");
|
|
66735
|
+
if (nameNode?.text !== methodName3)
|
|
66736
|
+
continue;
|
|
66737
|
+
const isAccessor = member.children.some((c2) => (c2.text === "get" || c2.text === "set") && c2.type !== "property_identifier");
|
|
66738
|
+
resolvesToMethod = !isAccessor;
|
|
66739
|
+
break;
|
|
66740
|
+
}
|
|
66741
|
+
if (member.type === "public_field_definition" || member.type === "field_definition") {
|
|
66742
|
+
const nameNode = member.children.find((c2) => c2.type === "property_identifier" || c2.type === "private_property_identifier");
|
|
66743
|
+
if (nameNode?.text === methodName3)
|
|
66744
|
+
return null;
|
|
66561
66745
|
}
|
|
66562
66746
|
}
|
|
66747
|
+
if (!resolvesToMethod)
|
|
66748
|
+
return null;
|
|
66563
66749
|
return makeViolation(this.ruleKey, node2, filePath, "high", "Unbound method reference", `\`this.${methodName3}\` is used as a value without binding \u2014 \`this\` will be lost when called as a callback.`, sourceCode, "Use `this.method.bind(this)`, an arrow wrapper `() => this.method()`, or declare as an arrow function property.");
|
|
66564
66750
|
}
|
|
66565
66751
|
};
|
|
@@ -66662,7 +66848,7 @@ var init_missing_error_boundary = __esm({
|
|
|
66662
66848
|
visit(node2, filePath, sourceCode) {
|
|
66663
66849
|
if (!sourceCode.includes("React") && !sourceCode.includes("react") && !sourceCode.includes("jsx"))
|
|
66664
66850
|
return null;
|
|
66665
|
-
const hasAsyncData = /(?<![.\w])useQuery\b/.test(sourceCode) || /(?<![.\w])useSWR\b/.test(sourceCode) || /\buseSuspenseQuery\b/.test(sourceCode) || /\buseSuspenseInfiniteQuery\b/.test(sourceCode)
|
|
66851
|
+
const hasAsyncData = /(?<![.\w])useQuery\b/.test(sourceCode) || /(?<![.\w])useSWR\b/.test(sourceCode) || /\buseSuspenseQuery\b/.test(sourceCode) || /\buseSuspenseInfiniteQuery\b/.test(sourceCode);
|
|
66666
66852
|
if (!hasAsyncData)
|
|
66667
66853
|
return null;
|
|
66668
66854
|
if (/\bErrorBoundary\b/.test(sourceCode))
|
|
@@ -79487,6 +79673,9 @@ var init_star_import = __esm({
|
|
|
79487
79673
|
if (sourceText === "zod" || sourceText.startsWith("@react-email/") || sourceText.startsWith("fumadocs-ui/") || sourceText.startsWith("fumadocs-core/")) {
|
|
79488
79674
|
return null;
|
|
79489
79675
|
}
|
|
79676
|
+
if (sourceText === "semver" || sourceText.startsWith("@sentry/")) {
|
|
79677
|
+
return null;
|
|
79678
|
+
}
|
|
79490
79679
|
if (sourceText.startsWith("./") || sourceText.startsWith("../"))
|
|
79491
79680
|
return null;
|
|
79492
79681
|
const nsImport = node2.namedChildren.find((c2) => c2.type === "import_clause")?.namedChildren.find((cc) => cc.type === "namespace_import");
|
|
@@ -81055,14 +81244,20 @@ var init_expression_complexity = __esm({
|
|
|
81055
81244
|
if (!expr)
|
|
81056
81245
|
return null;
|
|
81057
81246
|
let target = expr;
|
|
81058
|
-
while (target.type === "parenthesized_expression" && target.namedChildren[0]) {
|
|
81247
|
+
while ((target.type === "parenthesized_expression" || target.type === "as_expression" || target.type === "satisfies_expression" || target.type === "non_null_expression") && target.namedChildren[0]) {
|
|
81059
81248
|
target = target.namedChildren[0];
|
|
81060
81249
|
}
|
|
81250
|
+
if (target.type === "object" || target.type === "array")
|
|
81251
|
+
return null;
|
|
81061
81252
|
if (target.type === "arrow_function" || target.type === "function_expression" || target.type === "function_declaration" || target.type === "generator_function" || target.type === "generator_function_declaration")
|
|
81062
81253
|
return null;
|
|
81063
81254
|
if (target.type === "jsx_element" || target.type === "jsx_fragment" || target.type === "jsx_self_closing_element")
|
|
81064
81255
|
return null;
|
|
81065
81256
|
let operatorCount = 0;
|
|
81257
|
+
let hasLogical = false;
|
|
81258
|
+
let hasArithmetic = false;
|
|
81259
|
+
const LOGICAL_OPS = /* @__PURE__ */ new Set(["&&", "||", "??"]);
|
|
81260
|
+
const ARITHMETIC_OPS3 = /* @__PURE__ */ new Set(["+", "-", "*", "/", "%", "**", "&", "|", "^", "<<", ">>", ">>>"]);
|
|
81066
81261
|
const BINARY_TYPES = /* @__PURE__ */ new Set(["binary_expression", "logical_expression"]);
|
|
81067
81262
|
const FUNCTION_BOUNDARY_TYPES3 = /* @__PURE__ */ new Set([
|
|
81068
81263
|
"function_declaration",
|
|
@@ -81075,6 +81270,13 @@ var init_expression_complexity = __esm({
|
|
|
81075
81270
|
function countOps(n) {
|
|
81076
81271
|
if (BINARY_TYPES.has(n.type)) {
|
|
81077
81272
|
operatorCount++;
|
|
81273
|
+
const op = n.childForFieldName("operator")?.text;
|
|
81274
|
+
if (op) {
|
|
81275
|
+
if (LOGICAL_OPS.has(op))
|
|
81276
|
+
hasLogical = true;
|
|
81277
|
+
else if (ARITHMETIC_OPS3.has(op))
|
|
81278
|
+
hasArithmetic = true;
|
|
81279
|
+
}
|
|
81078
81280
|
}
|
|
81079
81281
|
for (let i = 0; i < n.childCount; i++) {
|
|
81080
81282
|
const child = n.child(i);
|
|
@@ -81087,6 +81289,8 @@ var init_expression_complexity = __esm({
|
|
|
81087
81289
|
}
|
|
81088
81290
|
countOps(expr);
|
|
81089
81291
|
if (operatorCount > 5) {
|
|
81292
|
+
if (hasLogical && !hasArithmetic)
|
|
81293
|
+
return null;
|
|
81090
81294
|
return makeViolation(this.ruleKey, node2, filePath, "medium", "Complex expression", `Expression has ${operatorCount} binary/logical operators (max 5). Break it into named variables for readability.`, sourceCode, "Split the expression into smaller, named intermediate variables.");
|
|
81091
81295
|
}
|
|
81092
81296
|
return null;
|
|
@@ -81911,12 +82115,73 @@ var init_strict_equality = __esm({
|
|
|
81911
82115
|
}
|
|
81912
82116
|
});
|
|
81913
82117
|
|
|
81914
|
-
// packages/analyzer/dist/rules/code-quality/visitors/
|
|
81915
|
-
|
|
82118
|
+
// packages/analyzer/dist/rules/code-quality/visitors/_shared/commented-out-code.js
|
|
82119
|
+
function stripLineMarker(line) {
|
|
82120
|
+
return line.replace(/^\s*(?:\/\/+|#+)\s?/, "").replace(/^\s*\*\/?\s?/, "").replace(/\*\/\s*$/, "").trim();
|
|
82121
|
+
}
|
|
82122
|
+
function looksLikeProse(line) {
|
|
82123
|
+
const words = line.match(/[A-Za-z][A-Za-z'-]+/g) ?? [];
|
|
82124
|
+
const codePunct = (line.match(/[;{}()=<>[\]]/g) ?? []).length;
|
|
82125
|
+
return words.length >= 4 && codePunct <= 1;
|
|
82126
|
+
}
|
|
82127
|
+
function looksLikeCode(line, opts) {
|
|
82128
|
+
if (/[;{}]\s*$/.test(line))
|
|
82129
|
+
return true;
|
|
82130
|
+
if (opts.colonTerminates && /:\s*$/.test(line))
|
|
82131
|
+
return true;
|
|
82132
|
+
if (/=>/.test(line))
|
|
82133
|
+
return true;
|
|
82134
|
+
if (/^[\w.]+\s*\([^)]*\)\s*;?\s*$/.test(line))
|
|
82135
|
+
return true;
|
|
82136
|
+
if (/^[\w.[\]]+\s*=\s*[^=].*$/.test(line) && !/==/.test(line))
|
|
82137
|
+
return true;
|
|
82138
|
+
return false;
|
|
82139
|
+
}
|
|
82140
|
+
function isCommentedOutCode(inner, opts) {
|
|
82141
|
+
let code = 0;
|
|
82142
|
+
let prose = 0;
|
|
82143
|
+
for (const raw of inner.split("\n")) {
|
|
82144
|
+
const line = stripLineMarker(raw);
|
|
82145
|
+
if (line.length === 0)
|
|
82146
|
+
continue;
|
|
82147
|
+
if (looksLikeProse(line))
|
|
82148
|
+
prose++;
|
|
82149
|
+
else if (looksLikeCode(line, opts))
|
|
82150
|
+
code++;
|
|
82151
|
+
}
|
|
82152
|
+
return code > 0 && code >= prose;
|
|
82153
|
+
}
|
|
82154
|
+
function lineCommentRunInner(node2, opts) {
|
|
82155
|
+
const isRunLine = (n) => n != null && n.type === "comment" && opts.isLineComment(n.text);
|
|
82156
|
+
if (!isRunLine(node2))
|
|
82157
|
+
return null;
|
|
82158
|
+
const prev = node2.previousSibling;
|
|
82159
|
+
if (isRunLine(prev) && prev.startPosition.row === node2.startPosition.row - 1)
|
|
82160
|
+
return null;
|
|
82161
|
+
const lines = [opts.strip(node2.text)];
|
|
82162
|
+
let cur = node2.nextSibling;
|
|
82163
|
+
let lastRow = node2.startPosition.row;
|
|
82164
|
+
while (isRunLine(cur) && cur.startPosition.row === lastRow + 1) {
|
|
82165
|
+
lines.push(opts.strip(cur.text));
|
|
82166
|
+
lastRow = cur.startPosition.row;
|
|
82167
|
+
cur = cur.nextSibling;
|
|
82168
|
+
}
|
|
82169
|
+
return lines.join("\n");
|
|
82170
|
+
}
|
|
81916
82171
|
var init_commented_out_code = __esm({
|
|
82172
|
+
"packages/analyzer/dist/rules/code-quality/visitors/_shared/commented-out-code.js"() {
|
|
82173
|
+
"use strict";
|
|
82174
|
+
}
|
|
82175
|
+
});
|
|
82176
|
+
|
|
82177
|
+
// packages/analyzer/dist/rules/code-quality/visitors/javascript/commented-out-code.js
|
|
82178
|
+
var isLineComment, commentedOutCodeVisitor;
|
|
82179
|
+
var init_commented_out_code2 = __esm({
|
|
81917
82180
|
"packages/analyzer/dist/rules/code-quality/visitors/javascript/commented-out-code.js"() {
|
|
81918
82181
|
"use strict";
|
|
81919
82182
|
init_types2();
|
|
82183
|
+
init_commented_out_code();
|
|
82184
|
+
isLineComment = (t2) => t2.startsWith("//");
|
|
81920
82185
|
commentedOutCodeVisitor = {
|
|
81921
82186
|
ruleKey: "code-quality/deterministic/commented-out-code",
|
|
81922
82187
|
languages: ["typescript", "tsx", "javascript"],
|
|
@@ -81925,21 +82190,19 @@ var init_commented_out_code = __esm({
|
|
|
81925
82190
|
const text4 = node2.text;
|
|
81926
82191
|
if (text4.startsWith("/**"))
|
|
81927
82192
|
return null;
|
|
81928
|
-
let inner
|
|
81929
|
-
if (
|
|
81930
|
-
inner =
|
|
81931
|
-
|
|
81932
|
-
|
|
81933
|
-
if (
|
|
81934
|
-
|
|
81935
|
-
|
|
81936
|
-
|
|
81937
|
-
|
|
81938
|
-
|
|
81939
|
-
|
|
81940
|
-
|
|
81941
|
-
const matchCount = codePatterns.filter((p2) => p2.test(inner)).length;
|
|
81942
|
-
if (matchCount >= 2) {
|
|
82193
|
+
let inner;
|
|
82194
|
+
if (isLineComment(text4)) {
|
|
82195
|
+
inner = lineCommentRunInner(node2, { isLineComment, strip: (t2) => t2.replace(/^\/\/+/, "") });
|
|
82196
|
+
if (inner === null)
|
|
82197
|
+
return null;
|
|
82198
|
+
} else if (text4.startsWith("/*")) {
|
|
82199
|
+
inner = text4.slice(2, -2);
|
|
82200
|
+
} else {
|
|
82201
|
+
return null;
|
|
82202
|
+
}
|
|
82203
|
+
if (inner.trim().length < 10)
|
|
82204
|
+
return null;
|
|
82205
|
+
if (isCommentedOutCode(inner, {})) {
|
|
81943
82206
|
return makeViolation(this.ruleKey, node2, filePath, "low", "Commented-out code", "This comment appears to contain commented-out code. Remove it or track it in version control.", sourceCode, "Delete the commented-out code. If needed, it can be recovered from version control.");
|
|
81944
82207
|
}
|
|
81945
82208
|
return null;
|
|
@@ -82720,6 +82983,11 @@ var init_for_in_without_filter = __esm({
|
|
|
82720
82983
|
return true;
|
|
82721
82984
|
}
|
|
82722
82985
|
}
|
|
82986
|
+
if (n.type === "member_expression") {
|
|
82987
|
+
const prop = n.childForFieldName("property");
|
|
82988
|
+
if (prop?.text === "hasOwnProperty" || prop?.text === "hasOwn")
|
|
82989
|
+
return true;
|
|
82990
|
+
}
|
|
82723
82991
|
if (n.type === "string" && (n.text.includes("hasOwnProperty") || n.text.includes("hasOwn")))
|
|
82724
82992
|
return true;
|
|
82725
82993
|
for (let i = 0; i < n.childCount; i++) {
|
|
@@ -84087,6 +84355,10 @@ var init_selector_parameter = __esm({
|
|
|
84087
84355
|
languages: ["typescript", "tsx", "javascript"],
|
|
84088
84356
|
nodeTypes: JS_FUNCTION_TYPES,
|
|
84089
84357
|
visit(node2, filePath, sourceCode) {
|
|
84358
|
+
const fnParent = node2.parent;
|
|
84359
|
+
if ((node2.type === "arrow_function" || node2.type === "function_expression") && (fnParent?.type === "arguments" || fnParent?.type === "jsx_expression")) {
|
|
84360
|
+
return null;
|
|
84361
|
+
}
|
|
84090
84362
|
const params = node2.childForFieldName("parameters");
|
|
84091
84363
|
if (!params)
|
|
84092
84364
|
return null;
|
|
@@ -86169,6 +86441,15 @@ var init_meaningless_void_operator = __esm({
|
|
|
86169
86441
|
});
|
|
86170
86442
|
|
|
86171
86443
|
// packages/analyzer/dist/rules/code-quality/visitors/javascript/test-with-hardcoded-timeout.js
|
|
86444
|
+
function isTestFile(filePath) {
|
|
86445
|
+
const norm = filePath.replace(/\\/g, "/");
|
|
86446
|
+
const base2 = norm.slice(norm.lastIndexOf("/") + 1);
|
|
86447
|
+
if (/\.(test|spec)\.[cm]?[jt]sx?$/i.test(base2))
|
|
86448
|
+
return true;
|
|
86449
|
+
if (/(^|\/)__tests?__\//.test(norm))
|
|
86450
|
+
return true;
|
|
86451
|
+
return false;
|
|
86452
|
+
}
|
|
86172
86453
|
var testWithHardcodedTimeoutVisitor;
|
|
86173
86454
|
var init_test_with_hardcoded_timeout = __esm({
|
|
86174
86455
|
"packages/analyzer/dist/rules/code-quality/visitors/javascript/test-with-hardcoded-timeout.js"() {
|
|
@@ -86179,7 +86460,7 @@ var init_test_with_hardcoded_timeout = __esm({
|
|
|
86179
86460
|
languages: ["typescript", "tsx", "javascript"],
|
|
86180
86461
|
nodeTypes: ["call_expression"],
|
|
86181
86462
|
visit(node2, filePath, sourceCode) {
|
|
86182
|
-
if (!
|
|
86463
|
+
if (!isTestFile(filePath))
|
|
86183
86464
|
return null;
|
|
86184
86465
|
const fn = node2.childForFieldName("function");
|
|
86185
86466
|
if (!fn)
|
|
@@ -87539,8 +87820,8 @@ var init_test_empty_file = __esm({
|
|
|
87539
87820
|
nodeTypes: ["program"],
|
|
87540
87821
|
visit(node2, filePath, sourceCode) {
|
|
87541
87822
|
const lowerPath = filePath.toLowerCase();
|
|
87542
|
-
const
|
|
87543
|
-
if (!
|
|
87823
|
+
const isTestFile6 = lowerPath.includes(".test.") || lowerPath.includes(".spec.") || lowerPath.includes("__tests__");
|
|
87824
|
+
if (!isTestFile6)
|
|
87544
87825
|
return null;
|
|
87545
87826
|
if (hasTestFunction(node2))
|
|
87546
87827
|
return null;
|
|
@@ -91246,7 +91527,7 @@ var init_javascript5 = __esm({
|
|
|
91246
91527
|
init_useless_computed_key();
|
|
91247
91528
|
init_useless_concat();
|
|
91248
91529
|
init_strict_equality();
|
|
91249
|
-
|
|
91530
|
+
init_commented_out_code2();
|
|
91250
91531
|
init_inverted_boolean();
|
|
91251
91532
|
init_prefer_single_boolean_return();
|
|
91252
91533
|
init_prefer_immediate_return();
|
|
@@ -92413,30 +92694,27 @@ var init_unused_variable2 = __esm({
|
|
|
92413
92694
|
});
|
|
92414
92695
|
|
|
92415
92696
|
// packages/analyzer/dist/rules/code-quality/visitors/python/commented-out-code.js
|
|
92416
|
-
var pythonCommentedOutCodeVisitor;
|
|
92417
|
-
var
|
|
92697
|
+
var isLineComment2, pythonCommentedOutCodeVisitor;
|
|
92698
|
+
var init_commented_out_code3 = __esm({
|
|
92418
92699
|
"packages/analyzer/dist/rules/code-quality/visitors/python/commented-out-code.js"() {
|
|
92419
92700
|
"use strict";
|
|
92420
92701
|
init_types2();
|
|
92702
|
+
init_commented_out_code();
|
|
92703
|
+
isLineComment2 = (t2) => t2.startsWith("#");
|
|
92421
92704
|
pythonCommentedOutCodeVisitor = {
|
|
92422
92705
|
ruleKey: "code-quality/deterministic/commented-out-code",
|
|
92423
92706
|
languages: ["python"],
|
|
92424
92707
|
nodeTypes: ["comment"],
|
|
92425
92708
|
visit(node2, filePath, sourceCode) {
|
|
92426
92709
|
const text4 = node2.text;
|
|
92427
|
-
if (!text4
|
|
92710
|
+
if (!isLineComment2(text4))
|
|
92428
92711
|
return null;
|
|
92429
|
-
const inner =
|
|
92430
|
-
if (inner
|
|
92712
|
+
const inner = lineCommentRunInner(node2, { isLineComment: isLineComment2, strip: (t2) => t2.replace(/^#+/, "") });
|
|
92713
|
+
if (inner === null)
|
|
92431
92714
|
return null;
|
|
92432
|
-
|
|
92433
|
-
|
|
92434
|
-
|
|
92435
|
-
/\w+\(.*\)/,
|
|
92436
|
-
/=\s*\w/
|
|
92437
|
-
];
|
|
92438
|
-
const matchCount = codePatterns.filter((p2) => p2.test(inner)).length;
|
|
92439
|
-
if (matchCount >= 2) {
|
|
92715
|
+
if (inner.trim().length < 10)
|
|
92716
|
+
return null;
|
|
92717
|
+
if (isCommentedOutCode(inner, { colonTerminates: true })) {
|
|
92440
92718
|
return makeViolation(this.ruleKey, node2, filePath, "low", "Commented-out code", "This comment appears to contain commented-out code. Remove it or track it in version control.", sourceCode, "Delete the commented-out code. If needed, it can be recovered from version control.");
|
|
92441
92719
|
}
|
|
92442
92720
|
return null;
|
|
@@ -101429,8 +101707,8 @@ var init_test_not_discoverable = __esm({
|
|
|
101429
101707
|
return null;
|
|
101430
101708
|
const className = classNameNode.text;
|
|
101431
101709
|
const isTestClass = className.startsWith("Test") || className.endsWith("Test") || className.endsWith("Tests");
|
|
101432
|
-
const
|
|
101433
|
-
if (!isTestClass && !
|
|
101710
|
+
const isTestFile6 = isPythonTestFile(filePath);
|
|
101711
|
+
if (!isTestClass && !isTestFile6)
|
|
101434
101712
|
return null;
|
|
101435
101713
|
const body = node2.childForFieldName("body");
|
|
101436
101714
|
if (!body)
|
|
@@ -103199,7 +103477,7 @@ var init_python7 = __esm({
|
|
|
103199
103477
|
init_no_debugger2();
|
|
103200
103478
|
init_require_await2();
|
|
103201
103479
|
init_unused_variable2();
|
|
103202
|
-
|
|
103480
|
+
init_commented_out_code3();
|
|
103203
103481
|
init_abstract_class_without_abstract_method();
|
|
103204
103482
|
init_and_or_ternary();
|
|
103205
103483
|
init_assert_in_production();
|
|
@@ -105147,7 +105425,12 @@ var init_result = __esm({
|
|
|
105147
105425
|
durationMs: external_exports.number().nonnegative(),
|
|
105148
105426
|
/** Present on `fail` / `error`. */
|
|
105149
105427
|
failure: GuardFailureDetailSchema.optional(),
|
|
105150
|
-
/**
|
|
105428
|
+
/**
|
|
105429
|
+
* Repo-relative pointer into `evidence/`; present on every EXECUTED outcome —
|
|
105430
|
+
* `pass` (the run transcript proving what ran) as well as `fail` / `error`.
|
|
105431
|
+
* Absent on non-executed `stale` / `orphaned`, and on pre-2026-07-08 runs whose
|
|
105432
|
+
* passes were never given a bundle (optional keeps those parsing + rendering).
|
|
105433
|
+
*/
|
|
105151
105434
|
evidencePath: external_exports.string().optional(),
|
|
105152
105435
|
/**
|
|
105153
105436
|
* Present when the bound section moved: the section kept its text but now
|
|
@@ -105725,7 +106008,18 @@ function withLanguageSupport(rules, visitors) {
|
|
|
105725
106008
|
continue;
|
|
105726
106009
|
}
|
|
105727
106010
|
if (rule.engine === "roslyn-host" || rule.engine === "roslyn-workspace") {
|
|
105728
|
-
|
|
106011
|
+
if (language === "csharp") {
|
|
106012
|
+
support[language] = { status: "supported" };
|
|
106013
|
+
continue;
|
|
106014
|
+
}
|
|
106015
|
+
const hasExplicitForLang = explicitFamilies.get(rule.key)?.has(language) ?? false;
|
|
106016
|
+
const universalExcludesLang2 = universalExcludedFamilies.get(rule.key)?.has(language) ?? false;
|
|
106017
|
+
const hasUniversalForLang = universalRuleKeys.has(rule.key) && UNIVERSAL_VISITOR_FAMILIES.includes(language) && !universalExcludesLang2;
|
|
106018
|
+
if (hasExplicitForLang || hasUniversalForLang) {
|
|
106019
|
+
support[language] = { status: "supported" };
|
|
106020
|
+
continue;
|
|
106021
|
+
}
|
|
106022
|
+
support[language] = { status: "not-applicable", reason: "C# semantic rule (Roslyn host); no equivalent in this language" };
|
|
105729
106023
|
continue;
|
|
105730
106024
|
}
|
|
105731
106025
|
const hasExplicit = explicitFamilies.get(rule.key)?.has(language) ?? false;
|
|
@@ -114484,6 +114778,12 @@ function walkCSharp(node2, visit) {
|
|
|
114484
114778
|
walkCSharp(child, visit);
|
|
114485
114779
|
}
|
|
114486
114780
|
}
|
|
114781
|
+
function isCSharpTestPath(filePath) {
|
|
114782
|
+
return filePath.split(/[\\/]/).some((segment) => {
|
|
114783
|
+
const s = segment.toLowerCase();
|
|
114784
|
+
return /\.tests?$/.test(s) || s.endsWith(".testbase") || s.endsWith("testapp");
|
|
114785
|
+
});
|
|
114786
|
+
}
|
|
114487
114787
|
var FUNCTION_BOUNDARY_TYPES;
|
|
114488
114788
|
var init_csharp_helpers = __esm({
|
|
114489
114789
|
"packages/analyzer/dist/rules/_shared/csharp-helpers.js"() {
|
|
@@ -115898,7 +116198,7 @@ function isTypeConstantAccess(node2) {
|
|
|
115898
116198
|
const receiver = lastSegment(node2.childForFieldName("expression")?.text ?? "");
|
|
115899
116199
|
return /^[A-Z]/.test(receiver);
|
|
115900
116200
|
}
|
|
115901
|
-
function
|
|
116201
|
+
function leafName2(node2) {
|
|
115902
116202
|
if (node2.type === "identifier")
|
|
115903
116203
|
return node2.text;
|
|
115904
116204
|
if (node2.type === "member_access_expression")
|
|
@@ -115934,8 +116234,8 @@ var init_timing_attack_comparison2 = __esm({
|
|
|
115934
116234
|
return null;
|
|
115935
116235
|
if (isTypeConstantAccess(left) || isTypeConstantAccess(right))
|
|
115936
116236
|
return null;
|
|
115937
|
-
const leftLeaf =
|
|
115938
|
-
const rightLeaf =
|
|
116237
|
+
const leftLeaf = leafName2(left);
|
|
116238
|
+
const rightLeaf = leafName2(right);
|
|
115939
116239
|
if (leftLeaf === "Length" || rightLeaf === "Length")
|
|
115940
116240
|
return null;
|
|
115941
116241
|
if (ENUM_CONSTANT_PATTERN2.test(leftLeaf) || ENUM_CONSTANT_PATTERN2.test(rightLeaf))
|
|
@@ -115954,7 +116254,7 @@ var init_timing_attack_comparison2 = __esm({
|
|
|
115954
116254
|
});
|
|
115955
116255
|
|
|
115956
116256
|
// packages/analyzer/dist/rules/security/visitors/csharp/insecure-random.js
|
|
115957
|
-
function
|
|
116257
|
+
function isTestFile2(filePath) {
|
|
115958
116258
|
const fileName = filePath.replace(/^.*[\\/]/, "");
|
|
115959
116259
|
return /Tests?\.cs$/i.test(fileName) || /(?:TestSetup|TestFixture|Fixtures?|FunctionalTests|IntegrationTests|UnitTests|TestHelpers?)/.test(fileName);
|
|
115960
116260
|
}
|
|
@@ -115996,7 +116296,7 @@ var init_insecure_random3 = __esm({
|
|
|
115996
116296
|
languages: ["csharp"],
|
|
115997
116297
|
nodeTypes: ["object_creation_expression", "member_access_expression"],
|
|
115998
116298
|
visit(node2, filePath, sourceCode) {
|
|
115999
|
-
if (
|
|
116299
|
+
if (isTestFile2(filePath))
|
|
116000
116300
|
return null;
|
|
116001
116301
|
if (node2.type === "object_creation_expression") {
|
|
116002
116302
|
if (getCreatedTypeName(node2) !== "Random")
|
|
@@ -118467,11 +118767,14 @@ var init_empty_catch3 = __esm({
|
|
|
118467
118767
|
const stmt = tryStatements[0];
|
|
118468
118768
|
if (/\b(Parse|TryParse|Deserialize)\s*[<(]/.test(stmt.text))
|
|
118469
118769
|
return null;
|
|
118470
|
-
|
|
118471
|
-
if (expr?.type === "
|
|
118770
|
+
let expr = stmt.namedChildren[0];
|
|
118771
|
+
if (expr?.type === "await_expression")
|
|
118772
|
+
expr = expr.namedChildren[0];
|
|
118773
|
+
const isBestEffort = (name) => BEST_EFFORT_METHODS.has(name.replace(/Async$/, ""));
|
|
118774
|
+
if (expr?.type === "invocation_expression" && isBestEffort(getCSharpMethodName(expr))) {
|
|
118472
118775
|
return null;
|
|
118473
118776
|
}
|
|
118474
|
-
if (expr?.type === "conditional_access_expression" &&
|
|
118777
|
+
if (expr?.type === "conditional_access_expression" && isBestEffort((expr.text.match(/\.(\w+)\s*\([^()]*\)\s*$/) ?? [])[1] ?? "")) {
|
|
118475
118778
|
return null;
|
|
118476
118779
|
}
|
|
118477
118780
|
}
|
|
@@ -118535,6 +118838,8 @@ var init_self_assignment3 = __esm({
|
|
|
118535
118838
|
languages: ["csharp"],
|
|
118536
118839
|
nodeTypes: ["assignment_expression"],
|
|
118537
118840
|
visit(node2, filePath, sourceCode) {
|
|
118841
|
+
if (node2.parent?.type === "initializer_expression")
|
|
118842
|
+
return null;
|
|
118538
118843
|
const left = node2.childForFieldName("left");
|
|
118539
118844
|
const right = node2.childForFieldName("right");
|
|
118540
118845
|
const operator = node2.childForFieldName("operator");
|
|
@@ -119542,7 +119847,7 @@ var init_infinite_recursion2 = __esm({
|
|
|
119542
119847
|
return null;
|
|
119543
119848
|
if (node2.type === "property_declaration") {
|
|
119544
119849
|
const arrow = node2.childForFieldName("value");
|
|
119545
|
-
const arrowExpr = arrow?.namedChildren[0];
|
|
119850
|
+
const arrowExpr = arrow?.type === "arrow_expression_clause" ? arrow.namedChildren[0] : null;
|
|
119546
119851
|
if (arrowExpr?.type === "identifier" && arrowExpr.text === name) {
|
|
119547
119852
|
return makeViolation(this.ruleKey, node2, filePath, "critical", "Infinite recursion", `Property \`${name}\` returns itself \u2014 reading it recurses until StackOverflowException.`, sourceCode, "Return the backing field (or use an auto-property) instead of the property itself.");
|
|
119548
119853
|
}
|
|
@@ -121607,8 +121912,11 @@ var init_useless_finally2 = __esm({
|
|
|
121607
121912
|
});
|
|
121608
121913
|
|
|
121609
121914
|
// packages/analyzer/dist/rules/bugs/visitors/csharp/fstring-missing-placeholders.js
|
|
121610
|
-
function
|
|
121611
|
-
|
|
121915
|
+
function hasRealHole(node2) {
|
|
121916
|
+
if (node2.namedChildren.some((c2) => c2?.type === "interpolation"))
|
|
121917
|
+
return true;
|
|
121918
|
+
const stripped = node2.text.replace(/\{\{/g, "").replace(/\}\}/g, "");
|
|
121919
|
+
return stripped.includes("{");
|
|
121612
121920
|
}
|
|
121613
121921
|
var csharpFstringMissingPlaceholdersVisitor;
|
|
121614
121922
|
var init_fstring_missing_placeholders2 = __esm({
|
|
@@ -121620,7 +121928,7 @@ var init_fstring_missing_placeholders2 = __esm({
|
|
|
121620
121928
|
languages: ["csharp"],
|
|
121621
121929
|
nodeTypes: ["interpolated_string_expression"],
|
|
121622
121930
|
visit(node2, filePath, sourceCode) {
|
|
121623
|
-
if (
|
|
121931
|
+
if (hasRealHole(node2))
|
|
121624
121932
|
return null;
|
|
121625
121933
|
let top = node2;
|
|
121626
121934
|
while (top.parent?.type === "binary_expression" && top.parent.childForFieldName("operator")?.text === "+") {
|
|
@@ -121631,7 +121939,7 @@ var init_fstring_missing_placeholders2 = __esm({
|
|
|
121631
121939
|
const walk20 = (n) => {
|
|
121632
121940
|
if (siblingHasHoles)
|
|
121633
121941
|
return;
|
|
121634
|
-
if (n.type === "interpolated_string_expression" && n.id !== node2.id &&
|
|
121942
|
+
if (n.type === "interpolated_string_expression" && n.id !== node2.id && hasRealHole(n)) {
|
|
121635
121943
|
siblingHasHoles = true;
|
|
121636
121944
|
return;
|
|
121637
121945
|
}
|
|
@@ -123111,6 +123419,32 @@ var init_chained_orderby_loses_ordering = __esm({
|
|
|
123111
123419
|
});
|
|
123112
123420
|
|
|
123113
123421
|
// packages/analyzer/dist/rules/bugs/visitors/csharp/check-against-value-being-assigned.js
|
|
123422
|
+
function enclosingTypeDecl(node2) {
|
|
123423
|
+
let p2 = node2.parent;
|
|
123424
|
+
while (p2) {
|
|
123425
|
+
if (p2.type === "class_declaration" || p2.type === "struct_declaration" || p2.type === "record_declaration") {
|
|
123426
|
+
return p2;
|
|
123427
|
+
}
|
|
123428
|
+
p2 = p2.parent;
|
|
123429
|
+
}
|
|
123430
|
+
return null;
|
|
123431
|
+
}
|
|
123432
|
+
function selfMemberName(target) {
|
|
123433
|
+
if (target.type === "identifier")
|
|
123434
|
+
return target.text;
|
|
123435
|
+
if (target.type === "member_access_expression") {
|
|
123436
|
+
const obj = target.childForFieldName("expression");
|
|
123437
|
+
if (obj?.type === "this")
|
|
123438
|
+
return target.childForFieldName("name")?.text ?? null;
|
|
123439
|
+
}
|
|
123440
|
+
return null;
|
|
123441
|
+
}
|
|
123442
|
+
function enclosingTypeHasProperty(typeDecl, name) {
|
|
123443
|
+
const body = typeDecl.childForFieldName("body") ?? typeDecl.namedChildren.find((c2) => c2?.type === "declaration_list");
|
|
123444
|
+
if (!body)
|
|
123445
|
+
return false;
|
|
123446
|
+
return body.namedChildren.some((m) => m?.type === "property_declaration" && m.childForFieldName("name")?.text === name);
|
|
123447
|
+
}
|
|
123114
123448
|
function singleStatement(consequence) {
|
|
123115
123449
|
if (consequence.type === "block") {
|
|
123116
123450
|
const stmts = consequence.namedChildren.filter((c2) => c2?.type !== "comment");
|
|
@@ -123158,6 +123492,12 @@ var init_check_against_value_being_assigned = __esm({
|
|
|
123158
123492
|
const sameBA = condLeft.text === value.text && condRight.text === target.text;
|
|
123159
123493
|
if (!sameAB && !sameBA)
|
|
123160
123494
|
return null;
|
|
123495
|
+
const selfName = selfMemberName(target);
|
|
123496
|
+
if (selfName) {
|
|
123497
|
+
const typeDecl = enclosingTypeDecl(node2);
|
|
123498
|
+
if (typeDecl && enclosingTypeHasProperty(typeDecl, selfName))
|
|
123499
|
+
return null;
|
|
123500
|
+
}
|
|
123161
123501
|
return makeViolation(this.ruleKey, node2, filePath, "low", "Redundant check against the value being assigned", `\`if (${condition.text}) ${assign.text};\` guards a plain assignment with a check against the same value \u2014 assigning unconditionally has the identical effect.`, sourceCode, "Remove the guard and assign unconditionally, or fix the condition if a different check was intended.");
|
|
123162
123502
|
}
|
|
123163
123503
|
};
|
|
@@ -123647,7 +123987,8 @@ var init_redundant_base_call = __esm({
|
|
|
123647
123987
|
const receiver = node2.childForFieldName("expression");
|
|
123648
123988
|
if (receiver?.type !== "base" && receiver?.text !== "base")
|
|
123649
123989
|
return null;
|
|
123650
|
-
const
|
|
123990
|
+
const nameNode = node2.childForFieldName("name");
|
|
123991
|
+
const memberName3 = nameNode?.type === "generic_name" ? nameNode.namedChildren.find((c2) => c2?.type === "identifier")?.text : nameNode?.text;
|
|
123651
123992
|
if (!memberName3)
|
|
123652
123993
|
return null;
|
|
123653
123994
|
const typeDecl = enclosingType(node2);
|
|
@@ -123982,6 +124323,19 @@ function baseEntryName(entry) {
|
|
|
123982
124323
|
}
|
|
123983
124324
|
return null;
|
|
123984
124325
|
}
|
|
124326
|
+
function baseEntryArity(entry) {
|
|
124327
|
+
const generic = entry.type === "generic_name" ? entry : entry.type === "qualified_name" ? entry.childForFieldName("name") : null;
|
|
124328
|
+
if (generic?.type !== "generic_name")
|
|
124329
|
+
return 0;
|
|
124330
|
+
const args = generic.namedChildren.find((c2) => c2?.type === "type_argument_list");
|
|
124331
|
+
return args ? args.namedChildren.filter((c2) => c2 != null).length : 0;
|
|
124332
|
+
}
|
|
124333
|
+
function declaredArity(node2) {
|
|
124334
|
+
const params = node2.childForFieldName("type_parameters");
|
|
124335
|
+
if (!params)
|
|
124336
|
+
return 0;
|
|
124337
|
+
return params.namedChildren.filter((c2) => c2?.type === "type_parameter").length;
|
|
124338
|
+
}
|
|
123985
124339
|
var csharpRecursiveTypeInheritanceVisitor;
|
|
123986
124340
|
var init_recursive_type_inheritance = __esm({
|
|
123987
124341
|
"packages/analyzer/dist/rules/bugs/visitors/csharp/recursive-type-inheritance.js"() {
|
|
@@ -124003,6 +124357,8 @@ var init_recursive_type_inheritance = __esm({
|
|
|
124003
124357
|
return null;
|
|
124004
124358
|
if (baseEntryName(firstBase) !== typeName2)
|
|
124005
124359
|
return null;
|
|
124360
|
+
if (baseEntryArity(firstBase) !== declaredArity(node2))
|
|
124361
|
+
return null;
|
|
124006
124362
|
return makeViolation(this.ruleKey, firstBase, filePath, "high", "Recursive type inheritance", `\`${typeName2}\` lists itself as its own base type, producing a nonsensical recursive inheritance chain.`, sourceCode, "Remove the self reference from the base list.");
|
|
124007
124363
|
}
|
|
124008
124364
|
};
|
|
@@ -126230,6 +126586,20 @@ function isCSharpGeneratedSource(filePath, sourceCode) {
|
|
|
126230
126586
|
return true;
|
|
126231
126587
|
return sourceCode.slice(0, 600).includes("<auto-generated");
|
|
126232
126588
|
}
|
|
126589
|
+
function isCSharpEfMigration(node2) {
|
|
126590
|
+
const cls = getCSharpEnclosingClass(node2);
|
|
126591
|
+
if (!cls)
|
|
126592
|
+
return false;
|
|
126593
|
+
const baseList = cls.namedChildren.find((c2) => c2?.type === "base_list");
|
|
126594
|
+
if (!baseList)
|
|
126595
|
+
return false;
|
|
126596
|
+
return baseList.namedChildren.some((base2) => {
|
|
126597
|
+
if (!base2)
|
|
126598
|
+
return false;
|
|
126599
|
+
const simple = base2.text.split(".").pop() ?? base2.text;
|
|
126600
|
+
return simple === "Migration";
|
|
126601
|
+
});
|
|
126602
|
+
}
|
|
126233
126603
|
function isCSharpPrivateMember(node2) {
|
|
126234
126604
|
const accessibility = [];
|
|
126235
126605
|
for (const child of node2.children) {
|
|
@@ -128793,17 +129163,13 @@ var init_collapsible_if3 = __esm({
|
|
|
128793
129163
|
});
|
|
128794
129164
|
|
|
128795
129165
|
// packages/analyzer/dist/rules/code-quality/visitors/csharp/commented-out-code.js
|
|
128796
|
-
var
|
|
128797
|
-
var
|
|
129166
|
+
var isLineComment3, csharpCommentedOutCodeVisitor;
|
|
129167
|
+
var init_commented_out_code4 = __esm({
|
|
128798
129168
|
"packages/analyzer/dist/rules/code-quality/visitors/csharp/commented-out-code.js"() {
|
|
128799
129169
|
"use strict";
|
|
128800
129170
|
init_types2();
|
|
128801
|
-
|
|
128802
|
-
|
|
128803
|
-
/[;{}]\s*$/,
|
|
128804
|
-
/=>/,
|
|
128805
|
-
/\w+\(.*\)\s*[;{]?\s*$/
|
|
128806
|
-
];
|
|
129171
|
+
init_commented_out_code();
|
|
129172
|
+
isLineComment3 = (t2) => t2.startsWith("//") && !t2.startsWith("///");
|
|
128807
129173
|
csharpCommentedOutCodeVisitor = {
|
|
128808
129174
|
ruleKey: "code-quality/deterministic/commented-out-code",
|
|
128809
129175
|
languages: ["csharp"],
|
|
@@ -128812,15 +129178,19 @@ var init_commented_out_code3 = __esm({
|
|
|
128812
129178
|
const text4 = node2.text;
|
|
128813
129179
|
if (text4.startsWith("///") || text4.startsWith("/**"))
|
|
128814
129180
|
return null;
|
|
128815
|
-
let inner
|
|
128816
|
-
if (
|
|
128817
|
-
inner =
|
|
128818
|
-
|
|
128819
|
-
|
|
128820
|
-
if (
|
|
129181
|
+
let inner;
|
|
129182
|
+
if (isLineComment3(text4)) {
|
|
129183
|
+
inner = lineCommentRunInner(node2, { isLineComment: isLineComment3, strip: (t2) => t2.replace(/^\/\/+/, "") });
|
|
129184
|
+
if (inner === null)
|
|
129185
|
+
return null;
|
|
129186
|
+
} else if (text4.startsWith("/*")) {
|
|
129187
|
+
inner = text4.slice(2, -2);
|
|
129188
|
+
} else {
|
|
128821
129189
|
return null;
|
|
128822
|
-
|
|
128823
|
-
if (
|
|
129190
|
+
}
|
|
129191
|
+
if (inner.trim().length < 10)
|
|
129192
|
+
return null;
|
|
129193
|
+
if (isCommentedOutCode(inner, {})) {
|
|
128824
129194
|
return makeViolation(this.ruleKey, node2, filePath, "low", "Commented-out code", "This comment appears to contain commented-out code. Remove it or track it in version control.", sourceCode, "Delete the commented-out code. If needed, it can be recovered from version control.");
|
|
128825
129195
|
}
|
|
128826
129196
|
return null;
|
|
@@ -129528,6 +129898,13 @@ function csharpEmptyBodyIsIntentional(node2, body) {
|
|
|
129528
129898
|
}
|
|
129529
129899
|
if (isCSharpNoOpCallbackPosition(node2))
|
|
129530
129900
|
return true;
|
|
129901
|
+
let enclosingType3 = node2.parent;
|
|
129902
|
+
while (enclosingType3 && enclosingType3.type !== "class_declaration" && enclosingType3.type !== "struct_declaration" && enclosingType3.type !== "record_declaration" && enclosingType3.type !== "record_struct_declaration") {
|
|
129903
|
+
enclosingType3 = enclosingType3.parent;
|
|
129904
|
+
}
|
|
129905
|
+
const typeName2 = enclosingType3?.childForFieldName("name")?.text;
|
|
129906
|
+
if (typeName2 && /^(Null|Noop|NoOp|Empty)[A-Z0-9]/.test(typeName2))
|
|
129907
|
+
return true;
|
|
129531
129908
|
if (node2.type === "method_declaration") {
|
|
129532
129909
|
if (hasCSharpModifier(node2, "virtual") || hasCSharpModifier(node2, "override") || hasCSharpModifier(node2, "partial"))
|
|
129533
129910
|
return true;
|
|
@@ -129805,6 +130182,7 @@ var init_hardcoded_url2 = __esm({
|
|
|
129805
130182
|
"packages/analyzer/dist/rules/code-quality/visitors/csharp/hardcoded-url.js"() {
|
|
129806
130183
|
"use strict";
|
|
129807
130184
|
init_types2();
|
|
130185
|
+
init_csharp_helpers();
|
|
129808
130186
|
NAMESPACE_URI_HOSTS = /w3\.org|schema\.org|xmlns|openxmlformats|xmlsoap|purl\.org|tempuri\.org|schemas\.microsoft\.com|tools\.ietf\.org|datatracker\.ietf\.org|rfc-editor\.org/;
|
|
129809
130187
|
STABLE_API_HOSTS = /googleapis\.com|maps\.google|api\.stripe\.com|api\.twilio\.com|api\.sendgrid\.com|api\.github\.com|cdn\.|fonts\.googleapis|cloudflare|unpkg\.com|cdnjs\.cloudflare|jsdelivr\.net|nuget\.org/;
|
|
129810
130188
|
PLACEHOLDER_NAME = /default|placeholder|example|sample|template|fallback|demo|test|mock|stub|dummy/;
|
|
@@ -129816,6 +130194,8 @@ var init_hardcoded_url2 = __esm({
|
|
|
129816
130194
|
const text4 = node2.text;
|
|
129817
130195
|
if (!/https?:\/\/[a-zA-Z0-9]/.test(text4))
|
|
129818
130196
|
return null;
|
|
130197
|
+
if (isCSharpTestPath(filePath))
|
|
130198
|
+
return null;
|
|
129819
130199
|
if (text4.includes("example.com") || text4.includes("localhost") || text4.includes("127.0.0.1") || text4.includes("placeholder"))
|
|
129820
130200
|
return null;
|
|
129821
130201
|
if (NAMESPACE_URI_HOSTS.test(text4))
|
|
@@ -129836,6 +130216,42 @@ var init_hardcoded_url2 = __esm({
|
|
|
129836
130216
|
});
|
|
129837
130217
|
|
|
129838
130218
|
// packages/analyzer/dist/rules/code-quality/visitors/csharp/identical-functions.js
|
|
130219
|
+
function isTrivialExpr(e) {
|
|
130220
|
+
switch (e.type) {
|
|
130221
|
+
case "integer_literal":
|
|
130222
|
+
case "real_literal":
|
|
130223
|
+
case "boolean_literal":
|
|
130224
|
+
case "string_literal":
|
|
130225
|
+
case "verbatim_string_literal":
|
|
130226
|
+
case "null_literal":
|
|
130227
|
+
case "character_literal":
|
|
130228
|
+
case "identifier":
|
|
130229
|
+
case "this_expression":
|
|
130230
|
+
case "default_expression":
|
|
130231
|
+
case "member_access_expression":
|
|
130232
|
+
return true;
|
|
130233
|
+
case "invocation_expression": {
|
|
130234
|
+
const args = e.childForFieldName("arguments");
|
|
130235
|
+
if (!args)
|
|
130236
|
+
return true;
|
|
130237
|
+
return args.namedChildren.every((a) => {
|
|
130238
|
+
if (a?.type !== "argument")
|
|
130239
|
+
return true;
|
|
130240
|
+
const value = a.namedChildren.find((c2) => c2 && c2.type !== "name_colon");
|
|
130241
|
+
return !value || isTrivialExpr(value);
|
|
130242
|
+
});
|
|
130243
|
+
}
|
|
130244
|
+
default:
|
|
130245
|
+
return false;
|
|
130246
|
+
}
|
|
130247
|
+
}
|
|
130248
|
+
function isTrivialReturnBody(body) {
|
|
130249
|
+
const stmts = body.namedChildren.filter((c2) => c2 && c2.type !== "comment");
|
|
130250
|
+
if (stmts.length !== 1 || stmts[0]?.type !== "return_statement")
|
|
130251
|
+
return false;
|
|
130252
|
+
const expr = stmts[0].namedChildren.find((c2) => c2 && c2.type !== "comment");
|
|
130253
|
+
return !expr || isTrivialExpr(expr);
|
|
130254
|
+
}
|
|
129839
130255
|
var COMPARED_TYPES, csharpIdenticalFunctionsVisitor;
|
|
129840
130256
|
var init_identical_functions2 = __esm({
|
|
129841
130257
|
"packages/analyzer/dist/rules/code-quality/visitors/csharp/identical-functions.js"() {
|
|
@@ -129854,7 +130270,7 @@ var init_identical_functions2 = __esm({
|
|
|
129854
130270
|
const body = n.childForFieldName("body");
|
|
129855
130271
|
if (body && body.type === "block" && body.namedChildCount > 0) {
|
|
129856
130272
|
const onlyThrow = body.namedChildCount === 1 && body.namedChildren[0]?.type === "throw_statement";
|
|
129857
|
-
if (!onlyThrow) {
|
|
130273
|
+
if (!onlyThrow && !isTrivialReturnBody(body)) {
|
|
129858
130274
|
const normalized = body.text.replace(/\s+/g, " ").trim();
|
|
129859
130275
|
bodies.push({ body: normalized, fnNode: n });
|
|
129860
130276
|
}
|
|
@@ -130044,6 +130460,8 @@ var init_magic_number2 = __esm({
|
|
|
130044
130460
|
return null;
|
|
130045
130461
|
if (parentType === "argument" && parent.parent?.type === "bracketed_argument_list")
|
|
130046
130462
|
return null;
|
|
130463
|
+
if (parentType === "argument" && parent.childForFieldName("name"))
|
|
130464
|
+
return null;
|
|
130047
130465
|
if (parentType === "binary_expression" && TIME_FACTORS2.has(val)) {
|
|
130048
130466
|
const op = parent.childForFieldName("operator");
|
|
130049
130467
|
if (op?.text === "*") {
|
|
@@ -130365,6 +130783,8 @@ var init_no_extraneous_class2 = __esm({
|
|
|
130365
130783
|
return null;
|
|
130366
130784
|
if (node2.namedChildren.some((c2) => c2?.type === "base_list"))
|
|
130367
130785
|
return null;
|
|
130786
|
+
if (node2.namedChildren.some((c2) => c2?.type === "attribute_list"))
|
|
130787
|
+
return null;
|
|
130368
130788
|
const body = node2.childForFieldName("body");
|
|
130369
130789
|
if (!body)
|
|
130370
130790
|
return null;
|
|
@@ -130623,7 +131043,8 @@ var init_redundant_jump3 = __esm({
|
|
|
130623
131043
|
if (!grandparent)
|
|
130624
131044
|
return null;
|
|
130625
131045
|
if (node2.type === "return_statement") {
|
|
130626
|
-
|
|
131046
|
+
const hasExpression = node2.children.some((c2) => c2 != null && c2.type !== "return" && c2.type !== ";");
|
|
131047
|
+
if (hasExpression)
|
|
130627
131048
|
return null;
|
|
130628
131049
|
if (!isCSharpFunctionBoundary(grandparent.type))
|
|
130629
131050
|
return null;
|
|
@@ -131988,6 +132409,8 @@ var init_too_many_lines3 = __esm({
|
|
|
131988
132409
|
const bodyNode = getCSharpFunctionBody(node2);
|
|
131989
132410
|
if (!bodyNode)
|
|
131990
132411
|
return null;
|
|
132412
|
+
if (isCSharpGeneratedSource(filePath, sourceCode) || isCSharpEfMigration(node2))
|
|
132413
|
+
return null;
|
|
131991
132414
|
const lineCount = bodyNode.endPosition.row - bodyNode.startPosition.row + 1;
|
|
131992
132415
|
if (lineCount > 50) {
|
|
131993
132416
|
const name = getCSharpFunctionName(node2);
|
|
@@ -132635,93 +133058,6 @@ var init_unused_collection2 = __esm({
|
|
|
132635
133058
|
}
|
|
132636
133059
|
});
|
|
132637
133060
|
|
|
132638
|
-
// packages/analyzer/dist/rules/code-quality/visitors/csharp/unused-function-parameter.js
|
|
132639
|
-
var csharpUnusedFunctionParameterVisitor;
|
|
132640
|
-
var init_unused_function_parameter2 = __esm({
|
|
132641
|
-
"packages/analyzer/dist/rules/code-quality/visitors/csharp/unused-function-parameter.js"() {
|
|
132642
|
-
"use strict";
|
|
132643
|
-
init_types2();
|
|
132644
|
-
init_csharp_helpers();
|
|
132645
|
-
csharpUnusedFunctionParameterVisitor = {
|
|
132646
|
-
ruleKey: "code-quality/deterministic/unused-function-parameter",
|
|
132647
|
-
languages: ["csharp"],
|
|
132648
|
-
nodeTypes: ["method_declaration", "constructor_declaration", "local_function_statement"],
|
|
132649
|
-
visit(node2, filePath, sourceCode) {
|
|
132650
|
-
const params = node2.childForFieldName("parameters");
|
|
132651
|
-
if (!params || params.namedChildCount === 0)
|
|
132652
|
-
return null;
|
|
132653
|
-
const body = node2.childForFieldName("body");
|
|
132654
|
-
if (!body)
|
|
132655
|
-
return null;
|
|
132656
|
-
if (body.type === "block" && body.namedChildCount === 0)
|
|
132657
|
-
return null;
|
|
132658
|
-
if (/NotImplementedException|NotSupportedException/.test(body.text))
|
|
132659
|
-
return null;
|
|
132660
|
-
if (body.type === "block" && body.namedChildCount === 1 && body.namedChildren[0]?.type === "return_statement" && /Task\.CompletedTask|Task\.FromResult|ValueTask\.CompletedTask/.test(body.namedChildren[0].text)) {
|
|
132661
|
-
return null;
|
|
132662
|
-
}
|
|
132663
|
-
if (node2.type === "method_declaration") {
|
|
132664
|
-
for (const mod of ["override", "virtual", "abstract", "partial", "extern"]) {
|
|
132665
|
-
if (hasCSharpModifier(node2, mod))
|
|
132666
|
-
return null;
|
|
132667
|
-
}
|
|
132668
|
-
if (node2.namedChildren.some((c2) => c2?.type === "explicit_interface_specifier"))
|
|
132669
|
-
return null;
|
|
132670
|
-
if (node2.childForFieldName("name")?.text === "Main")
|
|
132671
|
-
return null;
|
|
132672
|
-
}
|
|
132673
|
-
const paramList = [];
|
|
132674
|
-
for (const param of params.namedChildren) {
|
|
132675
|
-
if (!param || param.type !== "parameter")
|
|
132676
|
-
continue;
|
|
132677
|
-
if (param.children.some((c2) => c2?.type === "this" || c2?.type === "modifier" && c2.text === "this"))
|
|
132678
|
-
continue;
|
|
132679
|
-
if (param.childForFieldName("type")?.text === "CancellationToken")
|
|
132680
|
-
continue;
|
|
132681
|
-
const nameNode = param.childForFieldName("name");
|
|
132682
|
-
if (nameNode?.type === "identifier")
|
|
132683
|
-
paramList.push({ name: nameNode.text, node: param });
|
|
132684
|
-
}
|
|
132685
|
-
if (paramList.length === 0)
|
|
132686
|
-
return null;
|
|
132687
|
-
if (paramList.length === 2) {
|
|
132688
|
-
const first2 = params.namedChildren.find((c2) => c2?.type === "parameter");
|
|
132689
|
-
const firstType = first2?.childForFieldName("type")?.text;
|
|
132690
|
-
const secondType = paramList[1] ? paramList[1].node.childForFieldName("type")?.text : void 0;
|
|
132691
|
-
if ((firstType === "object" || firstType === "object?") && secondType?.endsWith("EventArgs"))
|
|
132692
|
-
return null;
|
|
132693
|
-
}
|
|
132694
|
-
const used = /* @__PURE__ */ new Set();
|
|
132695
|
-
function collectReads(n) {
|
|
132696
|
-
if (n.type === "identifier") {
|
|
132697
|
-
const parent = n.parent;
|
|
132698
|
-
const isMemberName = parent && (parent.type === "member_access_expression" || parent.type === "qualified_name" || parent.type === "member_binding_expression") && parent.childForFieldName("name")?.id === n.id;
|
|
132699
|
-
if (!isMemberName)
|
|
132700
|
-
used.add(n.text);
|
|
132701
|
-
}
|
|
132702
|
-
for (let i = 0; i < n.namedChildCount; i++) {
|
|
132703
|
-
const child = n.namedChild(i);
|
|
132704
|
-
if (child)
|
|
132705
|
-
collectReads(child);
|
|
132706
|
-
}
|
|
132707
|
-
}
|
|
132708
|
-
collectReads(body);
|
|
132709
|
-
const initializer = node2.namedChildren.find((c2) => c2?.type === "constructor_initializer");
|
|
132710
|
-
if (initializer)
|
|
132711
|
-
collectReads(initializer);
|
|
132712
|
-
for (const { name, node: paramNode } of paramList) {
|
|
132713
|
-
if (name.startsWith("_"))
|
|
132714
|
-
continue;
|
|
132715
|
-
if (!used.has(name)) {
|
|
132716
|
-
return makeViolation(this.ruleKey, paramNode, filePath, "low", `Unused parameter \`${name}\``, `Parameter \`${name}\` is never used in the method body. Remove it or rename it to \`_\` if the signature is fixed.`, sourceCode, `Remove unused parameter \`${name}\` or rename it to \`_${name}\`.`);
|
|
132717
|
-
}
|
|
132718
|
-
}
|
|
132719
|
-
return null;
|
|
132720
|
-
}
|
|
132721
|
-
};
|
|
132722
|
-
}
|
|
132723
|
-
});
|
|
132724
|
-
|
|
132725
133061
|
// packages/analyzer/dist/rules/code-quality/visitors/csharp/unused-private-member.js
|
|
132726
133062
|
var csharpUnusedPrivateMemberVisitor;
|
|
132727
133063
|
var init_unused_private_member2 = __esm({
|
|
@@ -132746,6 +133082,8 @@ var init_unused_private_member2 = __esm({
|
|
|
132746
133082
|
for (const member of body.namedChildren) {
|
|
132747
133083
|
if (!member)
|
|
132748
133084
|
continue;
|
|
133085
|
+
if (member.namedChildren.some((c2) => c2?.type === "explicit_interface_specifier"))
|
|
133086
|
+
continue;
|
|
132749
133087
|
if (!isCSharpPrivateMember(member))
|
|
132750
133088
|
continue;
|
|
132751
133089
|
if (getCSharpDeclAttributeNames(member).length > 0)
|
|
@@ -133143,8 +133481,17 @@ var init_abstract_class_public_constructor = __esm({
|
|
|
133143
133481
|
});
|
|
133144
133482
|
|
|
133145
133483
|
// packages/analyzer/dist/rules/code-quality/visitors/csharp/abstract-class-without-abstract-members.js
|
|
133146
|
-
function
|
|
133147
|
-
return body.namedChildren.some((c2) => c2 && MEMBER_TYPES2.has(c2.type) && hasCSharpModifier(c2,
|
|
133484
|
+
function hasMemberWithModifier(body, modifier) {
|
|
133485
|
+
return body.namedChildren.some((c2) => c2 != null && MEMBER_TYPES2.has(c2.type) && hasCSharpModifier(c2, modifier));
|
|
133486
|
+
}
|
|
133487
|
+
function hasProtectedConstructor(body) {
|
|
133488
|
+
return body.namedChildren.some((c2) => c2?.type === "constructor_declaration" && hasCSharpModifier(c2, "protected"));
|
|
133489
|
+
}
|
|
133490
|
+
function hasBaseList(classDecl) {
|
|
133491
|
+
return classDecl.namedChildren.some((c2) => c2?.type === "base_list");
|
|
133492
|
+
}
|
|
133493
|
+
function hasExtensionSignal(classDecl, body) {
|
|
133494
|
+
return hasMemberWithModifier(body, "abstract") || hasMemberWithModifier(body, "virtual") || hasMemberWithModifier(body, "override") || hasProtectedConstructor(body) || hasBaseList(classDecl);
|
|
133148
133495
|
}
|
|
133149
133496
|
var MEMBER_TYPES2, csharpAbstractClassWithoutAbstractMembersVisitor;
|
|
133150
133497
|
var init_abstract_class_without_abstract_members = __esm({
|
|
@@ -133156,6 +133503,7 @@ var init_abstract_class_without_abstract_members = __esm({
|
|
|
133156
133503
|
"method_declaration",
|
|
133157
133504
|
"property_declaration",
|
|
133158
133505
|
"event_declaration",
|
|
133506
|
+
"event_field_declaration",
|
|
133159
133507
|
"indexer_declaration"
|
|
133160
133508
|
]);
|
|
133161
133509
|
csharpAbstractClassWithoutAbstractMembersVisitor = {
|
|
@@ -133170,10 +133518,10 @@ var init_abstract_class_without_abstract_members = __esm({
|
|
|
133170
133518
|
const body = node2.childForFieldName("body");
|
|
133171
133519
|
if (!body)
|
|
133172
133520
|
return null;
|
|
133173
|
-
if (
|
|
133521
|
+
if (hasExtensionSignal(node2, body))
|
|
133174
133522
|
return null;
|
|
133175
133523
|
const name = node2.childForFieldName("name")?.text ?? "class";
|
|
133176
|
-
return makeViolation(this.ruleKey, node2, filePath, "low", "Abstract class without abstract members", `Abstract class \`${name}\` declares no abstract members, so it should be a concrete
|
|
133524
|
+
return makeViolation(this.ruleKey, node2, filePath, "low", "Abstract class without abstract members", `Abstract class \`${name}\` declares no abstract members and no other reason to be abstract (no virtual/override member, no protected constructor, no base type), so it should be a concrete class or a static holder instead.`, sourceCode, "Add abstract members, drop the `abstract` modifier, or convert the type to an interface.");
|
|
133177
133525
|
}
|
|
133178
133526
|
};
|
|
133179
133527
|
}
|
|
@@ -134091,6 +134439,8 @@ var init_static_holder_type_has_constructor = __esm({
|
|
|
134091
134439
|
return null;
|
|
134092
134440
|
if (hasCSharpModifier(node2, "abstract"))
|
|
134093
134441
|
return null;
|
|
134442
|
+
if (node2.namedChildren.some((c2) => c2?.type === "base_list"))
|
|
134443
|
+
return null;
|
|
134094
134444
|
const body = node2.namedChildren.find((c2) => c2?.type === "declaration_list");
|
|
134095
134445
|
if (!body)
|
|
134096
134446
|
return null;
|
|
@@ -135974,6 +136324,15 @@ var init_extension_method_on_object = __esm({
|
|
|
135974
136324
|
});
|
|
135975
136325
|
|
|
135976
136326
|
// packages/analyzer/dist/rules/code-quality/visitors/csharp/generic-parameter-not-inferable.js
|
|
136327
|
+
function isInterfaceMember(method) {
|
|
136328
|
+
let current = method.parent;
|
|
136329
|
+
while (current) {
|
|
136330
|
+
if (TYPE_DECL_TYPES2.has(current.type))
|
|
136331
|
+
return current.type === "interface_declaration";
|
|
136332
|
+
current = current.parent;
|
|
136333
|
+
}
|
|
136334
|
+
return false;
|
|
136335
|
+
}
|
|
135977
136336
|
function identifiersIn2(node2) {
|
|
135978
136337
|
const used = /* @__PURE__ */ new Set();
|
|
135979
136338
|
if (!node2)
|
|
@@ -135995,14 +136354,23 @@ function parameterTypeIdentifiers(method) {
|
|
|
135995
136354
|
for (const id of identifiersIn2(param.childForFieldName("type")))
|
|
135996
136355
|
used.add(id);
|
|
135997
136356
|
}
|
|
136357
|
+
for (const id of identifiersIn2(params.childForFieldName("type")))
|
|
136358
|
+
used.add(id);
|
|
135998
136359
|
return used;
|
|
135999
136360
|
}
|
|
136000
|
-
var csharpGenericParameterNotInferableVisitor;
|
|
136361
|
+
var TYPE_DECL_TYPES2, csharpGenericParameterNotInferableVisitor;
|
|
136001
136362
|
var init_generic_parameter_not_inferable = __esm({
|
|
136002
136363
|
"packages/analyzer/dist/rules/code-quality/visitors/csharp/generic-parameter-not-inferable.js"() {
|
|
136003
136364
|
"use strict";
|
|
136004
136365
|
init_types2();
|
|
136005
136366
|
init_csharp_helpers();
|
|
136367
|
+
TYPE_DECL_TYPES2 = /* @__PURE__ */ new Set([
|
|
136368
|
+
"interface_declaration",
|
|
136369
|
+
"class_declaration",
|
|
136370
|
+
"struct_declaration",
|
|
136371
|
+
"record_declaration",
|
|
136372
|
+
"record_struct_declaration"
|
|
136373
|
+
]);
|
|
136006
136374
|
csharpGenericParameterNotInferableVisitor = {
|
|
136007
136375
|
ruleKey: "code-quality/deterministic/generic-parameter-not-inferable",
|
|
136008
136376
|
languages: ["csharp"],
|
|
@@ -136011,6 +136379,8 @@ var init_generic_parameter_not_inferable = __esm({
|
|
|
136011
136379
|
const typeParams = node2.namedChildren.find((c2) => c2?.type === "type_parameter_list");
|
|
136012
136380
|
if (!typeParams)
|
|
136013
136381
|
return null;
|
|
136382
|
+
if (isInterfaceMember(node2))
|
|
136383
|
+
return null;
|
|
136014
136384
|
const usedInParams = parameterTypeIdentifiers(node2);
|
|
136015
136385
|
const nameNode = node2.childForFieldName("name");
|
|
136016
136386
|
const usedInReturn = /* @__PURE__ */ new Set();
|
|
@@ -136022,15 +136392,13 @@ var init_generic_parameter_not_inferable = __esm({
|
|
|
136022
136392
|
for (const id of identifiersIn2(child))
|
|
136023
136393
|
usedInReturn.add(id);
|
|
136024
136394
|
}
|
|
136025
|
-
const usedInBody = identifiersIn2(node2.childForFieldName("body"));
|
|
136026
136395
|
for (const tp of typeParams.namedChildren) {
|
|
136027
136396
|
if (tp?.type !== "type_parameter")
|
|
136028
136397
|
continue;
|
|
136029
136398
|
const name = tp.namedChildren.find((c2) => c2?.type === "identifier")?.text;
|
|
136030
136399
|
if (!name)
|
|
136031
136400
|
continue;
|
|
136032
|
-
|
|
136033
|
-
if (!usedInParams.has(name) && usedElsewhere) {
|
|
136401
|
+
if (!usedInParams.has(name) && usedInReturn.has(name)) {
|
|
136034
136402
|
return makeViolation(this.ruleKey, tp, filePath, "low", "Type parameter not inferable", `Type parameter \`${name}\` appears in no method parameter, so callers must always specify it explicitly.`, sourceCode, `Use \`${name}\` in a parameter type, or accept that callers must specify it and consider a non-generic design.`);
|
|
136035
136403
|
}
|
|
136036
136404
|
}
|
|
@@ -136143,6 +136511,9 @@ var init_native_method_not_wrapped = __esm({
|
|
|
136143
136511
|
});
|
|
136144
136512
|
|
|
136145
136513
|
// packages/analyzer/dist/rules/code-quality/visitors/csharp/nested-generic-parameter.js
|
|
136514
|
+
function genericBaseName2(generic) {
|
|
136515
|
+
return generic.namedChildren.find((c2) => c2?.type === "identifier")?.text ?? "";
|
|
136516
|
+
}
|
|
136146
136517
|
function asGenericName(typeNode) {
|
|
136147
136518
|
if (!typeNode)
|
|
136148
136519
|
return null;
|
|
@@ -136158,16 +136529,19 @@ function hasNestedGeneric(typeNode) {
|
|
|
136158
136529
|
const generic = asGenericName(typeNode);
|
|
136159
136530
|
if (!generic)
|
|
136160
136531
|
return false;
|
|
136532
|
+
if (DELEGATE_OR_EXPRESSION_GENERICS.has(genericBaseName2(generic)))
|
|
136533
|
+
return false;
|
|
136161
136534
|
const args = generic.namedChildren.find((c2) => c2?.type === "type_argument_list");
|
|
136162
136535
|
if (!args)
|
|
136163
136536
|
return false;
|
|
136164
136537
|
return args.namedChildren.some((arg) => asGenericName(arg) !== null);
|
|
136165
136538
|
}
|
|
136166
|
-
var csharpNestedGenericParameterVisitor;
|
|
136539
|
+
var DELEGATE_OR_EXPRESSION_GENERICS, csharpNestedGenericParameterVisitor;
|
|
136167
136540
|
var init_nested_generic_parameter = __esm({
|
|
136168
136541
|
"packages/analyzer/dist/rules/code-quality/visitors/csharp/nested-generic-parameter.js"() {
|
|
136169
136542
|
"use strict";
|
|
136170
136543
|
init_types2();
|
|
136544
|
+
DELEGATE_OR_EXPRESSION_GENERICS = /* @__PURE__ */ new Set(["Func", "Action", "Predicate", "Expression"]);
|
|
136171
136545
|
csharpNestedGenericParameterVisitor = {
|
|
136172
136546
|
ruleKey: "code-quality/deterministic/nested-generic-parameter",
|
|
136173
136547
|
languages: ["csharp"],
|
|
@@ -136287,6 +136661,39 @@ function enclosingTypeBody(node2) {
|
|
|
136287
136661
|
const body = node2.parent;
|
|
136288
136662
|
return body?.type === "declaration_list" ? body : null;
|
|
136289
136663
|
}
|
|
136664
|
+
function isZeroArgCallTo(expr, getName) {
|
|
136665
|
+
if (expr?.type !== "invocation_expression")
|
|
136666
|
+
return false;
|
|
136667
|
+
const fn = expr.childForFieldName("function") ?? expr.namedChildren[0];
|
|
136668
|
+
const fnText = fn?.text;
|
|
136669
|
+
if (fnText !== getName && fnText !== `this.${getName}`)
|
|
136670
|
+
return false;
|
|
136671
|
+
const args = expr.childForFieldName("arguments") ?? expr.namedChildren.find((c2) => c2?.type === "argument_list");
|
|
136672
|
+
const argCount = args?.namedChildren.filter((c2) => c2?.type === "argument").length ?? 0;
|
|
136673
|
+
return argCount === 0;
|
|
136674
|
+
}
|
|
136675
|
+
function getterDelegatesTo(prop, getName) {
|
|
136676
|
+
const propArrow = prop.namedChildren.find((c2) => c2?.type === "arrow_expression_clause");
|
|
136677
|
+
if (propArrow)
|
|
136678
|
+
return isZeroArgCallTo(propArrow.namedChildren.find(Boolean), getName);
|
|
136679
|
+
const accessorList = prop.namedChildren.find((c2) => c2?.type === "accessor_list");
|
|
136680
|
+
if (!accessorList)
|
|
136681
|
+
return false;
|
|
136682
|
+
const getter = accessorList.namedChildren.find((a) => a?.type === "accessor_declaration" && a.children.some((c2) => c2?.text === "get"));
|
|
136683
|
+
if (!getter)
|
|
136684
|
+
return false;
|
|
136685
|
+
const getArrow = getter.namedChildren.find((c2) => c2?.type === "arrow_expression_clause");
|
|
136686
|
+
if (getArrow)
|
|
136687
|
+
return isZeroArgCallTo(getArrow.namedChildren.find(Boolean), getName);
|
|
136688
|
+
const block = getter.namedChildren.find((c2) => c2?.type === "block");
|
|
136689
|
+
if (block) {
|
|
136690
|
+
const stmts = block.namedChildren.filter((c2) => c2?.type !== "comment");
|
|
136691
|
+
if (stmts.length === 1 && stmts[0]?.type === "return_statement") {
|
|
136692
|
+
return isZeroArgCallTo(stmts[0].namedChildren.find(Boolean), getName);
|
|
136693
|
+
}
|
|
136694
|
+
}
|
|
136695
|
+
return false;
|
|
136696
|
+
}
|
|
136290
136697
|
var csharpPropertyNameMatchesGetMethodVisitor;
|
|
136291
136698
|
var init_property_name_matches_get_method = __esm({
|
|
136292
136699
|
"packages/analyzer/dist/rules/code-quality/visitors/csharp/property-name-matches-get-method.js"() {
|
|
@@ -136314,6 +136721,8 @@ var init_property_name_matches_get_method = __esm({
|
|
|
136314
136721
|
});
|
|
136315
136722
|
if (!hasGetMethod)
|
|
136316
136723
|
return null;
|
|
136724
|
+
if (getterDelegatesTo(node2, target))
|
|
136725
|
+
return null;
|
|
136317
136726
|
return makeViolation(this.ruleKey, node2, filePath, "low", "Property name matches a Get method", `Property \`${propName}\` coexists with a parameterless \`${target}()\` method \u2014 a confusing duplication of how the value is exposed.`, sourceCode, `Keep one accessor: either the property \`${propName}\` or the method \`${target}\`, not both.`);
|
|
136318
136727
|
}
|
|
136319
136728
|
};
|
|
@@ -136321,6 +136730,50 @@ var init_property_name_matches_get_method = __esm({
|
|
|
136321
136730
|
});
|
|
136322
136731
|
|
|
136323
136732
|
// packages/analyzer/dist/rules/code-quality/visitors/csharp/public-const-versioning-hazard.js
|
|
136733
|
+
function constFieldNames(fieldDecl) {
|
|
136734
|
+
const names = [];
|
|
136735
|
+
const varDecl = fieldDecl.namedChildren.find((c2) => c2?.type === "variable_declaration");
|
|
136736
|
+
if (!varDecl)
|
|
136737
|
+
return names;
|
|
136738
|
+
for (const vd of varDecl.namedChildren) {
|
|
136739
|
+
if (vd?.type !== "variable_declarator")
|
|
136740
|
+
continue;
|
|
136741
|
+
const n = vd.childForFieldName("name")?.text ?? vd.namedChildren.find((c2) => c2?.type === "identifier")?.text;
|
|
136742
|
+
if (n)
|
|
136743
|
+
names.push(n);
|
|
136744
|
+
}
|
|
136745
|
+
return names;
|
|
136746
|
+
}
|
|
136747
|
+
function referencedBySiblingConst(node2, names) {
|
|
136748
|
+
let root2 = node2;
|
|
136749
|
+
while (root2.parent)
|
|
136750
|
+
root2 = root2.parent;
|
|
136751
|
+
let found = false;
|
|
136752
|
+
const scan3 = (n) => {
|
|
136753
|
+
if (found)
|
|
136754
|
+
return;
|
|
136755
|
+
if (n.type === "field_declaration" && n.id !== node2.id && hasCSharpModifier(n, "const")) {
|
|
136756
|
+
const varDecl = n.namedChildren.find((c2) => c2?.type === "variable_declaration");
|
|
136757
|
+
if (varDecl) {
|
|
136758
|
+
for (const vd of varDecl.namedChildren) {
|
|
136759
|
+
if (vd?.type !== "variable_declarator")
|
|
136760
|
+
continue;
|
|
136761
|
+
const declaredName = vd.childForFieldName("name");
|
|
136762
|
+
walkCSharp(vd, (id) => {
|
|
136763
|
+
if (id.type === "identifier" && id.id !== declaredName?.id && names.includes(id.text)) {
|
|
136764
|
+
found = true;
|
|
136765
|
+
}
|
|
136766
|
+
});
|
|
136767
|
+
}
|
|
136768
|
+
}
|
|
136769
|
+
}
|
|
136770
|
+
for (const c2 of n.namedChildren)
|
|
136771
|
+
if (c2)
|
|
136772
|
+
scan3(c2);
|
|
136773
|
+
};
|
|
136774
|
+
scan3(root2);
|
|
136775
|
+
return found;
|
|
136776
|
+
}
|
|
136324
136777
|
var csharpPublicConstVersioningHazardVisitor;
|
|
136325
136778
|
var init_public_const_versioning_hazard = __esm({
|
|
136326
136779
|
"packages/analyzer/dist/rules/code-quality/visitors/csharp/public-const-versioning-hazard.js"() {
|
|
@@ -136336,6 +136789,9 @@ var init_public_const_versioning_hazard = __esm({
|
|
|
136336
136789
|
return null;
|
|
136337
136790
|
if (!hasCSharpModifier(node2, "public") && !hasCSharpModifier(node2, "protected"))
|
|
136338
136791
|
return null;
|
|
136792
|
+
const names = constFieldNames(node2);
|
|
136793
|
+
if (names.length > 0 && referencedBySiblingConst(node2, names))
|
|
136794
|
+
return null;
|
|
136339
136795
|
return makeViolation(this.ruleKey, node2, filePath, "low", "Public constant versioning hazard", "A `public const` value is inlined into consumers at compile time and will not update unless they recompile \u2014 prefer `static readonly`.", sourceCode, "Replace the `public const` with a `public static readonly` field.");
|
|
136340
136796
|
}
|
|
136341
136797
|
};
|
|
@@ -137011,12 +137467,12 @@ var init_missing_access_modifier = __esm({
|
|
|
137011
137467
|
return null;
|
|
137012
137468
|
if (node2.parent?.parent?.type === "interface_declaration")
|
|
137013
137469
|
return null;
|
|
137470
|
+
if (node2.namedChildren.some((c2) => c2?.type === "explicit_interface_specifier"))
|
|
137471
|
+
return null;
|
|
137014
137472
|
if (node2.type === "method_declaration") {
|
|
137015
137473
|
const nm = node2.childForFieldName("name");
|
|
137016
137474
|
if (nm?.type === "qualified_name" || (nm?.text ?? "").includes("."))
|
|
137017
137475
|
return null;
|
|
137018
|
-
if (node2.namedChildren.some((c2) => c2?.type === "explicit_interface_specifier"))
|
|
137019
|
-
return null;
|
|
137020
137476
|
}
|
|
137021
137477
|
if (node2.type === "constructor_declaration" && mods.includes("static"))
|
|
137022
137478
|
return null;
|
|
@@ -137080,7 +137536,7 @@ function topLevelTypeIdentifiers(root2) {
|
|
|
137080
137536
|
const body = m.namedChildren.find((c2) => c2?.type === "declaration_list");
|
|
137081
137537
|
if (body)
|
|
137082
137538
|
collectFrom(body);
|
|
137083
|
-
} else if (
|
|
137539
|
+
} else if (TYPE_DECL_TYPES3.has(m.type)) {
|
|
137084
137540
|
const id = m.childForFieldName("name");
|
|
137085
137541
|
if (id)
|
|
137086
137542
|
out.push(id);
|
|
@@ -137093,6 +137549,8 @@ function topLevelTypeIdentifiers(root2) {
|
|
|
137093
137549
|
function nameMatches(fileName, typeName2) {
|
|
137094
137550
|
if (fileName === typeName2)
|
|
137095
137551
|
return true;
|
|
137552
|
+
if (typeName2 === `${fileName}Attribute`)
|
|
137553
|
+
return true;
|
|
137096
137554
|
const brace = fileName.indexOf("{");
|
|
137097
137555
|
if (brace > 0 && fileName.slice(0, brace) === typeName2)
|
|
137098
137556
|
return true;
|
|
@@ -137101,12 +137559,12 @@ function nameMatches(fileName, typeName2) {
|
|
|
137101
137559
|
return true;
|
|
137102
137560
|
return false;
|
|
137103
137561
|
}
|
|
137104
|
-
var
|
|
137562
|
+
var TYPE_DECL_TYPES3, csharpFilenameTypeMismatchVisitor;
|
|
137105
137563
|
var init_csharp_filename_type_mismatch = __esm({
|
|
137106
137564
|
"packages/analyzer/dist/rules/code-quality/visitors/csharp/csharp-filename-type-mismatch.js"() {
|
|
137107
137565
|
"use strict";
|
|
137108
137566
|
init_types2();
|
|
137109
|
-
|
|
137567
|
+
TYPE_DECL_TYPES3 = /* @__PURE__ */ new Set([
|
|
137110
137568
|
"class_declaration",
|
|
137111
137569
|
"struct_declaration",
|
|
137112
137570
|
"interface_declaration",
|
|
@@ -137120,13 +137578,18 @@ var init_csharp_filename_type_mismatch = __esm({
|
|
|
137120
137578
|
nodeTypes: ["compilation_unit"],
|
|
137121
137579
|
visit(node2, filePath, sourceCode) {
|
|
137122
137580
|
const base2 = filePath.split("/").pop() ?? "";
|
|
137123
|
-
const
|
|
137581
|
+
const lower = base2.toLowerCase();
|
|
137582
|
+
const compoundExt = [".cshtml.cs", ".razor.cs"].find((ext2) => lower.endsWith(ext2));
|
|
137583
|
+
const fileName = compoundExt ? base2.slice(0, base2.length - compoundExt.length) : base2.replace(/\.[^.]*$/, "");
|
|
137124
137584
|
if (!fileName)
|
|
137125
137585
|
return null;
|
|
137586
|
+
const migrationName = fileName.match(/^\d{14}_(.+)$/)?.[1];
|
|
137587
|
+
const candidateNames2 = migrationName ? [fileName, migrationName] : [fileName];
|
|
137126
137588
|
const identifiers = topLevelTypeIdentifiers(node2);
|
|
137127
137589
|
if (identifiers.length === 0)
|
|
137128
137590
|
return null;
|
|
137129
|
-
|
|
137591
|
+
const matches = (id) => candidateNames2.some((fn) => nameMatches(fn, id.text)) || compoundExt !== void 0 && id.text === `${fileName}Model`;
|
|
137592
|
+
if (identifiers.some(matches))
|
|
137130
137593
|
return null;
|
|
137131
137594
|
const first2 = identifiers[0];
|
|
137132
137595
|
return makeViolation(this.ruleKey, first2, filePath, "low", "File name does not match a contained type", `File '${fileName}' declares type '${first2.text}' but no top-level type matches the file name; name the file after a type so it is easy to locate.`, sourceCode, `Rename the file after a contained type, e.g. ${first2.text}.cs.`);
|
|
@@ -137579,7 +138042,7 @@ var init_csharp6 = __esm({
|
|
|
137579
138042
|
init_cognitive_complexity3();
|
|
137580
138043
|
init_collapsible_else_if2();
|
|
137581
138044
|
init_collapsible_if3();
|
|
137582
|
-
|
|
138045
|
+
init_commented_out_code4();
|
|
137583
138046
|
init_comparison_of_constant2();
|
|
137584
138047
|
init_console_log2();
|
|
137585
138048
|
init_contradictory_boolean_expression2();
|
|
@@ -137662,7 +138125,6 @@ var init_csharp6 = __esm({
|
|
|
137662
138125
|
init_unnecessary_namespace_qualifier2();
|
|
137663
138126
|
init_unsafe_any_usage2();
|
|
137664
138127
|
init_unused_collection2();
|
|
137665
|
-
init_unused_function_parameter2();
|
|
137666
138128
|
init_unused_private_member2();
|
|
137667
138129
|
init_unused_private_method2();
|
|
137668
138130
|
init_unused_private_nested_class2();
|
|
@@ -137921,7 +138383,6 @@ var init_csharp6 = __esm({
|
|
|
137921
138383
|
csharpUnnecessaryNamespaceQualifierVisitor,
|
|
137922
138384
|
csharpUnsafeAnyUsageVisitor,
|
|
137923
138385
|
csharpUnusedCollectionVisitor,
|
|
137924
|
-
csharpUnusedFunctionParameterVisitor,
|
|
137925
138386
|
csharpUnusedPrivateMemberVisitor,
|
|
137926
138387
|
csharpUnusedPrivateMethodVisitor,
|
|
137927
138388
|
csharpUnusedPrivateNestedClassVisitor,
|
|
@@ -140103,6 +140564,11 @@ function allElementsConstant(creation) {
|
|
|
140103
140564
|
return false;
|
|
140104
140565
|
return elements.every((e) => LITERAL_TYPES6.has(e.type));
|
|
140105
140566
|
}
|
|
140567
|
+
function isGeneratedOrMigrationFile(filePath) {
|
|
140568
|
+
if (/(^|[\\/])Migrations[\\/]/.test(filePath))
|
|
140569
|
+
return true;
|
|
140570
|
+
return /\.(designer|g|g\.i|generated)\.cs$/i.test(filePath);
|
|
140571
|
+
}
|
|
140106
140572
|
var LITERAL_TYPES6, csharpConstantArrayArgumentVisitor;
|
|
140107
140573
|
var init_constant_array_argument = __esm({
|
|
140108
140574
|
"packages/analyzer/dist/rules/performance/visitors/csharp/constant-array-argument.js"() {
|
|
@@ -140123,6 +140589,8 @@ var init_constant_array_argument = __esm({
|
|
|
140123
140589
|
languages: ["csharp"],
|
|
140124
140590
|
nodeTypes: ["array_creation_expression", "implicit_array_creation_expression"],
|
|
140125
140591
|
visit(node2, filePath, sourceCode) {
|
|
140592
|
+
if (isGeneratedOrMigrationFile(filePath))
|
|
140593
|
+
return null;
|
|
140126
140594
|
if (node2.parent?.type !== "argument")
|
|
140127
140595
|
return null;
|
|
140128
140596
|
if (!getCSharpEnclosingFunction(node2))
|
|
@@ -140911,7 +141379,36 @@ var init_missing_finally_cleanup2 = __esm({
|
|
|
140911
141379
|
});
|
|
140912
141380
|
|
|
140913
141381
|
// packages/analyzer/dist/rules/reliability/visitors/csharp/unsafe-json-parse.js
|
|
140914
|
-
|
|
141382
|
+
function bodyDeclaresMember(body, name) {
|
|
141383
|
+
for (const member of body.namedChildren) {
|
|
141384
|
+
if (!member)
|
|
141385
|
+
continue;
|
|
141386
|
+
if (member.type === "property_declaration") {
|
|
141387
|
+
if (member.childForFieldName("name")?.text === name)
|
|
141388
|
+
return true;
|
|
141389
|
+
} else if (member.type === "field_declaration") {
|
|
141390
|
+
const decl = member.namedChildren.find((c2) => c2?.type === "variable_declaration");
|
|
141391
|
+
for (const d3 of decl?.namedChildren ?? []) {
|
|
141392
|
+
if (d3?.type === "variable_declarator" && d3.childForFieldName("name")?.text === name)
|
|
141393
|
+
return true;
|
|
141394
|
+
}
|
|
141395
|
+
}
|
|
141396
|
+
}
|
|
141397
|
+
return false;
|
|
141398
|
+
}
|
|
141399
|
+
function enclosingTypeDeclaresMember(node2, name) {
|
|
141400
|
+
let current = node2.parent;
|
|
141401
|
+
while (current) {
|
|
141402
|
+
if (TYPE_DECLS2.has(current.type)) {
|
|
141403
|
+
const body = current.childForFieldName("body");
|
|
141404
|
+
if (body && bodyDeclaresMember(body, name))
|
|
141405
|
+
return true;
|
|
141406
|
+
}
|
|
141407
|
+
current = current.parent;
|
|
141408
|
+
}
|
|
141409
|
+
return false;
|
|
141410
|
+
}
|
|
141411
|
+
var JSON_PARSERS, TYPE_DECLS2, csharpUnsafeJsonParseVisitor;
|
|
140915
141412
|
var init_unsafe_json_parse3 = __esm({
|
|
140916
141413
|
"packages/analyzer/dist/rules/reliability/visitors/csharp/unsafe-json-parse.js"() {
|
|
140917
141414
|
"use strict";
|
|
@@ -140926,15 +141423,25 @@ var init_unsafe_json_parse3 = __esm({
|
|
|
140926
141423
|
JsonDocument: /* @__PURE__ */ new Set(["Parse", "ParseAsync"]),
|
|
140927
141424
|
JsonNode: /* @__PURE__ */ new Set(["Parse"])
|
|
140928
141425
|
};
|
|
141426
|
+
TYPE_DECLS2 = /* @__PURE__ */ new Set([
|
|
141427
|
+
"class_declaration",
|
|
141428
|
+
"struct_declaration",
|
|
141429
|
+
"record_declaration",
|
|
141430
|
+
"record_struct_declaration"
|
|
141431
|
+
]);
|
|
140929
141432
|
csharpUnsafeJsonParseVisitor = {
|
|
140930
141433
|
ruleKey: "reliability/deterministic/unsafe-json-parse",
|
|
140931
141434
|
languages: ["csharp"],
|
|
140932
141435
|
nodeTypes: ["invocation_expression"],
|
|
140933
141436
|
visit(node2, filePath, sourceCode) {
|
|
140934
|
-
const
|
|
141437
|
+
const rawReceiver = getCSharpReceiver(node2);
|
|
141438
|
+
const receiver = simpleTypeName5(rawReceiver);
|
|
140935
141439
|
const method = getCSharpMethodName(node2);
|
|
140936
141440
|
if (!JSON_PARSERS[receiver]?.has(method))
|
|
140937
141441
|
return null;
|
|
141442
|
+
const bareReceiver = rawReceiver.startsWith("this.") ? rawReceiver.slice(5) : rawReceiver;
|
|
141443
|
+
if (!bareReceiver.includes(".") && enclosingTypeDeclaresMember(node2, bareReceiver))
|
|
141444
|
+
return null;
|
|
140938
141445
|
const firstArg = getCSharpArguments(node2)[0];
|
|
140939
141446
|
if (firstArg?.type === "invocation_expression") {
|
|
140940
141447
|
const innerReceiver = simpleTypeName5(getCSharpReceiver(firstArg));
|
|
@@ -142641,18 +143148,10 @@ var init_logger_field_naming = __esm({
|
|
|
142641
143148
|
csharpLoggerFieldNamingVisitor = {
|
|
142642
143149
|
ruleKey: "style/deterministic/logger-field-naming",
|
|
142643
143150
|
languages: ["csharp"],
|
|
142644
|
-
nodeTypes: ["field_declaration"
|
|
143151
|
+
nodeTypes: ["field_declaration"],
|
|
142645
143152
|
visit(node2, filePath, sourceCode) {
|
|
142646
143153
|
if (isAutoGeneratedCSharpFile(sourceCode))
|
|
142647
143154
|
return null;
|
|
142648
|
-
if (node2.type === "property_declaration") {
|
|
142649
|
-
if (!isLoggerType(node2.childForFieldName("type")))
|
|
142650
|
-
return null;
|
|
142651
|
-
const name = node2.childForFieldName("name");
|
|
142652
|
-
if (!name || ACCEPTED.test(name.text))
|
|
142653
|
-
return null;
|
|
142654
|
-
return makeViolation(this.ruleKey, name, filePath, "low", "Logger does not follow the naming convention", `Logger '${name.text}' does not follow the convention for logger members (camelCase, optionally _-prefixed).`, sourceCode, `Rename the logger to a camelCase name such as '_logger'.`);
|
|
142655
|
-
}
|
|
142656
143155
|
const declaration = node2.namedChildren.find((c2) => c2?.type === "variable_declaration");
|
|
142657
143156
|
if (!declaration)
|
|
142658
143157
|
return null;
|
|
@@ -143460,15 +143959,28 @@ function isNestedInType(node2) {
|
|
|
143460
143959
|
const parent = node2.parent;
|
|
143461
143960
|
if (parent?.type !== "declaration_list")
|
|
143462
143961
|
return false;
|
|
143463
|
-
return parent.parent != null &&
|
|
143962
|
+
return parent.parent != null && TYPE_DECL_TYPES4.has(parent.parent.type);
|
|
143464
143963
|
}
|
|
143465
|
-
|
|
143964
|
+
function isConstantContainer(node2) {
|
|
143965
|
+
if (node2.type !== "class_declaration")
|
|
143966
|
+
return false;
|
|
143967
|
+
if (!hasCSharpModifier(node2, "static"))
|
|
143968
|
+
return false;
|
|
143969
|
+
const body = node2.childForFieldName("body");
|
|
143970
|
+
if (!body)
|
|
143971
|
+
return false;
|
|
143972
|
+
const members = body.namedChildren.filter((c2) => c2 && c2.type !== "comment");
|
|
143973
|
+
if (members.length === 0)
|
|
143974
|
+
return false;
|
|
143975
|
+
return members.every((m) => m?.type === "field_declaration" && (hasCSharpModifier(m, "const") || hasCSharpModifier(m, "static") && hasCSharpModifier(m, "readonly")));
|
|
143976
|
+
}
|
|
143977
|
+
var TYPE_DECL_TYPES4, csharpNestedTypePubliclyVisibleVisitor;
|
|
143466
143978
|
var init_nested_type_publicly_visible = __esm({
|
|
143467
143979
|
"packages/analyzer/dist/rules/architecture/visitors/csharp/nested-type-publicly-visible.js"() {
|
|
143468
143980
|
"use strict";
|
|
143469
143981
|
init_types2();
|
|
143470
143982
|
init_csharp_helpers();
|
|
143471
|
-
|
|
143983
|
+
TYPE_DECL_TYPES4 = /* @__PURE__ */ new Set([
|
|
143472
143984
|
"class_declaration",
|
|
143473
143985
|
"struct_declaration",
|
|
143474
143986
|
"interface_declaration",
|
|
@@ -143486,6 +143998,8 @@ var init_nested_type_publicly_visible = __esm({
|
|
|
143486
143998
|
return null;
|
|
143487
143999
|
if (getCSharpAttributeNames(node2).length > 0)
|
|
143488
144000
|
return null;
|
|
144001
|
+
if (isConstantContainer(node2))
|
|
144002
|
+
return null;
|
|
143489
144003
|
const name = node2.childForFieldName("name")?.text ?? "type";
|
|
143490
144004
|
return makeViolation(this.ruleKey, node2, filePath, "low", "Publicly visible nested type", `Nested type '${name}' is publicly visible, exposing an implementation detail of its containing type.`, sourceCode, `Make '${name}' private or internal, or lift it out to its own top-level type if it is a real part of the API.`);
|
|
143491
144005
|
}
|
|
@@ -143573,6 +144087,8 @@ var init_type_outside_namespace = __esm({
|
|
|
143573
144087
|
|
|
143574
144088
|
// packages/analyzer/dist/rules/architecture/visitors/csharp/_uri-helpers.js
|
|
143575
144089
|
function nameLooksLikeUri(name) {
|
|
144090
|
+
if (PREPOSITION_BEFORE_URI.test(name))
|
|
144091
|
+
return false;
|
|
143576
144092
|
if (URI_NAME_PATTERN.test(name))
|
|
143577
144093
|
return true;
|
|
143578
144094
|
return /(Url|Uri|Endpoint|Webhook)$/.test(name);
|
|
@@ -143580,11 +144096,12 @@ function nameLooksLikeUri(name) {
|
|
|
143580
144096
|
function isStringType(typeNode) {
|
|
143581
144097
|
return typeNode?.type === "predefined_type" && typeNode.text === "string";
|
|
143582
144098
|
}
|
|
143583
|
-
var URI_NAME_PATTERN;
|
|
144099
|
+
var URI_NAME_PATTERN, PREPOSITION_BEFORE_URI;
|
|
143584
144100
|
var init_uri_helpers = __esm({
|
|
143585
144101
|
"packages/analyzer/dist/rules/architecture/visitors/csharp/_uri-helpers.js"() {
|
|
143586
144102
|
"use strict";
|
|
143587
144103
|
URI_NAME_PATTERN = /(^|[^a-z])(url|uri|uris|urls|endpoint|endpoints|webhook|webhookurl|callbackurl|redirecturi|redirecturl|hreflink|baseurl|baseaddress)$/i;
|
|
144104
|
+
PREPOSITION_BEFORE_URI = /(In|As|Of|At|By|Within)(Url|Uri|Uris|Urls|Endpoint|Endpoints|Webhook)$/;
|
|
143588
144105
|
}
|
|
143589
144106
|
});
|
|
143590
144107
|
|
|
@@ -143622,13 +144139,22 @@ var init_uri_parameter_as_string = __esm({
|
|
|
143622
144139
|
});
|
|
143623
144140
|
|
|
143624
144141
|
// packages/analyzer/dist/rules/architecture/visitors/csharp/uri-property-as-string.js
|
|
143625
|
-
|
|
144142
|
+
function initializerProvesNotUri(valueNode) {
|
|
144143
|
+
if (!valueNode || !isCSharpStringNode(valueNode))
|
|
144144
|
+
return false;
|
|
144145
|
+
const text4 = getCSharpStringText(valueNode);
|
|
144146
|
+
if (text4 == null || text4.length === 0)
|
|
144147
|
+
return false;
|
|
144148
|
+
return !text4.includes("://");
|
|
144149
|
+
}
|
|
144150
|
+
var BINDING_ATTRIBUTES, csharpUriPropertyAsStringVisitor;
|
|
143626
144151
|
var init_uri_property_as_string = __esm({
|
|
143627
144152
|
"packages/analyzer/dist/rules/architecture/visitors/csharp/uri-property-as-string.js"() {
|
|
143628
144153
|
"use strict";
|
|
143629
144154
|
init_types2();
|
|
143630
144155
|
init_csharp_helpers();
|
|
143631
144156
|
init_uri_helpers();
|
|
144157
|
+
BINDING_ATTRIBUTES = /* @__PURE__ */ new Set(["BindProperty", "FromQuery", "FromRoute", "FromForm", "ModelBinder"]);
|
|
143632
144158
|
csharpUriPropertyAsStringVisitor = {
|
|
143633
144159
|
ruleKey: "architecture/deterministic/uri-property-as-string",
|
|
143634
144160
|
languages: ["csharp"],
|
|
@@ -143641,6 +144167,10 @@ var init_uri_property_as_string = __esm({
|
|
|
143641
144167
|
const name = node2.childForFieldName("name")?.text;
|
|
143642
144168
|
if (!name || !nameLooksLikeUri(name))
|
|
143643
144169
|
return null;
|
|
144170
|
+
if (getCSharpAttributeNames(node2).some((a) => BINDING_ATTRIBUTES.has(a)))
|
|
144171
|
+
return null;
|
|
144172
|
+
if (initializerProvesNotUri(node2.childForFieldName("value")))
|
|
144173
|
+
return null;
|
|
143644
144174
|
return makeViolation(this.ruleKey, node2.childForFieldName("type"), filePath, "low", "URI property typed as string", `Property '${name}' holds a URI but is typed as string; use System.Uri to get parsing and validation.`, sourceCode, `Change the type of '${name}' from string to System.Uri.`);
|
|
143645
144175
|
}
|
|
143646
144176
|
};
|
|
@@ -143678,6 +144208,21 @@ function isModelType(classDecl) {
|
|
|
143678
144208
|
const name = classDecl.childForFieldName("name")?.text ?? "";
|
|
143679
144209
|
return MODEL_NAME_SUFFIX.test(name);
|
|
143680
144210
|
}
|
|
144211
|
+
function isServerConstructed(classDecl, body) {
|
|
144212
|
+
for (const member of body.namedChildren) {
|
|
144213
|
+
if (member?.type === "constructor_declaration") {
|
|
144214
|
+
const params = member.childForFieldName("parameters");
|
|
144215
|
+
if (params && params.namedChildCount > 0)
|
|
144216
|
+
return true;
|
|
144217
|
+
}
|
|
144218
|
+
if (member?.type === "method_declaration" && hasCSharpModifier(member, "static")) {
|
|
144219
|
+
const mName = member.childForFieldName("name")?.text ?? "";
|
|
144220
|
+
if (mName === "Create" || mName.startsWith("From"))
|
|
144221
|
+
return true;
|
|
144222
|
+
}
|
|
144223
|
+
}
|
|
144224
|
+
return false;
|
|
144225
|
+
}
|
|
143681
144226
|
function flaggablePropertyType(typeNode) {
|
|
143682
144227
|
if (typeNode?.type !== "predefined_type")
|
|
143683
144228
|
return null;
|
|
@@ -143690,7 +144235,7 @@ var init_value_type_action_param_under_posting = __esm({
|
|
|
143690
144235
|
"use strict";
|
|
143691
144236
|
init_types2();
|
|
143692
144237
|
init_csharp_helpers();
|
|
143693
|
-
MODEL_NAME_SUFFIX = /(Request|
|
|
144238
|
+
MODEL_NAME_SUFFIX = /(Request|Input|Form|Command|Query|Payload)$/;
|
|
143694
144239
|
SCALAR_VALUE_TYPES = /* @__PURE__ */ new Set(["int", "long", "short", "byte", "uint", "ulong", "ushort", "sbyte", "decimal", "double", "float", "bool", "char"]);
|
|
143695
144240
|
csharpValueTypeActionParamUnderPostingVisitor = {
|
|
143696
144241
|
ruleKey: "architecture/deterministic/value-type-action-param-under-posting",
|
|
@@ -143702,6 +144247,8 @@ var init_value_type_action_param_under_posting = __esm({
|
|
|
143702
144247
|
const body = node2.childForFieldName("body");
|
|
143703
144248
|
if (!body)
|
|
143704
144249
|
return null;
|
|
144250
|
+
if (isServerConstructed(node2, body))
|
|
144251
|
+
return null;
|
|
143705
144252
|
for (const member of body.namedChildren) {
|
|
143706
144253
|
if (member?.type !== "property_declaration")
|
|
143707
144254
|
continue;
|
|
@@ -143729,6 +144276,22 @@ var init_value_type_action_param_under_posting = __esm({
|
|
|
143729
144276
|
});
|
|
143730
144277
|
|
|
143731
144278
|
// packages/analyzer/dist/rules/architecture/visitors/csharp/action-missing-producesresponsetype.js
|
|
144279
|
+
function excludedFromApiExplorer(node2) {
|
|
144280
|
+
for (const child of node2.children) {
|
|
144281
|
+
if (child?.type !== "attribute_list")
|
|
144282
|
+
continue;
|
|
144283
|
+
for (const attr of child.namedChildren) {
|
|
144284
|
+
if (attr?.type !== "attribute")
|
|
144285
|
+
continue;
|
|
144286
|
+
const name = (attr.childForFieldName("name")?.text ?? "").split(".").pop();
|
|
144287
|
+
if (name !== "ApiExplorerSettings")
|
|
144288
|
+
continue;
|
|
144289
|
+
if (/\bIgnoreApi\s*=\s*true\b/i.test(attr.text))
|
|
144290
|
+
return true;
|
|
144291
|
+
}
|
|
144292
|
+
}
|
|
144293
|
+
return false;
|
|
144294
|
+
}
|
|
143732
144295
|
function attributeNames7(node2) {
|
|
143733
144296
|
const names = [];
|
|
143734
144297
|
for (const child of node2.children) {
|
|
@@ -143776,6 +144339,8 @@ var init_action_missing_producesresponsetype = __esm({
|
|
|
143776
144339
|
const classAttrs = attributeNames7(cls);
|
|
143777
144340
|
if (classAttrs.some((a) => a.startsWith("ProducesResponseType") || a === "ProducesDefaultResponseType"))
|
|
143778
144341
|
return null;
|
|
144342
|
+
if (excludedFromApiExplorer(node2) || excludedFromApiExplorer(cls))
|
|
144343
|
+
return null;
|
|
143779
144344
|
const name = node2.childForFieldName("name");
|
|
143780
144345
|
return makeViolation(this.ruleKey, name ?? node2, filePath, "low", "Controller action has no [ProducesResponseType]", `Action '${name?.text ?? ""}' declares no [ProducesResponseType]; its response shapes and status codes are missing from the API description.`, sourceCode, "Annotate the action with [ProducesResponseType] for each status code it can return.");
|
|
143781
144346
|
}
|
|
@@ -145718,52 +146283,96 @@ var init_pyproject_checker = __esm({
|
|
|
145718
146283
|
// packages/analyzer/dist/roslyn-host-client.js
|
|
145719
146284
|
import { spawn as spawn4 } from "child_process";
|
|
145720
146285
|
import { existsSync as existsSync10 } from "fs";
|
|
146286
|
+
import { tmpdir } from "os";
|
|
145721
146287
|
import { dirname as dirname9, resolve as resolve9 } from "path";
|
|
145722
146288
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
145723
146289
|
function resolveRoslynHostBinary() {
|
|
145724
146290
|
const override = process.env[HOST_BINARY_ENV];
|
|
145725
146291
|
if (override)
|
|
145726
146292
|
return existsSync10(override) ? override : null;
|
|
145727
|
-
const
|
|
145728
|
-
|
|
145729
|
-
|
|
145730
|
-
|
|
145731
|
-
|
|
145732
|
-
|
|
146293
|
+
const rels = [
|
|
146294
|
+
"roslyn-host/csharp-roslyn-host.dll",
|
|
146295
|
+
"tools/csharp-roslyn-host/bin/Release/net8.0/csharp-roslyn-host"
|
|
146296
|
+
];
|
|
146297
|
+
let dir = dirname9(fileURLToPath5(import.meta.url));
|
|
146298
|
+
for (let i = 0; i < 12; i++) {
|
|
146299
|
+
for (const rel of rels) {
|
|
146300
|
+
const candidate = resolve9(dir, rel);
|
|
146301
|
+
if (existsSync10(candidate))
|
|
146302
|
+
return candidate;
|
|
146303
|
+
}
|
|
146304
|
+
const parent = dirname9(dir);
|
|
146305
|
+
if (parent === dir)
|
|
146306
|
+
break;
|
|
146307
|
+
dir = parent;
|
|
145733
146308
|
}
|
|
145734
146309
|
return null;
|
|
145735
146310
|
}
|
|
145736
146311
|
function invokeHost(bin, request) {
|
|
145737
146312
|
return new Promise((resolvePromise, reject) => {
|
|
145738
|
-
const
|
|
146313
|
+
const viaDotnet = bin.endsWith(".dll");
|
|
146314
|
+
const cmd = viaDotnet ? "dotnet" : bin;
|
|
146315
|
+
const args = viaDotnet ? [bin] : [];
|
|
146316
|
+
const child = spawn4(cmd, args, { stdio: ["pipe", "pipe", "pipe"], cwd: tmpdir() });
|
|
145739
146317
|
let stdout = "";
|
|
145740
146318
|
let stderr = "";
|
|
146319
|
+
let settled = false;
|
|
146320
|
+
const fail4 = (err) => {
|
|
146321
|
+
if (settled)
|
|
146322
|
+
return;
|
|
146323
|
+
settled = true;
|
|
146324
|
+
reject(err);
|
|
146325
|
+
};
|
|
146326
|
+
const succeed = (violations) => {
|
|
146327
|
+
if (settled)
|
|
146328
|
+
return;
|
|
146329
|
+
settled = true;
|
|
146330
|
+
resolvePromise(violations);
|
|
146331
|
+
};
|
|
145741
146332
|
child.stdout.setEncoding("utf8");
|
|
145742
146333
|
child.stderr.setEncoding("utf8");
|
|
145743
146334
|
child.stdout.on("data", (d3) => stdout += d3);
|
|
145744
146335
|
child.stderr.on("data", (d3) => stderr += d3);
|
|
145745
|
-
child.on("error", (e) =>
|
|
145746
|
-
child.on("
|
|
145747
|
-
|
|
145748
|
-
|
|
145749
|
-
|
|
146336
|
+
child.on("error", (e) => fail4(new RoslynHostUnavailableError(`Failed to start the Roslyn host (${viaDotnet ? `dotnet ${bin}` : bin}): ${e.message}. Is the .NET runtime installed?`)));
|
|
146337
|
+
child.stdin.on("error", () => {
|
|
146338
|
+
});
|
|
146339
|
+
child.on("close", (code, signalName) => {
|
|
146340
|
+
if (code !== 0 || signalName) {
|
|
146341
|
+
const reason = stderr.trim() || stdout.trim() || "(no output)";
|
|
146342
|
+
fail4(new RoslynHostUnavailableError(`The Roslyn host exited ${signalName ? `via ${signalName}` : `with code ${code}`} before responding. Is a compatible .NET runtime installed? Host output: ${reason}`));
|
|
146343
|
+
return;
|
|
146344
|
+
}
|
|
146345
|
+
const lines = stdout.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
146346
|
+
if (lines.length === 0) {
|
|
146347
|
+
fail4(new Error(`Roslyn host produced no output.${stderr ? ` stderr: ${stderr}` : ""}`));
|
|
145750
146348
|
return;
|
|
145751
146349
|
}
|
|
145752
146350
|
let resp;
|
|
145753
|
-
|
|
145754
|
-
|
|
145755
|
-
|
|
145756
|
-
|
|
146351
|
+
for (const l of lines) {
|
|
146352
|
+
try {
|
|
146353
|
+
const parsed = JSON.parse(l);
|
|
146354
|
+
if (parsed && typeof parsed.ok === "boolean") {
|
|
146355
|
+
resp = parsed;
|
|
146356
|
+
break;
|
|
146357
|
+
}
|
|
146358
|
+
} catch {
|
|
146359
|
+
}
|
|
146360
|
+
}
|
|
146361
|
+
if (!resp) {
|
|
146362
|
+
fail4(new Error(`Roslyn host returned invalid JSON: ${lines[0]}`));
|
|
145757
146363
|
return;
|
|
145758
146364
|
}
|
|
145759
146365
|
if (!resp.ok) {
|
|
145760
|
-
|
|
146366
|
+
fail4(new Error(`Roslyn host error: ${resp.error ?? "unknown"}`));
|
|
145761
146367
|
return;
|
|
145762
146368
|
}
|
|
145763
|
-
|
|
146369
|
+
succeed(resp.violations ?? []);
|
|
145764
146370
|
});
|
|
145765
|
-
|
|
145766
|
-
|
|
146371
|
+
try {
|
|
146372
|
+
child.stdin.write(JSON.stringify(request) + "\n");
|
|
146373
|
+
child.stdin.end();
|
|
146374
|
+
} catch {
|
|
146375
|
+
}
|
|
145767
146376
|
});
|
|
145768
146377
|
}
|
|
145769
146378
|
function runRoslynWorkspace(projectPath, rules) {
|
|
@@ -146568,7 +147177,7 @@ var init_flow_service = __esm({
|
|
|
146568
147177
|
});
|
|
146569
147178
|
|
|
146570
147179
|
// packages/core/dist/progress.js
|
|
146571
|
-
function buildAnalysisSteps(enabledCategories, enableLlmRules) {
|
|
147180
|
+
function buildAnalysisSteps(enabledCategories, enableLlmRules, hasCSharp) {
|
|
146572
147181
|
const steps = [
|
|
146573
147182
|
{ key: "parse", label: "Parsing repository" }
|
|
146574
147183
|
];
|
|
@@ -146579,6 +147188,9 @@ function buildAnalysisSteps(enabledCategories, enableLlmRules) {
|
|
|
146579
147188
|
for (const domain of activeDomains) {
|
|
146580
147189
|
steps.push({ key: domain, label: `${DOMAIN_LABELS[domain]} checks` });
|
|
146581
147190
|
}
|
|
147191
|
+
if (hasCSharp) {
|
|
147192
|
+
steps.push({ key: "csharp", label: "C# semantic analysis" });
|
|
147193
|
+
}
|
|
146582
147194
|
steps.push({ key: "persist", label: "Saving results" });
|
|
146583
147195
|
return steps;
|
|
146584
147196
|
}
|
|
@@ -146621,6 +147233,23 @@ var init_progress = __esm({
|
|
|
146621
147233
|
this.emit();
|
|
146622
147234
|
}
|
|
146623
147235
|
}
|
|
147236
|
+
/**
|
|
147237
|
+
* Insert a step at runtime, just before `persist`, if it isn't already there.
|
|
147238
|
+
* Used for phases we can't declare up front — e.g. the C# semantic tier only
|
|
147239
|
+
* exists when the repo actually has C#, which isn't known until files are read.
|
|
147240
|
+
* No-op if the key already exists.
|
|
147241
|
+
*/
|
|
147242
|
+
ensureStep(key4, label) {
|
|
147243
|
+
if (this.steps.some((s) => s.key === key4))
|
|
147244
|
+
return;
|
|
147245
|
+
const persistIdx = this.steps.findIndex((s) => s.key === "persist");
|
|
147246
|
+
const step = { key: key4, label, status: "pending" };
|
|
147247
|
+
if (persistIdx === -1)
|
|
147248
|
+
this.steps.push(step);
|
|
147249
|
+
else
|
|
147250
|
+
this.steps.splice(persistIdx, 0, step);
|
|
147251
|
+
this.emit();
|
|
147252
|
+
}
|
|
146624
147253
|
setStatus(key4, status, detail) {
|
|
146625
147254
|
const step = this.steps.find((s) => s.key === key4);
|
|
146626
147255
|
if (step) {
|
|
@@ -146694,7 +147323,7 @@ var require_windows = __commonJS({
|
|
|
146694
147323
|
"node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.js"(exports, module) {
|
|
146695
147324
|
module.exports = isexe;
|
|
146696
147325
|
isexe.sync = sync;
|
|
146697
|
-
var
|
|
147326
|
+
var fs71 = __require("fs");
|
|
146698
147327
|
function checkPathExt(path80, options) {
|
|
146699
147328
|
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
146700
147329
|
if (!pathext) {
|
|
@@ -146719,12 +147348,12 @@ var require_windows = __commonJS({
|
|
|
146719
147348
|
return checkPathExt(path80, options);
|
|
146720
147349
|
}
|
|
146721
147350
|
function isexe(path80, options, cb) {
|
|
146722
|
-
|
|
147351
|
+
fs71.stat(path80, function(er, stat) {
|
|
146723
147352
|
cb(er, er ? false : checkStat(stat, path80, options));
|
|
146724
147353
|
});
|
|
146725
147354
|
}
|
|
146726
147355
|
function sync(path80, options) {
|
|
146727
|
-
return checkStat(
|
|
147356
|
+
return checkStat(fs71.statSync(path80), path80, options);
|
|
146728
147357
|
}
|
|
146729
147358
|
}
|
|
146730
147359
|
});
|
|
@@ -146734,14 +147363,14 @@ var require_mode = __commonJS({
|
|
|
146734
147363
|
"node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.js"(exports, module) {
|
|
146735
147364
|
module.exports = isexe;
|
|
146736
147365
|
isexe.sync = sync;
|
|
146737
|
-
var
|
|
147366
|
+
var fs71 = __require("fs");
|
|
146738
147367
|
function isexe(path80, options, cb) {
|
|
146739
|
-
|
|
147368
|
+
fs71.stat(path80, function(er, stat) {
|
|
146740
147369
|
cb(er, er ? false : checkStat(stat, options));
|
|
146741
147370
|
});
|
|
146742
147371
|
}
|
|
146743
147372
|
function sync(path80, options) {
|
|
146744
|
-
return checkStat(
|
|
147373
|
+
return checkStat(fs71.statSync(path80), options);
|
|
146745
147374
|
}
|
|
146746
147375
|
function checkStat(stat, options) {
|
|
146747
147376
|
return stat.isFile() && checkMode(stat, options);
|
|
@@ -146765,7 +147394,7 @@ var require_mode = __commonJS({
|
|
|
146765
147394
|
// node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js
|
|
146766
147395
|
var require_isexe = __commonJS({
|
|
146767
147396
|
"node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js"(exports, module) {
|
|
146768
|
-
var
|
|
147397
|
+
var fs71 = __require("fs");
|
|
146769
147398
|
var core2;
|
|
146770
147399
|
if (process.platform === "win32" || global.TESTING_WINDOWS) {
|
|
146771
147400
|
core2 = require_windows();
|
|
@@ -147029,16 +147658,16 @@ var require_shebang_command = __commonJS({
|
|
|
147029
147658
|
var require_readShebang = __commonJS({
|
|
147030
147659
|
"node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js"(exports, module) {
|
|
147031
147660
|
"use strict";
|
|
147032
|
-
var
|
|
147661
|
+
var fs71 = __require("fs");
|
|
147033
147662
|
var shebangCommand = require_shebang_command();
|
|
147034
147663
|
function readShebang(command) {
|
|
147035
147664
|
const size = 150;
|
|
147036
147665
|
const buffer = Buffer.alloc(size);
|
|
147037
147666
|
let fd;
|
|
147038
147667
|
try {
|
|
147039
|
-
fd =
|
|
147040
|
-
|
|
147041
|
-
|
|
147668
|
+
fd = fs71.openSync(command, "r");
|
|
147669
|
+
fs71.readSync(fd, buffer, 0, size, 0);
|
|
147670
|
+
fs71.closeSync(fd);
|
|
147042
147671
|
} catch (e) {
|
|
147043
147672
|
}
|
|
147044
147673
|
return shebangCommand(buffer.toString());
|
|
@@ -147442,7 +148071,7 @@ var require_package = __commonJS({
|
|
|
147442
148071
|
// node_modules/.pnpm/dotenv@16.6.1/node_modules/dotenv/lib/main.js
|
|
147443
148072
|
var require_main = __commonJS({
|
|
147444
148073
|
"node_modules/.pnpm/dotenv@16.6.1/node_modules/dotenv/lib/main.js"(exports, module) {
|
|
147445
|
-
var
|
|
148074
|
+
var fs71 = __require("fs");
|
|
147446
148075
|
var path80 = __require("path");
|
|
147447
148076
|
var os15 = __require("os");
|
|
147448
148077
|
var crypto6 = __require("crypto");
|
|
@@ -147551,7 +148180,7 @@ var require_main = __commonJS({
|
|
|
147551
148180
|
if (options && options.path && options.path.length > 0) {
|
|
147552
148181
|
if (Array.isArray(options.path)) {
|
|
147553
148182
|
for (const filepath of options.path) {
|
|
147554
|
-
if (
|
|
148183
|
+
if (fs71.existsSync(filepath)) {
|
|
147555
148184
|
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
147556
148185
|
}
|
|
147557
148186
|
}
|
|
@@ -147561,7 +148190,7 @@ var require_main = __commonJS({
|
|
|
147561
148190
|
} else {
|
|
147562
148191
|
possibleVaultPath = path80.resolve(process.cwd(), ".env.vault");
|
|
147563
148192
|
}
|
|
147564
|
-
if (
|
|
148193
|
+
if (fs71.existsSync(possibleVaultPath)) {
|
|
147565
148194
|
return possibleVaultPath;
|
|
147566
148195
|
}
|
|
147567
148196
|
return null;
|
|
@@ -147610,7 +148239,7 @@ var require_main = __commonJS({
|
|
|
147610
148239
|
const parsedAll = {};
|
|
147611
148240
|
for (const path81 of optionPaths) {
|
|
147612
148241
|
try {
|
|
147613
|
-
const parsed = DotenvModule.parse(
|
|
148242
|
+
const parsed = DotenvModule.parse(fs71.readFileSync(path81, { encoding }));
|
|
147614
148243
|
DotenvModule.populate(parsedAll, parsed, options);
|
|
147615
148244
|
} catch (e) {
|
|
147616
148245
|
if (debug2) {
|
|
@@ -148446,7 +149075,7 @@ var init_schemas2 = __esm({
|
|
|
148446
149075
|
// packages/core/dist/services/llm/cli-provider.js
|
|
148447
149076
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
148448
149077
|
import { join as join10 } from "node:path";
|
|
148449
|
-
import { tmpdir } from "node:os";
|
|
149078
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
148450
149079
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
148451
149080
|
var import_cross_spawn, BaseCLIProvider, ClaudeCodeProvider;
|
|
148452
149081
|
var init_cli_provider = __esm({
|
|
@@ -148516,7 +149145,7 @@ var init_cli_provider = __esm({
|
|
|
148516
149145
|
constructor(transport) {
|
|
148517
149146
|
this.transport = transport;
|
|
148518
149147
|
if (process.env.TRUECOURSE_CLI_DEBUG) {
|
|
148519
|
-
this.debugDir = join10(
|
|
149148
|
+
this.debugDir = join10(tmpdir2(), "truecourse-cli-debug");
|
|
148520
149149
|
mkdirSync2(this.debugDir, { recursive: true });
|
|
148521
149150
|
log.info(`[CLI] Debug output: ${this.debugDir}`);
|
|
148522
149151
|
}
|
|
@@ -148629,8 +149258,13 @@ var init_cli_provider = __esm({
|
|
|
148629
149258
|
unregisterChildProcess(this._repoId, child);
|
|
148630
149259
|
reject(new Error(`[CLI] Failed to spawn ${this.binaryName}: ${err.message}`));
|
|
148631
149260
|
});
|
|
148632
|
-
child.stdin.
|
|
148633
|
-
|
|
149261
|
+
child.stdin.on("error", () => {
|
|
149262
|
+
});
|
|
149263
|
+
try {
|
|
149264
|
+
child.stdin.write(prompt);
|
|
149265
|
+
child.stdin.end();
|
|
149266
|
+
} catch {
|
|
149267
|
+
}
|
|
148634
149268
|
});
|
|
148635
149269
|
}
|
|
148636
149270
|
/** Extract usage data from CLI JSON envelope if present. */
|
|
@@ -149191,7 +149825,7 @@ var init_provider = __esm({
|
|
|
149191
149825
|
});
|
|
149192
149826
|
|
|
149193
149827
|
// packages/core/dist/services/llm/context-router.js
|
|
149194
|
-
function
|
|
149828
|
+
function isTestFile3(filePath) {
|
|
149195
149829
|
return TEST_PATTERNS.some((p2) => filePath.includes(p2));
|
|
149196
149830
|
}
|
|
149197
149831
|
function matchesFileFilter(fa, filter2, fileContent) {
|
|
@@ -149226,7 +149860,7 @@ function matchesFileFilter(fa, filter2, fileContent) {
|
|
|
149226
149860
|
return false;
|
|
149227
149861
|
}
|
|
149228
149862
|
if (filter2.isTestFile !== void 0) {
|
|
149229
|
-
if (filter2.isTestFile !==
|
|
149863
|
+
if (filter2.isTestFile !== isTestFile3(fa.filePath))
|
|
149230
149864
|
return false;
|
|
149231
149865
|
}
|
|
149232
149866
|
if (filter2.languages) {
|
|
@@ -150043,7 +150677,7 @@ function findCSharpProjectFiles(repoPath) {
|
|
|
150043
150677
|
continue;
|
|
150044
150678
|
walk20(path16.join(dir, e.name), depth + 1);
|
|
150045
150679
|
} else if (e.isFile()) {
|
|
150046
|
-
if (e.name.endsWith(".sln"))
|
|
150680
|
+
if (e.name.endsWith(".sln") || e.name.endsWith(".slnx"))
|
|
150047
150681
|
solutions.push(path16.join(dir, e.name));
|
|
150048
150682
|
else if (e.name.endsWith(".csproj"))
|
|
150049
150683
|
projects.push(path16.join(dir, e.name));
|
|
@@ -150306,6 +150940,29 @@ async function runViolationPipeline(input) {
|
|
|
150306
150940
|
}
|
|
150307
150941
|
}
|
|
150308
150942
|
}
|
|
150943
|
+
{
|
|
150944
|
+
const detByDomain = /* @__PURE__ */ new Map();
|
|
150945
|
+
for (const v of allCodeViolations) {
|
|
150946
|
+
const d3 = v.ruleKey.split("/")[0];
|
|
150947
|
+
detByDomain.set(d3, (detByDomain.get(d3) ?? 0) + 1);
|
|
150948
|
+
}
|
|
150949
|
+
const archDet = serviceViolationResults.length + moduleViolationResults.length + methodViolationResults.length;
|
|
150950
|
+
if (archDet > 0)
|
|
150951
|
+
detByDomain.set("architecture", (detByDomain.get("architecture") ?? 0) + archDet);
|
|
150952
|
+
for (const domain of DOMAIN_ORDER) {
|
|
150953
|
+
const count = detByDomain.get(domain) ?? 0;
|
|
150954
|
+
tracker?.done(domain, count > 0 ? `${count} violations` : "Clean");
|
|
150955
|
+
}
|
|
150956
|
+
}
|
|
150957
|
+
const detViolationCount = allCodeViolations.length;
|
|
150958
|
+
let csharpStepActive = false;
|
|
150959
|
+
const startCsharpStep = (detail) => {
|
|
150960
|
+
if (!csharpStepActive) {
|
|
150961
|
+
tracker?.ensureStep("csharp", "C# semantic analysis");
|
|
150962
|
+
csharpStepActive = true;
|
|
150963
|
+
}
|
|
150964
|
+
tracker?.start("csharp", detail);
|
|
150965
|
+
};
|
|
150309
150966
|
const enabledHostRules = enabledCodeRules.filter((r) => r.engine === "roslyn-host");
|
|
150310
150967
|
if (enabledHostRules.length > 0) {
|
|
150311
150968
|
const csharpFiles = [];
|
|
@@ -150319,6 +150976,7 @@ async function runViolationPipeline(input) {
|
|
|
150319
150976
|
csharpFiles.push({ path: key4, text: fc.content });
|
|
150320
150977
|
}
|
|
150321
150978
|
if (csharpFiles.length > 0) {
|
|
150979
|
+
startCsharpStep(`Analyzing ${csharpFiles.length} C# files\u2026`);
|
|
150322
150980
|
const ruleByKey = new Map(enabledHostRules.map((r) => [r.key, r]));
|
|
150323
150981
|
const hostViolations = await runRoslynHost(csharpFiles, enabledHostRules.map((r) => r.key));
|
|
150324
150982
|
for (const v of hostViolations) {
|
|
@@ -150345,19 +151003,20 @@ async function runViolationPipeline(input) {
|
|
|
150345
151003
|
if (enabledWorkspaceRules.length > 0 && filesToScan.some((f2) => detectLanguage(f2.filePath) === "csharp")) {
|
|
150346
151004
|
const projectFiles = findCSharpProjectFiles(repoPath);
|
|
150347
151005
|
if (projectFiles.length === 0) {
|
|
150348
|
-
log.info("[Pipeline] C# present but no .csproj/.sln found \u2014 project-aware C# rules skipped");
|
|
151006
|
+
log.info("[Pipeline] C# present but no .csproj/.sln/.slnx found \u2014 project-aware C# rules skipped");
|
|
150349
151007
|
} else {
|
|
150350
151008
|
const ruleByKey = new Map(enabledWorkspaceRules.map((r) => [r.key, r]));
|
|
150351
151009
|
const ruleKeys = enabledWorkspaceRules.map((r) => r.key);
|
|
150352
|
-
for (const projectFile of projectFiles) {
|
|
151010
|
+
for (const [pi, projectFile] of projectFiles.entries()) {
|
|
151011
|
+
startCsharpStep(projectFiles.length > 1 ? `Loading project ${pi + 1}/${projectFiles.length}: ${path16.basename(projectFile)}\u2026` : `Loading project ${path16.basename(projectFile)}\u2026`);
|
|
150353
151012
|
let wsViolations;
|
|
150354
151013
|
try {
|
|
150355
151014
|
wsViolations = await runRoslynWorkspace(projectFile, ruleKeys);
|
|
150356
151015
|
} catch (err) {
|
|
151016
|
+
tracker?.error("csharp", `Project load failed: ${path16.basename(projectFile)}`);
|
|
150357
151017
|
if (err instanceof RoslynHostUnavailableError)
|
|
150358
151018
|
throw err;
|
|
150359
|
-
|
|
150360
|
-
continue;
|
|
151019
|
+
throw new Error(`Project-aware C# analysis failed for ${path16.basename(projectFile)}: ${err.message}. Restore the project (\`dotnet restore\`) and ensure its pinned .NET SDK is installed.`);
|
|
150361
151020
|
}
|
|
150362
151021
|
for (const v of wsViolations) {
|
|
150363
151022
|
const rule = ruleByKey.get(v.ruleKey);
|
|
@@ -150389,6 +151048,10 @@ async function runViolationPipeline(input) {
|
|
|
150389
151048
|
}
|
|
150390
151049
|
}
|
|
150391
151050
|
}
|
|
151051
|
+
if (csharpStepActive) {
|
|
151052
|
+
const csharpFindings = allCodeViolations.length - detViolationCount;
|
|
151053
|
+
tracker?.done("csharp", csharpFindings > 0 ? `${csharpFindings} violations` : "Clean");
|
|
151054
|
+
}
|
|
150392
151055
|
log.info(`[Pipeline] Code scan: ${allCodeViolations.length} violations from ${filesToScan.length} files (${enabledCodeRules.length} det rules, ${enabledLlmCodeRules.length} LLM rules)`);
|
|
150393
151056
|
if (enabledCodeRules.some((r) => r.key === "bugs/deterministic/invalid-pyproject-toml")) {
|
|
150394
151057
|
const pyprojectPath = path16.join(repoPath, "pyproject.toml");
|
|
@@ -150434,10 +151097,6 @@ async function runViolationPipeline(input) {
|
|
|
150434
151097
|
}
|
|
150435
151098
|
const totalDet = [...violationsByDomain.values()].reduce((a, b) => a + b, 0);
|
|
150436
151099
|
log.info(`[Pipeline] Totals: ${DOMAIN_ORDER.filter((d3) => violationsByDomain.has(d3)).map((d3) => `${d3}=${violationsByDomain.get(d3)}`).join(", ")} (${totalDet})`);
|
|
150437
|
-
for (const domain of DOMAIN_ORDER) {
|
|
150438
|
-
const count = violationsByDomain.get(domain) ?? 0;
|
|
150439
|
-
tracker?.done(domain, count > 0 ? `${count} violations` : "Clean");
|
|
150440
|
-
}
|
|
150441
151100
|
onProgress?.({ step: "analyzing", percent: 84, detail: "Code checks done" });
|
|
150442
151101
|
const prevLlmCodeByFile = /* @__PURE__ */ new Map();
|
|
150443
151102
|
for (const cv of previousActiveCodeViolations) {
|
|
@@ -161703,7 +162362,7 @@ var require_form_data = __commonJS({
|
|
|
161703
162362
|
var http = __require("http");
|
|
161704
162363
|
var https = __require("https");
|
|
161705
162364
|
var parseUrl = __require("url").parse;
|
|
161706
|
-
var
|
|
162365
|
+
var fs71 = __require("fs");
|
|
161707
162366
|
var Stream = __require("stream").Stream;
|
|
161708
162367
|
var crypto6 = __require("crypto");
|
|
161709
162368
|
var mime = require_mime_types();
|
|
@@ -161770,7 +162429,7 @@ var require_form_data = __commonJS({
|
|
|
161770
162429
|
if (value.end != void 0 && value.end != Infinity && value.start != void 0) {
|
|
161771
162430
|
callback(null, value.end + 1 - (value.start ? value.start : 0));
|
|
161772
162431
|
} else {
|
|
161773
|
-
|
|
162432
|
+
fs71.stat(value.path, function(err, stat) {
|
|
161774
162433
|
if (err) {
|
|
161775
162434
|
callback(err);
|
|
161776
162435
|
return;
|
|
@@ -162388,8 +163047,8 @@ var require_node2 = __commonJS({
|
|
|
162388
163047
|
}
|
|
162389
163048
|
break;
|
|
162390
163049
|
case "FILE":
|
|
162391
|
-
var
|
|
162392
|
-
stream2 = new
|
|
163050
|
+
var fs71 = __require("fs");
|
|
163051
|
+
stream2 = new fs71.SyncWriteStream(fd2, { autoClose: false });
|
|
162393
163052
|
stream2._type = "fs";
|
|
162394
163053
|
break;
|
|
162395
163054
|
case "PIPE":
|
|
@@ -167488,21 +168147,21 @@ function node(getModule) {
|
|
|
167488
168147
|
if (lineMatch) {
|
|
167489
168148
|
let object;
|
|
167490
168149
|
let method;
|
|
167491
|
-
let
|
|
168150
|
+
let functionName2;
|
|
167492
168151
|
let typeName2;
|
|
167493
168152
|
let methodName3;
|
|
167494
168153
|
if (lineMatch[1]) {
|
|
167495
|
-
|
|
167496
|
-
let methodStart =
|
|
167497
|
-
if (
|
|
168154
|
+
functionName2 = lineMatch[1];
|
|
168155
|
+
let methodStart = functionName2.lastIndexOf(".");
|
|
168156
|
+
if (functionName2[methodStart - 1] === ".") {
|
|
167498
168157
|
methodStart--;
|
|
167499
168158
|
}
|
|
167500
168159
|
if (methodStart > 0) {
|
|
167501
|
-
object =
|
|
167502
|
-
method =
|
|
168160
|
+
object = functionName2.slice(0, methodStart);
|
|
168161
|
+
method = functionName2.slice(methodStart + 1);
|
|
167503
168162
|
const objectEnd = object.indexOf(".Module");
|
|
167504
168163
|
if (objectEnd > 0) {
|
|
167505
|
-
|
|
168164
|
+
functionName2 = functionName2.slice(objectEnd + 1);
|
|
167506
168165
|
object = object.slice(0, objectEnd);
|
|
167507
168166
|
}
|
|
167508
168167
|
}
|
|
@@ -167514,11 +168173,11 @@ function node(getModule) {
|
|
|
167514
168173
|
}
|
|
167515
168174
|
if (method === "<anonymous>") {
|
|
167516
168175
|
methodName3 = void 0;
|
|
167517
|
-
|
|
168176
|
+
functionName2 = void 0;
|
|
167518
168177
|
}
|
|
167519
|
-
if (
|
|
168178
|
+
if (functionName2 === void 0) {
|
|
167520
168179
|
methodName3 = methodName3 || UNKNOWN_FUNCTION;
|
|
167521
|
-
|
|
168180
|
+
functionName2 = typeName2 ? `${typeName2}.${methodName3}` : methodName3;
|
|
167522
168181
|
}
|
|
167523
168182
|
let filename = lineMatch[2]?.startsWith("file://") ? lineMatch[2].slice(7) : lineMatch[2];
|
|
167524
168183
|
const isNative = lineMatch[5] === "native";
|
|
@@ -167531,7 +168190,7 @@ function node(getModule) {
|
|
|
167531
168190
|
return {
|
|
167532
168191
|
filename: filename ? decodeURI(filename) : void 0,
|
|
167533
168192
|
module: getModule ? getModule(filename) : void 0,
|
|
167534
|
-
function:
|
|
168193
|
+
function: functionName2,
|
|
167535
168194
|
lineno: _parseIntOrUndefined(lineMatch[3]),
|
|
167536
168195
|
colno: _parseIntOrUndefined(lineMatch[4]),
|
|
167537
168196
|
in_app: filenameIsInApp(filename || "", isNative),
|
|
@@ -170369,7 +171028,7 @@ function readToolVersion() {
|
|
|
170369
171028
|
if (cachedVersion)
|
|
170370
171029
|
return cachedVersion;
|
|
170371
171030
|
if (true) {
|
|
170372
|
-
cachedVersion = "0.7.0-next.
|
|
171031
|
+
cachedVersion = "0.7.0-next.5";
|
|
170373
171032
|
return cachedVersion;
|
|
170374
171033
|
}
|
|
170375
171034
|
try {
|
|
@@ -172775,13 +173434,13 @@ var init_pexprs_toFailure = __esm({
|
|
|
172775
173434
|
return new Failure(this, "a Unicode [" + this.categoryOrProp + "] character", "description");
|
|
172776
173435
|
};
|
|
172777
173436
|
Alt.prototype.toFailure = function(grammar2) {
|
|
172778
|
-
const
|
|
172779
|
-
const description = "(" +
|
|
173437
|
+
const fs71 = this.terms.map((t2) => t2.toFailure(grammar2));
|
|
173438
|
+
const description = "(" + fs71.join(" or ") + ")";
|
|
172780
173439
|
return new Failure(this, description, "description");
|
|
172781
173440
|
};
|
|
172782
173441
|
Seq.prototype.toFailure = function(grammar2) {
|
|
172783
|
-
const
|
|
172784
|
-
const description = "(" +
|
|
173442
|
+
const fs71 = this.factors.map((f2) => f2.toFailure(grammar2));
|
|
173443
|
+
const description = "(" + fs71.join(" ") + ")";
|
|
172785
173444
|
return new Failure(this, description, "description");
|
|
172786
173445
|
};
|
|
172787
173446
|
Iter.prototype.toFailure = function(grammar2) {
|
|
@@ -174618,9 +175277,9 @@ function buildGrammar2(match4, namespace, optOhmGrammarForTesting, options) {
|
|
|
174618
175277
|
decl.withSuperGrammar(namespace[superGrammarName]);
|
|
174619
175278
|
}
|
|
174620
175279
|
},
|
|
174621
|
-
Rule_define(n,
|
|
175280
|
+
Rule_define(n, fs71, d3, _2, b) {
|
|
174622
175281
|
currentRuleName = n.visit();
|
|
174623
|
-
currentRuleFormals =
|
|
175282
|
+
currentRuleFormals = fs71.children.map((c2) => c2.visit())[0] || [];
|
|
174624
175283
|
if (!decl.defaultStartRule && decl.ensureSuperGrammar() !== Grammar.ProtoBuiltInRules) {
|
|
174625
175284
|
decl.withDefaultStartRule(currentRuleName);
|
|
174626
175285
|
}
|
|
@@ -174629,9 +175288,9 @@ function buildGrammar2(match4, namespace, optOhmGrammarForTesting, options) {
|
|
|
174629
175288
|
const source = this.source.trimmed();
|
|
174630
175289
|
return decl.define(currentRuleName, currentRuleFormals, body, description, source);
|
|
174631
175290
|
},
|
|
174632
|
-
Rule_override(n,
|
|
175291
|
+
Rule_override(n, fs71, _2, b) {
|
|
174633
175292
|
currentRuleName = n.visit();
|
|
174634
|
-
currentRuleFormals =
|
|
175293
|
+
currentRuleFormals = fs71.children.map((c2) => c2.visit())[0] || [];
|
|
174635
175294
|
const source = this.source.trimmed();
|
|
174636
175295
|
decl.ensureSuperGrammarRuleForOverriding(currentRuleName, source);
|
|
174637
175296
|
overriding = true;
|
|
@@ -174639,9 +175298,9 @@ function buildGrammar2(match4, namespace, optOhmGrammarForTesting, options) {
|
|
|
174639
175298
|
overriding = false;
|
|
174640
175299
|
return decl.override(currentRuleName, currentRuleFormals, body, null, source);
|
|
174641
175300
|
},
|
|
174642
|
-
Rule_extend(n,
|
|
175301
|
+
Rule_extend(n, fs71, _2, b) {
|
|
174643
175302
|
currentRuleName = n.visit();
|
|
174644
|
-
currentRuleFormals =
|
|
175303
|
+
currentRuleFormals = fs71.children.map((c2) => c2.visit())[0] || [];
|
|
174645
175304
|
const body = b.visit();
|
|
174646
175305
|
const source = this.source.trimmed();
|
|
174647
175306
|
return decl.extend(currentRuleName, currentRuleFormals, body, null, source);
|
|
@@ -174668,8 +175327,8 @@ function buildGrammar2(match4, namespace, optOhmGrammarForTesting, options) {
|
|
|
174668
175327
|
return builder.alt(...args).withSource(this.source);
|
|
174669
175328
|
}
|
|
174670
175329
|
},
|
|
174671
|
-
Formals(opointy,
|
|
174672
|
-
return
|
|
175330
|
+
Formals(opointy, fs71, cpointy) {
|
|
175331
|
+
return fs71.visit();
|
|
174673
175332
|
},
|
|
174674
175333
|
Params(opointy, ps, cpointy) {
|
|
174675
175334
|
return ps.visit();
|
|
@@ -174831,8 +175490,8 @@ function initPrototypeParser(grammar2) {
|
|
|
174831
175490
|
formals: optFormals.children.map((c2) => c2.parse())[0] || []
|
|
174832
175491
|
};
|
|
174833
175492
|
},
|
|
174834
|
-
Formals(oparen,
|
|
174835
|
-
return
|
|
175493
|
+
Formals(oparen, fs71, cparen) {
|
|
175494
|
+
return fs71.asIteration().children.map((c2) => c2.parse());
|
|
174836
175495
|
},
|
|
174837
175496
|
name(first2, rest) {
|
|
174838
175497
|
return this.sourceString;
|
|
@@ -178280,9 +178939,9 @@ var init_conformance = __esm({
|
|
|
178280
178939
|
});
|
|
178281
178940
|
|
|
178282
178941
|
// packages/contract-verifier/dist/extractor/source-walker.js
|
|
178283
|
-
import
|
|
178942
|
+
import fs31 from "node:fs";
|
|
178284
178943
|
import path33 from "node:path";
|
|
178285
|
-
function
|
|
178944
|
+
function isTestFile4(filePath) {
|
|
178286
178945
|
const parts = filePath.replace(/\\/g, "/").split("/");
|
|
178287
178946
|
const fileName = parts[parts.length - 1] ?? "";
|
|
178288
178947
|
if (/\.(test|spec)\.[mc]?[jt]sx?$/.test(fileName))
|
|
@@ -178299,7 +178958,7 @@ async function eachParsedSource(rootDir, visit) {
|
|
|
178299
178958
|
const walk20 = (dir) => {
|
|
178300
178959
|
let entries;
|
|
178301
178960
|
try {
|
|
178302
|
-
entries =
|
|
178961
|
+
entries = fs31.readdirSync(dir, { withFileTypes: true });
|
|
178303
178962
|
} catch {
|
|
178304
178963
|
return;
|
|
178305
178964
|
}
|
|
@@ -178315,14 +178974,14 @@ async function eachParsedSource(rootDir, visit) {
|
|
|
178315
178974
|
}
|
|
178316
178975
|
if (!entry.isFile())
|
|
178317
178976
|
continue;
|
|
178318
|
-
if (
|
|
178977
|
+
if (isTestFile4(full))
|
|
178319
178978
|
continue;
|
|
178320
178979
|
const lang = EXT_TO_LANG[path33.extname(entry.name)];
|
|
178321
178980
|
if (!lang)
|
|
178322
178981
|
continue;
|
|
178323
178982
|
let source;
|
|
178324
178983
|
try {
|
|
178325
|
-
source =
|
|
178984
|
+
source = fs31.readFileSync(full, "utf-8");
|
|
178326
178985
|
} catch {
|
|
178327
178986
|
continue;
|
|
178328
178987
|
}
|
|
@@ -178433,19 +179092,19 @@ function readCsharpString(node2, source) {
|
|
|
178433
179092
|
}
|
|
178434
179093
|
if (node2.type === "interpolated_string_expression") {
|
|
178435
179094
|
let text4 = "";
|
|
178436
|
-
let
|
|
179095
|
+
let hasInterpolation = false;
|
|
178437
179096
|
for (let i = 0; i < node2.namedChildCount; i++) {
|
|
178438
179097
|
const c2 = node2.namedChild(i);
|
|
178439
179098
|
if (!c2)
|
|
178440
179099
|
continue;
|
|
178441
179100
|
if (c2.type === "interpolation") {
|
|
178442
179101
|
text4 += " /*INTERP*/ ";
|
|
178443
|
-
|
|
179102
|
+
hasInterpolation = true;
|
|
178444
179103
|
} else {
|
|
178445
179104
|
text4 += source.slice(c2.startIndex, c2.endIndex);
|
|
178446
179105
|
}
|
|
178447
179106
|
}
|
|
178448
|
-
return { text: text4, hasInterpolation
|
|
179107
|
+
return { text: text4, hasInterpolation };
|
|
178449
179108
|
}
|
|
178450
179109
|
if (node2.type === "binary_expression") {
|
|
178451
179110
|
const op = node2.childForFieldName("operator");
|
|
@@ -180410,7 +181069,7 @@ var init_operation_aspnet = __esm({
|
|
|
180410
181069
|
});
|
|
180411
181070
|
|
|
180412
181071
|
// packages/contract-verifier/dist/extractor/file-based-routes.js
|
|
180413
|
-
import
|
|
181072
|
+
import fs32 from "node:fs";
|
|
180414
181073
|
import path34 from "node:path";
|
|
180415
181074
|
async function extractFileBasedRoutesFromDir(rootDir) {
|
|
180416
181075
|
await initParsers();
|
|
@@ -180429,7 +181088,7 @@ function findDirs(rootDir, wantedRel) {
|
|
|
180429
181088
|
const visit = (dir) => {
|
|
180430
181089
|
let entries;
|
|
180431
181090
|
try {
|
|
180432
|
-
entries =
|
|
181091
|
+
entries = fs32.readdirSync(dir, { withFileTypes: true });
|
|
180433
181092
|
} catch {
|
|
180434
181093
|
return;
|
|
180435
181094
|
}
|
|
@@ -180455,7 +181114,7 @@ function findDirs(rootDir, wantedRel) {
|
|
|
180455
181114
|
function walkRoot(rootAbs, root2, out) {
|
|
180456
181115
|
const tcIgnore = loadTcIgnore(rootAbs);
|
|
180457
181116
|
const visit = (dir) => {
|
|
180458
|
-
for (const entry of
|
|
181117
|
+
for (const entry of fs32.readdirSync(dir, { withFileTypes: true })) {
|
|
180459
181118
|
if (entry.name === "node_modules" || entry.name === ".git")
|
|
180460
181119
|
continue;
|
|
180461
181120
|
const full = path34.join(dir, entry.name);
|
|
@@ -180480,7 +181139,7 @@ function walkRoot(rootAbs, root2, out) {
|
|
|
180480
181139
|
const url = deriveUrl(relUnderRoot, root2);
|
|
180481
181140
|
if (url === null)
|
|
180482
181141
|
continue;
|
|
180483
|
-
const source =
|
|
181142
|
+
const source = fs32.readFileSync(full, "utf-8");
|
|
180484
181143
|
const lang = ext2 === ".tsx" ? "tsx" : ext2 === ".ts" ? "typescript" : "javascript";
|
|
180485
181144
|
let tree;
|
|
180486
181145
|
try {
|
|
@@ -180620,7 +181279,7 @@ var init_file_based_routes = __esm({
|
|
|
180620
181279
|
});
|
|
180621
181280
|
|
|
180622
181281
|
// packages/contract-verifier/dist/extractor/mount-graph.js
|
|
180623
|
-
import
|
|
181282
|
+
import fs33 from "node:fs";
|
|
180624
181283
|
import path35 from "node:path";
|
|
180625
181284
|
function analyzeRouterFile(filePath, source, tree) {
|
|
180626
181285
|
const declarations = [];
|
|
@@ -180771,7 +181430,7 @@ function resolveImportPath(fromFile, spec) {
|
|
|
180771
181430
|
];
|
|
180772
181431
|
for (const c2 of candidates) {
|
|
180773
181432
|
const abs = path35.resolve(baseDir, c2);
|
|
180774
|
-
if (
|
|
181433
|
+
if (fs33.existsSync(abs) && fs33.statSync(abs).isFile())
|
|
180775
181434
|
return abs;
|
|
180776
181435
|
}
|
|
180777
181436
|
return null;
|
|
@@ -180956,7 +181615,7 @@ var init_mount_graph = __esm({
|
|
|
180956
181615
|
});
|
|
180957
181616
|
|
|
180958
181617
|
// packages/contract-verifier/dist/extractor/auth-presence.js
|
|
180959
|
-
import
|
|
181618
|
+
import fs34 from "node:fs";
|
|
180960
181619
|
import path36 from "node:path";
|
|
180961
181620
|
async function detectAuthPresence(rootDir) {
|
|
180962
181621
|
await initParsers();
|
|
@@ -180967,7 +181626,7 @@ async function detectAuthPresence(rootDir) {
|
|
|
180967
181626
|
const scanned = [];
|
|
180968
181627
|
const tcIgnore = loadTcIgnore(rootDir);
|
|
180969
181628
|
const visit = (dir) => {
|
|
180970
|
-
for (const entry of
|
|
181629
|
+
for (const entry of fs34.readdirSync(dir, { withFileTypes: true })) {
|
|
180971
181630
|
if (entry.name === "node_modules" || entry.name === ".git")
|
|
180972
181631
|
continue;
|
|
180973
181632
|
const full = path36.join(dir, entry.name);
|
|
@@ -180982,7 +181641,7 @@ async function detectAuthPresence(rootDir) {
|
|
|
180982
181641
|
const ext2 = path36.extname(entry.name);
|
|
180983
181642
|
if (!TS_EXT2.has(ext2))
|
|
180984
181643
|
continue;
|
|
180985
|
-
const source =
|
|
181644
|
+
const source = fs34.readFileSync(full, "utf-8");
|
|
180986
181645
|
const lang = ext2 === ".tsx" ? "tsx" : ext2 === ".ts" ? "typescript" : "javascript";
|
|
180987
181646
|
let tree;
|
|
180988
181647
|
try {
|
|
@@ -181075,7 +181734,7 @@ function resolveImportPath2(importingFile, sourceStr) {
|
|
|
181075
181734
|
candidates.push(path36.join(baseRaw, `index${ext2}`));
|
|
181076
181735
|
}
|
|
181077
181736
|
for (const c2 of candidates) {
|
|
181078
|
-
if (
|
|
181737
|
+
if (fs34.existsSync(c2) && fs34.statSync(c2).isFile())
|
|
181079
181738
|
return c2;
|
|
181080
181739
|
}
|
|
181081
181740
|
return null;
|
|
@@ -181167,7 +181826,7 @@ var init_auth_presence = __esm({
|
|
|
181167
181826
|
});
|
|
181168
181827
|
|
|
181169
181828
|
// packages/contract-verifier/dist/extractor/idempotency-presence.js
|
|
181170
|
-
import
|
|
181829
|
+
import fs35 from "node:fs";
|
|
181171
181830
|
import path37 from "node:path";
|
|
181172
181831
|
function routeKey(filePath, declarationLine) {
|
|
181173
181832
|
return `${filePath}::${declarationLine}`;
|
|
@@ -181180,7 +181839,7 @@ async function detectIdempotencyPresence(rootDir, requestHeader) {
|
|
|
181180
181839
|
const scanned = [];
|
|
181181
181840
|
const tcIgnore = loadTcIgnore(rootDir);
|
|
181182
181841
|
const visit = (dir) => {
|
|
181183
|
-
for (const entry of
|
|
181842
|
+
for (const entry of fs35.readdirSync(dir, { withFileTypes: true })) {
|
|
181184
181843
|
if (entry.name === "node_modules" || entry.name === ".git")
|
|
181185
181844
|
continue;
|
|
181186
181845
|
const full = path37.join(dir, entry.name);
|
|
@@ -181195,7 +181854,7 @@ async function detectIdempotencyPresence(rootDir, requestHeader) {
|
|
|
181195
181854
|
const ext2 = path37.extname(entry.name);
|
|
181196
181855
|
if (!TS_EXT3.has(ext2))
|
|
181197
181856
|
continue;
|
|
181198
|
-
const source =
|
|
181857
|
+
const source = fs35.readFileSync(full, "utf-8");
|
|
181199
181858
|
const lang = ext2 === ".tsx" ? "tsx" : ext2 === ".ts" ? "typescript" : "javascript";
|
|
181200
181859
|
let tree;
|
|
181201
181860
|
try {
|
|
@@ -181426,7 +182085,7 @@ function resolveImportPath3(importingFile, sourceStr) {
|
|
|
181426
182085
|
candidates.push(path37.join(baseRaw, `index${ext2}`));
|
|
181427
182086
|
}
|
|
181428
182087
|
for (const c2 of candidates) {
|
|
181429
|
-
if (
|
|
182088
|
+
if (fs35.existsSync(c2) && fs35.statSync(c2).isFile())
|
|
181430
182089
|
return c2;
|
|
181431
182090
|
}
|
|
181432
182091
|
return null;
|
|
@@ -182448,14 +183107,14 @@ function getSqlText(node2, source) {
|
|
|
182448
183107
|
return { text: source.slice(node2.startIndex, node2.endIndex), hasInterpolation: false };
|
|
182449
183108
|
}
|
|
182450
183109
|
function extractFromSqlSource(sqlNode, filePath, source) {
|
|
182451
|
-
const { text: text4, hasInterpolation
|
|
182452
|
-
return buildQueriesFromSqlText(text4,
|
|
183110
|
+
const { text: text4, hasInterpolation } = getSqlText(sqlNode, source);
|
|
183111
|
+
return buildQueriesFromSqlText(text4, hasInterpolation, {
|
|
182453
183112
|
filePath,
|
|
182454
183113
|
lineStart: sqlNode.startPosition.row + 1,
|
|
182455
183114
|
lineEnd: sqlNode.endPosition.row + 1
|
|
182456
183115
|
});
|
|
182457
183116
|
}
|
|
182458
|
-
function buildQueriesFromSqlText(text4,
|
|
183117
|
+
function buildQueriesFromSqlText(text4, hasInterpolation, loc, adapterName = "raw-sql") {
|
|
182459
183118
|
if (!text4 || !/\bSELECT\b/i.test(text4))
|
|
182460
183119
|
return [];
|
|
182461
183120
|
const blocks = splitSelectBlocks(text4);
|
|
@@ -182474,7 +183133,7 @@ function buildQueriesFromSqlText(text4, hasInterpolation2, loc, adapterName = "r
|
|
|
182474
183133
|
else
|
|
182475
183134
|
unparseable.push({ reason: "unrecognised SQL predicate", raw: piece });
|
|
182476
183135
|
}
|
|
182477
|
-
if (
|
|
183136
|
+
if (hasInterpolation) {
|
|
182478
183137
|
unparseable.push({ reason: "string-interpolation substitution skipped", raw: "${...}" });
|
|
182479
183138
|
}
|
|
182480
183139
|
out.push({
|
|
@@ -182836,7 +183495,7 @@ function pySqlText(node2, source) {
|
|
|
182836
183495
|
function readPyStringNode(node2, source) {
|
|
182837
183496
|
if (node2.type === "concatenated_string") {
|
|
182838
183497
|
let text5 = "";
|
|
182839
|
-
let
|
|
183498
|
+
let hasInterpolation2 = false;
|
|
182840
183499
|
for (let i = 0; i < node2.namedChildCount; i++) {
|
|
182841
183500
|
const c2 = node2.namedChild(i);
|
|
182842
183501
|
if (!c2)
|
|
@@ -182844,15 +183503,15 @@ function readPyStringNode(node2, source) {
|
|
|
182844
183503
|
const part = readPyStringNode(c2, source);
|
|
182845
183504
|
if (part) {
|
|
182846
183505
|
text5 += part.text;
|
|
182847
|
-
|
|
183506
|
+
hasInterpolation2 = hasInterpolation2 || part.hasInterpolation;
|
|
182848
183507
|
}
|
|
182849
183508
|
}
|
|
182850
|
-
return { text: text5, hasInterpolation:
|
|
183509
|
+
return { text: text5, hasInterpolation: hasInterpolation2 };
|
|
182851
183510
|
}
|
|
182852
183511
|
if (node2.type !== "string")
|
|
182853
183512
|
return null;
|
|
182854
183513
|
let text4 = "";
|
|
182855
|
-
let
|
|
183514
|
+
let hasInterpolation = false;
|
|
182856
183515
|
for (let i = 0; i < node2.namedChildCount; i++) {
|
|
182857
183516
|
const c2 = node2.namedChild(i);
|
|
182858
183517
|
if (!c2)
|
|
@@ -182861,10 +183520,10 @@ function readPyStringNode(node2, source) {
|
|
|
182861
183520
|
text4 += source.slice(c2.startIndex, c2.endIndex);
|
|
182862
183521
|
else if (c2.type === "interpolation") {
|
|
182863
183522
|
text4 += " /*INTERP*/ ";
|
|
182864
|
-
|
|
183523
|
+
hasInterpolation = true;
|
|
182865
183524
|
}
|
|
182866
183525
|
}
|
|
182867
|
-
return { text: text4, hasInterpolation
|
|
183526
|
+
return { text: text4, hasInterpolation };
|
|
182868
183527
|
}
|
|
182869
183528
|
var SQL_HOST_METHODS, SQL_TAG_NAMES, COL, VAL, PY_SQL_EXEC_METHODS;
|
|
182870
183529
|
var init_raw_sql = __esm({
|
|
@@ -184811,7 +185470,7 @@ var init_minimatch = __esm({
|
|
|
184811
185470
|
});
|
|
184812
185471
|
|
|
184813
185472
|
// packages/contract-verifier/dist/extractor/manifests.js
|
|
184814
|
-
import
|
|
185473
|
+
import fs36 from "node:fs";
|
|
184815
185474
|
import path39 from "node:path";
|
|
184816
185475
|
function collectDependencies(rootDir) {
|
|
184817
185476
|
const out = [];
|
|
@@ -184819,7 +185478,7 @@ function collectDependencies(rootDir) {
|
|
|
184819
185478
|
const visit = (dir) => {
|
|
184820
185479
|
let entries;
|
|
184821
185480
|
try {
|
|
184822
|
-
entries =
|
|
185481
|
+
entries = fs36.readdirSync(dir, { withFileTypes: true });
|
|
184823
185482
|
} catch {
|
|
184824
185483
|
return;
|
|
184825
185484
|
}
|
|
@@ -184857,7 +185516,7 @@ function collectDependencies(rootDir) {
|
|
|
184857
185516
|
function readPackageJson(filePath) {
|
|
184858
185517
|
let pkg;
|
|
184859
185518
|
try {
|
|
184860
|
-
pkg = JSON.parse(
|
|
185519
|
+
pkg = JSON.parse(fs36.readFileSync(filePath, "utf-8"));
|
|
184861
185520
|
} catch {
|
|
184862
185521
|
return [];
|
|
184863
185522
|
}
|
|
@@ -184882,7 +185541,7 @@ function pyDistName(spec) {
|
|
|
184882
185541
|
function readRequirements(filePath) {
|
|
184883
185542
|
let text4;
|
|
184884
185543
|
try {
|
|
184885
|
-
text4 =
|
|
185544
|
+
text4 = fs36.readFileSync(filePath, "utf-8");
|
|
184886
185545
|
} catch {
|
|
184887
185546
|
return [];
|
|
184888
185547
|
}
|
|
@@ -184897,7 +185556,7 @@ function readRequirements(filePath) {
|
|
|
184897
185556
|
function readPyproject(filePath) {
|
|
184898
185557
|
let text4;
|
|
184899
185558
|
try {
|
|
184900
|
-
text4 =
|
|
185559
|
+
text4 = fs36.readFileSync(filePath, "utf-8");
|
|
184901
185560
|
} catch {
|
|
184902
185561
|
return [];
|
|
184903
185562
|
}
|
|
@@ -184922,7 +185581,7 @@ function readPyproject(filePath) {
|
|
|
184922
185581
|
function readSetupPy(filePath) {
|
|
184923
185582
|
let text4;
|
|
184924
185583
|
try {
|
|
184925
|
-
text4 =
|
|
185584
|
+
text4 = fs36.readFileSync(filePath, "utf-8");
|
|
184926
185585
|
} catch {
|
|
184927
185586
|
return [];
|
|
184928
185587
|
}
|
|
@@ -184940,7 +185599,7 @@ function readSetupPy(filePath) {
|
|
|
184940
185599
|
function readXmlPackageTags(filePath, tag, idAttr, versionAttr, field) {
|
|
184941
185600
|
let text4;
|
|
184942
185601
|
try {
|
|
184943
|
-
text4 =
|
|
185602
|
+
text4 = fs36.readFileSync(filePath, "utf-8");
|
|
184944
185603
|
} catch {
|
|
184945
185604
|
return [];
|
|
184946
185605
|
}
|
|
@@ -184992,7 +185651,7 @@ var init_manifests = __esm({
|
|
|
184992
185651
|
});
|
|
184993
185652
|
|
|
184994
185653
|
// packages/contract-verifier/dist/extractor/forbidden/index.js
|
|
184995
|
-
import
|
|
185654
|
+
import fs37 from "node:fs";
|
|
184996
185655
|
import path40 from "node:path";
|
|
184997
185656
|
function detectForbiddenFiles(rootDir, pattern) {
|
|
184998
185657
|
const out = [];
|
|
@@ -185000,7 +185659,7 @@ function detectForbiddenFiles(rootDir, pattern) {
|
|
|
185000
185659
|
const visit = (dir) => {
|
|
185001
185660
|
let entries;
|
|
185002
185661
|
try {
|
|
185003
|
-
entries =
|
|
185662
|
+
entries = fs37.readdirSync(dir, { withFileTypes: true });
|
|
185004
185663
|
} catch {
|
|
185005
185664
|
return;
|
|
185006
185665
|
}
|
|
@@ -185237,7 +185896,7 @@ function detectFlagInConfigFiles(rootDir, name) {
|
|
|
185237
185896
|
const visit = (dir) => {
|
|
185238
185897
|
let entries;
|
|
185239
185898
|
try {
|
|
185240
|
-
entries =
|
|
185899
|
+
entries = fs37.readdirSync(dir, { withFileTypes: true });
|
|
185241
185900
|
} catch {
|
|
185242
185901
|
return;
|
|
185243
185902
|
}
|
|
@@ -185256,7 +185915,7 @@ function detectFlagInConfigFiles(rootDir, name) {
|
|
|
185256
185915
|
continue;
|
|
185257
185916
|
let source;
|
|
185258
185917
|
try {
|
|
185259
|
-
source =
|
|
185918
|
+
source = fs37.readFileSync(full, "utf-8");
|
|
185260
185919
|
} catch {
|
|
185261
185920
|
continue;
|
|
185262
185921
|
}
|
|
@@ -188315,7 +188974,7 @@ var init_emission_facts = __esm({
|
|
|
188315
188974
|
});
|
|
188316
188975
|
|
|
188317
188976
|
// packages/contract-verifier/dist/extractor/entity-schema/index.js
|
|
188318
|
-
import
|
|
188977
|
+
import fs38 from "node:fs";
|
|
188319
188978
|
import path41 from "node:path";
|
|
188320
188979
|
async function extractEntitiesFromDir(rootDir) {
|
|
188321
188980
|
const tcIgnore = loadTcIgnore(rootDir);
|
|
@@ -188323,7 +188982,7 @@ async function extractEntitiesFromDir(rootDir) {
|
|
|
188323
188982
|
const walk20 = (dir) => {
|
|
188324
188983
|
let entries;
|
|
188325
188984
|
try {
|
|
188326
|
-
entries =
|
|
188985
|
+
entries = fs38.readdirSync(dir, { withFileTypes: true });
|
|
188327
188986
|
} catch {
|
|
188328
188987
|
return;
|
|
188329
188988
|
}
|
|
@@ -188336,7 +188995,7 @@ async function extractEntitiesFromDir(rootDir) {
|
|
|
188336
188995
|
if (e.isDirectory())
|
|
188337
188996
|
walk20(full);
|
|
188338
188997
|
else if (e.isFile() && e.name.endsWith(".prisma")) {
|
|
188339
|
-
out.push(...parsePrismaModels(full,
|
|
188998
|
+
out.push(...parsePrismaModels(full, fs38.readFileSync(full, "utf-8")));
|
|
188340
188999
|
}
|
|
188341
189000
|
}
|
|
188342
189001
|
};
|
|
@@ -189958,7 +190617,7 @@ var init_characteristic_imports = __esm({
|
|
|
189958
190617
|
});
|
|
189959
190618
|
|
|
189960
190619
|
// packages/contract-verifier/dist/extractor/architecture/shared/config-files.js
|
|
189961
|
-
import
|
|
190620
|
+
import fs39 from "node:fs";
|
|
189962
190621
|
import path42 from "node:path";
|
|
189963
190622
|
function collectFileIndex(rootDir) {
|
|
189964
190623
|
const files = [];
|
|
@@ -189967,7 +190626,7 @@ function collectFileIndex(rootDir) {
|
|
|
189967
190626
|
const visit = (dir) => {
|
|
189968
190627
|
let entries;
|
|
189969
190628
|
try {
|
|
189970
|
-
entries =
|
|
190629
|
+
entries = fs39.readdirSync(dir, { withFileTypes: true });
|
|
189971
190630
|
} catch {
|
|
189972
190631
|
return;
|
|
189973
190632
|
}
|
|
@@ -189993,7 +190652,7 @@ function collectFileIndex(rootDir) {
|
|
|
189993
190652
|
return cache3.get(relPath);
|
|
189994
190653
|
let text4;
|
|
189995
190654
|
try {
|
|
189996
|
-
text4 =
|
|
190655
|
+
text4 = fs39.readFileSync(path42.join(rootDir, relPath), "utf-8");
|
|
189997
190656
|
} catch {
|
|
189998
190657
|
text4 = null;
|
|
189999
190658
|
}
|
|
@@ -190450,9 +191109,9 @@ __export(extractor_exports, {
|
|
|
190450
191109
|
extractValidationRulesFromDir: () => extractValidationRulesFromDir,
|
|
190451
191110
|
getArchitectureDetector: () => getArchitectureDetector
|
|
190452
191111
|
});
|
|
190453
|
-
import
|
|
191112
|
+
import fs40 from "node:fs";
|
|
190454
191113
|
import path44 from "node:path";
|
|
190455
|
-
function
|
|
191114
|
+
function isTestFile5(filePath) {
|
|
190456
191115
|
const parts = filePath.replace(/\\/g, "/").split("/");
|
|
190457
191116
|
const fileName = parts[parts.length - 1];
|
|
190458
191117
|
if (/\.(test|spec)\.(t|j)sx?$/.test(fileName))
|
|
@@ -190467,7 +191126,7 @@ async function extractOperationsFromDir(rootDir) {
|
|
|
190467
191126
|
const fileAnalyses = [];
|
|
190468
191127
|
const tcIgnore = loadTcIgnore(rootDir);
|
|
190469
191128
|
const visit = (dir) => {
|
|
190470
|
-
for (const entry of
|
|
191129
|
+
for (const entry of fs40.readdirSync(dir, { withFileTypes: true })) {
|
|
190471
191130
|
if (entry.name === "node_modules" || entry.name === ".git")
|
|
190472
191131
|
continue;
|
|
190473
191132
|
const full = path44.join(dir, entry.name);
|
|
@@ -190482,9 +191141,9 @@ async function extractOperationsFromDir(rootDir) {
|
|
|
190482
191141
|
const ext2 = path44.extname(entry.name);
|
|
190483
191142
|
if (!TS_EXT4.has(ext2))
|
|
190484
191143
|
continue;
|
|
190485
|
-
if (
|
|
191144
|
+
if (isTestFile5(full))
|
|
190486
191145
|
continue;
|
|
190487
|
-
const source =
|
|
191146
|
+
const source = fs40.readFileSync(full, "utf-8");
|
|
190488
191147
|
const lang = ext2 === ".ts" || ext2 === ".tsx" ? ext2 === ".tsx" ? "tsx" : "typescript" : "javascript";
|
|
190489
191148
|
let tree;
|
|
190490
191149
|
try {
|
|
@@ -192934,17 +193593,17 @@ var init_symbol_index = __esm({
|
|
|
192934
193593
|
});
|
|
192935
193594
|
|
|
192936
193595
|
// packages/contract-verifier/dist/verify.js
|
|
192937
|
-
import
|
|
193596
|
+
import fs41 from "node:fs";
|
|
192938
193597
|
import path46 from "node:path";
|
|
192939
193598
|
async function verify(opts) {
|
|
192940
193599
|
const specFiles = [];
|
|
192941
193600
|
walkTcFiles(opts.contractsDir, (filePath) => {
|
|
192942
|
-
specFiles.push({ path: filePath, source:
|
|
193601
|
+
specFiles.push({ path: filePath, source: fs41.readFileSync(filePath, "utf-8") });
|
|
192943
193602
|
}, opts.includeInferred ?? false);
|
|
192944
193603
|
const baseFiles = [];
|
|
192945
|
-
if (opts.baseContractsDir &&
|
|
193604
|
+
if (opts.baseContractsDir && fs41.existsSync(opts.baseContractsDir)) {
|
|
192946
193605
|
walkTcFiles(opts.baseContractsDir, (filePath) => {
|
|
192947
|
-
const source =
|
|
193606
|
+
const source = fs41.readFileSync(filePath, "utf-8");
|
|
192948
193607
|
baseFiles.push(parseTcFile(filePath, source));
|
|
192949
193608
|
}, opts.includeInferred ?? false);
|
|
192950
193609
|
}
|
|
@@ -193334,7 +193993,7 @@ async function verify(opts) {
|
|
|
193334
193993
|
};
|
|
193335
193994
|
}
|
|
193336
193995
|
function walkTcFiles(rootDir, visit, includeInferred) {
|
|
193337
|
-
for (const entry of
|
|
193996
|
+
for (const entry of fs41.readdirSync(rootDir, { withFileTypes: true })) {
|
|
193338
193997
|
const full = path46.join(rootDir, entry.name);
|
|
193339
193998
|
if (entry.isDirectory()) {
|
|
193340
193999
|
if (!includeInferred && entry.name === "_inferred")
|
|
@@ -193629,7 +194288,7 @@ var init_serialize = __esm({
|
|
|
193629
194288
|
});
|
|
193630
194289
|
|
|
193631
194290
|
// packages/contract-verifier/dist/infer/index.js
|
|
193632
|
-
import
|
|
194291
|
+
import fs42 from "node:fs";
|
|
193633
194292
|
import path48 from "node:path";
|
|
193634
194293
|
async function infer(opts) {
|
|
193635
194294
|
const authored = loadAuthored(opts.contractsDir);
|
|
@@ -193657,7 +194316,7 @@ async function infer(opts) {
|
|
|
193657
194316
|
function loadAuthored(contractsDir) {
|
|
193658
194317
|
const files = [];
|
|
193659
194318
|
walkAuthoredTcFiles(contractsDir, (filePath) => {
|
|
193660
|
-
files.push({ path: filePath, source:
|
|
194319
|
+
files.push({ path: filePath, source: fs42.readFileSync(filePath, "utf-8") });
|
|
193661
194320
|
});
|
|
193662
194321
|
return parseAndResolve(files).index;
|
|
193663
194322
|
}
|
|
@@ -194342,21 +195001,21 @@ function writeInferred(contractsDir, decisions, options = {}) {
|
|
|
194342
195001
|
proposed.push(filePath);
|
|
194343
195002
|
continue;
|
|
194344
195003
|
}
|
|
194345
|
-
|
|
194346
|
-
const existing =
|
|
195004
|
+
fs42.mkdirSync(path48.dirname(filePath), { recursive: true });
|
|
195005
|
+
const existing = fs42.existsSync(filePath) ? fs42.readFileSync(filePath, "utf-8") : null;
|
|
194347
195006
|
if (existing === r.tcSource)
|
|
194348
195007
|
continue;
|
|
194349
|
-
|
|
195008
|
+
fs42.writeFileSync(filePath, r.tcSource);
|
|
194350
195009
|
written.push(filePath);
|
|
194351
195010
|
}
|
|
194352
|
-
if (!options.dryRun &&
|
|
195011
|
+
if (!options.dryRun && fs42.existsSync(root2))
|
|
194353
195012
|
pruneStale(root2, live);
|
|
194354
195013
|
return { written, proposed };
|
|
194355
195014
|
}
|
|
194356
195015
|
function walkAuthoredTcFiles(rootDir, visit) {
|
|
194357
|
-
if (!
|
|
195016
|
+
if (!fs42.existsSync(rootDir))
|
|
194358
195017
|
return;
|
|
194359
|
-
for (const entry of
|
|
195018
|
+
for (const entry of fs42.readdirSync(rootDir, { withFileTypes: true })) {
|
|
194360
195019
|
if (entry.isDirectory()) {
|
|
194361
195020
|
if (entry.name === INFERRED_DIR)
|
|
194362
195021
|
continue;
|
|
@@ -194372,22 +195031,22 @@ function toRelCode(codeDir, fp) {
|
|
|
194372
195031
|
}
|
|
194373
195032
|
function pruneStale(root2, live) {
|
|
194374
195033
|
const visit = (dir) => {
|
|
194375
|
-
if (!
|
|
195034
|
+
if (!fs42.existsSync(dir))
|
|
194376
195035
|
return false;
|
|
194377
195036
|
let dirEmpty = true;
|
|
194378
|
-
for (const entry of
|
|
195037
|
+
for (const entry of fs42.readdirSync(dir, { withFileTypes: true })) {
|
|
194379
195038
|
const full = path48.join(dir, entry.name);
|
|
194380
195039
|
if (entry.isDirectory()) {
|
|
194381
195040
|
if (visit(full)) {
|
|
194382
195041
|
try {
|
|
194383
|
-
|
|
195042
|
+
fs42.rmdirSync(full);
|
|
194384
195043
|
} catch {
|
|
194385
195044
|
}
|
|
194386
195045
|
} else {
|
|
194387
195046
|
dirEmpty = false;
|
|
194388
195047
|
}
|
|
194389
195048
|
} else if (entry.isFile() && entry.name.endsWith(".tc") && !live.has(full)) {
|
|
194390
|
-
|
|
195049
|
+
fs42.unlinkSync(full);
|
|
194391
195050
|
} else {
|
|
194392
195051
|
dirEmpty = false;
|
|
194393
195052
|
}
|
|
@@ -194553,6 +195212,7 @@ async function runAdd(options = {}) {
|
|
|
194553
195212
|
// tools/cli/src/commands/analyze.ts
|
|
194554
195213
|
init_dist4();
|
|
194555
195214
|
init_transport();
|
|
195215
|
+
import fs17 from "node:fs";
|
|
194556
195216
|
import path21 from "node:path";
|
|
194557
195217
|
|
|
194558
195218
|
// packages/core/dist/commands/analyze-in-process.js
|
|
@@ -194842,6 +195502,30 @@ async function resolveOrInitProject() {
|
|
|
194842
195502
|
ensureRepoTruecourseDir(repoDir);
|
|
194843
195503
|
return registerProject(repoDir);
|
|
194844
195504
|
}
|
|
195505
|
+
function repoHasCSharp(root2) {
|
|
195506
|
+
const SKIP = /* @__PURE__ */ new Set(["node_modules", "bin", "obj", ".git", ".truecourse", "dist", ".vs"]);
|
|
195507
|
+
let budget = 2e4;
|
|
195508
|
+
const stack2 = [root2];
|
|
195509
|
+
while (stack2.length > 0) {
|
|
195510
|
+
if (budget-- <= 0) return false;
|
|
195511
|
+
const dir = stack2.pop();
|
|
195512
|
+
let entries;
|
|
195513
|
+
try {
|
|
195514
|
+
entries = fs17.readdirSync(dir, { withFileTypes: true });
|
|
195515
|
+
} catch {
|
|
195516
|
+
continue;
|
|
195517
|
+
}
|
|
195518
|
+
for (const e of entries) {
|
|
195519
|
+
if (e.isDirectory()) {
|
|
195520
|
+
if (SKIP.has(e.name) || e.name.startsWith(".")) continue;
|
|
195521
|
+
stack2.push(path21.join(dir, e.name));
|
|
195522
|
+
} else if (e.name.endsWith(".cs")) {
|
|
195523
|
+
return true;
|
|
195524
|
+
}
|
|
195525
|
+
}
|
|
195526
|
+
}
|
|
195527
|
+
return false;
|
|
195528
|
+
}
|
|
194845
195529
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
194846
195530
|
var PRE_LLM_STEPS = /* @__PURE__ */ new Set(["parse", "scan"]);
|
|
194847
195531
|
var spinnerFrame = 0;
|
|
@@ -194980,7 +195664,7 @@ async function runAnalyze(options = {}) {
|
|
|
194980
195664
|
if (wipeLegacyPostgresData()) {
|
|
194981
195665
|
O2.info("Legacy Postgres data wiped. Re-analyze to repopulate.");
|
|
194982
195666
|
}
|
|
194983
|
-
const stepDefs = buildAnalysisSteps(enabledCategories, enableLlmRules);
|
|
195667
|
+
const stepDefs = buildAnalysisSteps(enabledCategories, enableLlmRules, repoHasCSharp(project.path));
|
|
194984
195668
|
const tracker = new StepTracker((payload) => {
|
|
194985
195669
|
if (payload.steps) renderSteps(payload.steps);
|
|
194986
195670
|
}, stepDefs);
|
|
@@ -195054,7 +195738,7 @@ async function runAnalyzeDiff(options = {}) {
|
|
|
195054
195738
|
const enableLlmRules = llmDecision.enabled;
|
|
195055
195739
|
if (enableLlmRules) await preflightClaudeOrExit();
|
|
195056
195740
|
renderPhase = enableLlmRules ? "pre-llm" : "all";
|
|
195057
|
-
const stepDefs = buildAnalysisSteps(enabledCategories, enableLlmRules);
|
|
195741
|
+
const stepDefs = buildAnalysisSteps(enabledCategories, enableLlmRules, repoHasCSharp(project.path));
|
|
195058
195742
|
const tracker = new StepTracker((payload) => {
|
|
195059
195743
|
if (payload.steps) renderSteps(payload.steps);
|
|
195060
195744
|
}, stepDefs);
|
|
@@ -195117,24 +195801,24 @@ init_paths();
|
|
|
195117
195801
|
init_registry();
|
|
195118
195802
|
init_helpers();
|
|
195119
195803
|
import { spawn as spawn7 } from "node:child_process";
|
|
195120
|
-
import
|
|
195804
|
+
import fs22 from "node:fs";
|
|
195121
195805
|
import path26 from "node:path";
|
|
195122
195806
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
195123
195807
|
|
|
195124
195808
|
// tools/cli/src/commands/service/macos.ts
|
|
195125
|
-
import
|
|
195809
|
+
import fs19 from "node:fs";
|
|
195126
195810
|
import path22 from "node:path";
|
|
195127
195811
|
import os5 from "node:os";
|
|
195128
195812
|
import { execSync } from "node:child_process";
|
|
195129
195813
|
|
|
195130
195814
|
// tools/cli/src/commands/service/env.ts
|
|
195131
|
-
import
|
|
195815
|
+
import fs18 from "node:fs";
|
|
195132
195816
|
function parseEnvFile(filePath) {
|
|
195133
195817
|
const vars = {};
|
|
195134
|
-
if (!
|
|
195818
|
+
if (!fs18.existsSync(filePath)) {
|
|
195135
195819
|
return vars;
|
|
195136
195820
|
}
|
|
195137
|
-
const content =
|
|
195821
|
+
const content = fs18.readFileSync(filePath, "utf-8");
|
|
195138
195822
|
for (const line of content.split("\n")) {
|
|
195139
195823
|
const trimmed2 = line.trim();
|
|
195140
195824
|
if (!trimmed2 || trimmed2.startsWith("#")) continue;
|
|
@@ -195205,10 +195889,10 @@ var MacOSService = class {
|
|
|
195205
195889
|
}
|
|
195206
195890
|
envVars.TRUECOURSE_LOG_DIR = path22.dirname(logPath);
|
|
195207
195891
|
envVars.TRUECOURSE_HOME = path22.join(os5.homedir(), ".truecourse");
|
|
195208
|
-
|
|
195209
|
-
|
|
195892
|
+
fs19.mkdirSync(PLIST_DIR, { recursive: true });
|
|
195893
|
+
fs19.mkdirSync(path22.dirname(logPath), { recursive: true });
|
|
195210
195894
|
const plist = buildPlist(serverPath, logPath, envVars);
|
|
195211
|
-
|
|
195895
|
+
fs19.writeFileSync(PLIST_PATH, plist, "utf-8");
|
|
195212
195896
|
execSync(`launchctl load -w "${PLIST_PATH}"`, { stdio: "pipe" });
|
|
195213
195897
|
}
|
|
195214
195898
|
async uninstall() {
|
|
@@ -195216,12 +195900,12 @@ var MacOSService = class {
|
|
|
195216
195900
|
execSync(`launchctl unload "${PLIST_PATH}"`, { stdio: "pipe" });
|
|
195217
195901
|
} catch {
|
|
195218
195902
|
}
|
|
195219
|
-
if (
|
|
195220
|
-
|
|
195903
|
+
if (fs19.existsSync(PLIST_PATH)) {
|
|
195904
|
+
fs19.unlinkSync(PLIST_PATH);
|
|
195221
195905
|
}
|
|
195222
195906
|
}
|
|
195223
195907
|
async start() {
|
|
195224
|
-
if (!
|
|
195908
|
+
if (!fs19.existsSync(PLIST_PATH)) {
|
|
195225
195909
|
throw new Error("Service is not installed. Run 'truecourse service install' first.");
|
|
195226
195910
|
}
|
|
195227
195911
|
execSync(`launchctl load -w "${PLIST_PATH}"`, { stdio: "pipe" });
|
|
@@ -195251,12 +195935,12 @@ var MacOSService = class {
|
|
|
195251
195935
|
}
|
|
195252
195936
|
}
|
|
195253
195937
|
async isInstalled() {
|
|
195254
|
-
return
|
|
195938
|
+
return fs19.existsSync(PLIST_PATH);
|
|
195255
195939
|
}
|
|
195256
195940
|
};
|
|
195257
195941
|
|
|
195258
195942
|
// tools/cli/src/commands/service/linux.ts
|
|
195259
|
-
import
|
|
195943
|
+
import fs20 from "node:fs";
|
|
195260
195944
|
import path23 from "node:path";
|
|
195261
195945
|
import os6 from "node:os";
|
|
195262
195946
|
import { execSync as execSync2 } from "node:child_process";
|
|
@@ -195288,10 +195972,10 @@ WantedBy=default.target
|
|
|
195288
195972
|
}
|
|
195289
195973
|
var LinuxService = class {
|
|
195290
195974
|
async install(serverPath, logPath) {
|
|
195291
|
-
|
|
195292
|
-
|
|
195975
|
+
fs20.mkdirSync(UNIT_DIR, { recursive: true });
|
|
195976
|
+
fs20.mkdirSync(path23.dirname(logPath), { recursive: true });
|
|
195293
195977
|
const unit = buildUnitFile(serverPath, logPath);
|
|
195294
|
-
|
|
195978
|
+
fs20.writeFileSync(UNIT_PATH, unit, "utf-8");
|
|
195295
195979
|
execSync2("systemctl --user daemon-reload", { stdio: "pipe" });
|
|
195296
195980
|
execSync2(`systemctl --user enable ${SERVICE_NAME}`, { stdio: "pipe" });
|
|
195297
195981
|
}
|
|
@@ -195304,8 +195988,8 @@ var LinuxService = class {
|
|
|
195304
195988
|
execSync2(`systemctl --user disable ${SERVICE_NAME}`, { stdio: "pipe" });
|
|
195305
195989
|
} catch {
|
|
195306
195990
|
}
|
|
195307
|
-
if (
|
|
195308
|
-
|
|
195991
|
+
if (fs20.existsSync(UNIT_PATH)) {
|
|
195992
|
+
fs20.unlinkSync(UNIT_PATH);
|
|
195309
195993
|
}
|
|
195310
195994
|
try {
|
|
195311
195995
|
execSync2("systemctl --user daemon-reload", { stdio: "pipe" });
|
|
@@ -195334,7 +196018,7 @@ var LinuxService = class {
|
|
|
195334
196018
|
}
|
|
195335
196019
|
}
|
|
195336
196020
|
async isInstalled() {
|
|
195337
|
-
return
|
|
196021
|
+
return fs20.existsSync(UNIT_PATH);
|
|
195338
196022
|
}
|
|
195339
196023
|
};
|
|
195340
196024
|
|
|
@@ -195444,7 +196128,7 @@ function getPlatform() {
|
|
|
195444
196128
|
}
|
|
195445
196129
|
|
|
195446
196130
|
// tools/cli/src/commands/service/logs.ts
|
|
195447
|
-
import
|
|
196131
|
+
import fs21 from "node:fs";
|
|
195448
196132
|
import path25 from "node:path";
|
|
195449
196133
|
import os8 from "node:os";
|
|
195450
196134
|
var MAX_LOG_SIZE2 = 10 * 1024 * 1024;
|
|
@@ -195462,32 +196146,32 @@ function getLogPath() {
|
|
|
195462
196146
|
return path25.join(getLogDir(), "dashboard.log");
|
|
195463
196147
|
}
|
|
195464
196148
|
function existingLogFiles(logDir) {
|
|
195465
|
-
if (!
|
|
195466
|
-
return
|
|
196149
|
+
if (!fs21.existsSync(logDir)) return [];
|
|
196150
|
+
return fs21.readdirSync(logDir).filter((name) => /\.log$/.test(name)).sort().map((name) => path25.join(logDir, name));
|
|
195467
196151
|
}
|
|
195468
196152
|
function rotateOne(logFile) {
|
|
195469
|
-
if (!
|
|
195470
|
-
if (
|
|
196153
|
+
if (!fs21.existsSync(logFile)) return;
|
|
196154
|
+
if (fs21.statSync(logFile).size < MAX_LOG_SIZE2) return;
|
|
195471
196155
|
for (let i = MAX_LOG_FILES2; i >= 1; i--) {
|
|
195472
196156
|
const older = `${logFile}.${i}`;
|
|
195473
196157
|
if (i === MAX_LOG_FILES2) {
|
|
195474
|
-
if (
|
|
196158
|
+
if (fs21.existsSync(older)) fs21.unlinkSync(older);
|
|
195475
196159
|
} else {
|
|
195476
196160
|
const newer = `${logFile}.${i + 1}`;
|
|
195477
|
-
if (
|
|
196161
|
+
if (fs21.existsSync(older)) fs21.renameSync(older, newer);
|
|
195478
196162
|
}
|
|
195479
196163
|
}
|
|
195480
|
-
|
|
196164
|
+
fs21.renameSync(logFile, `${logFile}.1`);
|
|
195481
196165
|
}
|
|
195482
196166
|
function rotateLogs(logDir) {
|
|
195483
196167
|
for (const name of ROTATABLE_LOG_NAMES) {
|
|
195484
196168
|
rotateOne(path25.join(logDir, name));
|
|
195485
196169
|
}
|
|
195486
|
-
if (!
|
|
196170
|
+
if (!fs21.existsSync(logDir)) return;
|
|
195487
196171
|
for (const file of existingLogFiles(logDir)) rotateOne(file);
|
|
195488
196172
|
}
|
|
195489
196173
|
function readLastLines(filePath, maxLines) {
|
|
195490
|
-
const content =
|
|
196174
|
+
const content = fs21.readFileSync(filePath, "utf-8");
|
|
195491
196175
|
const lines = content.split("\n");
|
|
195492
196176
|
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
195493
196177
|
return lines.slice(-maxLines).join("\n");
|
|
@@ -195515,17 +196199,17 @@ function tailLogs() {
|
|
|
195515
196199
|
}
|
|
195516
196200
|
dumpLogTails(logDir);
|
|
195517
196201
|
const sizes = /* @__PURE__ */ new Map();
|
|
195518
|
-
for (const file of files) sizes.set(file,
|
|
196202
|
+
for (const file of files) sizes.set(file, fs21.statSync(file).size);
|
|
195519
196203
|
const watch = (file) => {
|
|
195520
|
-
|
|
196204
|
+
fs21.watchFile(file, { interval: POLL_INTERVAL_MS }, () => {
|
|
195521
196205
|
try {
|
|
195522
|
-
const newSize =
|
|
196206
|
+
const newSize = fs21.statSync(file).size;
|
|
195523
196207
|
const lastSize = sizes.get(file) ?? 0;
|
|
195524
196208
|
if (newSize > lastSize) {
|
|
195525
|
-
const fd =
|
|
196209
|
+
const fd = fs21.openSync(file, "r");
|
|
195526
196210
|
const buf = Buffer.alloc(newSize - lastSize);
|
|
195527
|
-
|
|
195528
|
-
|
|
196211
|
+
fs21.readSync(fd, buf, 0, buf.length, lastSize);
|
|
196212
|
+
fs21.closeSync(fd);
|
|
195529
196213
|
const tag = `[${path25.basename(file)}] `;
|
|
195530
196214
|
const text4 = buf.toString("utf-8");
|
|
195531
196215
|
const tagged = text4.split("\n").map((line, i, arr) => i === arr.length - 1 && line === "" ? "" : tag + line).join("\n");
|
|
@@ -195540,7 +196224,7 @@ function tailLogs() {
|
|
|
195540
196224
|
};
|
|
195541
196225
|
for (const file of files) watch(file);
|
|
195542
196226
|
const cleanup = () => {
|
|
195543
|
-
for (const file of files)
|
|
196227
|
+
for (const file of files) fs21.unwatchFile(file);
|
|
195544
196228
|
process.exit(0);
|
|
195545
196229
|
};
|
|
195546
196230
|
process.on("SIGINT", cleanup);
|
|
@@ -195556,7 +196240,7 @@ function resolveServerEntry() {
|
|
|
195556
196240
|
// Source build output: tools/cli/dist → ../../../../dist/server.mjs
|
|
195557
196241
|
path26.resolve(__dirname2, "..", "..", "..", "..", "dist", "server.mjs")
|
|
195558
196242
|
];
|
|
195559
|
-
return candidates.find((p2) =>
|
|
196243
|
+
return candidates.find((p2) => fs22.existsSync(p2)) ?? null;
|
|
195560
196244
|
}
|
|
195561
196245
|
async function waitForHealth(url, timeoutMs = 3e4) {
|
|
195562
196246
|
const start = Date.now();
|
|
@@ -195684,7 +196368,7 @@ async function runDashboard(options = {}) {
|
|
|
195684
196368
|
);
|
|
195685
196369
|
process.exit(1);
|
|
195686
196370
|
}
|
|
195687
|
-
const configured =
|
|
196371
|
+
const configured = fs22.existsSync(getConfigPath());
|
|
195688
196372
|
const needsDecision = !configured || options.reconfigure;
|
|
195689
196373
|
let runMode;
|
|
195690
196374
|
if (options.mode) {
|
|
@@ -196180,7 +196864,7 @@ async function runRulesReset({ ruleKey }) {
|
|
|
196180
196864
|
|
|
196181
196865
|
// tools/cli/src/commands/contracts.ts
|
|
196182
196866
|
init_dist4();
|
|
196183
|
-
import
|
|
196867
|
+
import fs68 from "node:fs";
|
|
196184
196868
|
import path73 from "node:path";
|
|
196185
196869
|
|
|
196186
196870
|
// packages/spec-consolidator/dist/types.js
|
|
@@ -196414,7 +197098,7 @@ var CuratedCorpusSchema = external_exports.object({
|
|
|
196414
197098
|
});
|
|
196415
197099
|
|
|
196416
197100
|
// packages/spec-consolidator/dist/corpus-store.js
|
|
196417
|
-
import
|
|
197101
|
+
import fs23 from "node:fs";
|
|
196418
197102
|
import path27 from "node:path";
|
|
196419
197103
|
var CORPUS_FILE = "corpus.json";
|
|
196420
197104
|
function corpusFilePath(repoRoot5) {
|
|
@@ -196422,10 +197106,10 @@ function corpusFilePath(repoRoot5) {
|
|
|
196422
197106
|
}
|
|
196423
197107
|
function readCorpus(repoRoot5) {
|
|
196424
197108
|
const file = corpusFilePath(repoRoot5);
|
|
196425
|
-
if (!
|
|
197109
|
+
if (!fs23.existsSync(file))
|
|
196426
197110
|
return null;
|
|
196427
197111
|
try {
|
|
196428
|
-
const raw = JSON.parse(
|
|
197112
|
+
const raw = JSON.parse(fs23.readFileSync(file, "utf-8"));
|
|
196429
197113
|
return CuratedCorpusSchema.parse(raw);
|
|
196430
197114
|
} catch {
|
|
196431
197115
|
return null;
|
|
@@ -196433,7 +197117,7 @@ function readCorpus(repoRoot5) {
|
|
|
196433
197117
|
}
|
|
196434
197118
|
function writeCorpus(repoRoot5, input) {
|
|
196435
197119
|
const file = corpusFilePath(repoRoot5);
|
|
196436
|
-
|
|
197120
|
+
fs23.mkdirSync(path27.dirname(file), { recursive: true });
|
|
196437
197121
|
const payload = {
|
|
196438
197122
|
version: 3,
|
|
196439
197123
|
// Caller may pass the timestamp it stamped on the in-memory corpus so the
|
|
@@ -196444,16 +197128,16 @@ function writeCorpus(repoRoot5, input) {
|
|
|
196444
197128
|
relations: input.relations,
|
|
196445
197129
|
skippedDocs: input.skippedDocs ?? []
|
|
196446
197130
|
};
|
|
196447
|
-
|
|
197131
|
+
fs23.writeFileSync(file, JSON.stringify(payload, null, 2) + "\n");
|
|
196448
197132
|
}
|
|
196449
197133
|
|
|
196450
197134
|
// packages/spec-consolidator/dist/area-tagger.js
|
|
196451
197135
|
init_zod();
|
|
196452
197136
|
import { createHash as createHash3 } from "node:crypto";
|
|
196453
|
-
import
|
|
197137
|
+
import fs25 from "node:fs";
|
|
196454
197138
|
|
|
196455
197139
|
// packages/llm/dist/cache-store.js
|
|
196456
|
-
import
|
|
197140
|
+
import fs24 from "node:fs";
|
|
196457
197141
|
import path28 from "node:path";
|
|
196458
197142
|
var FileKvCacheStore = class {
|
|
196459
197143
|
file(scope, cacheName, key4) {
|
|
@@ -196461,18 +197145,18 @@ var FileKvCacheStore = class {
|
|
|
196461
197145
|
}
|
|
196462
197146
|
async get(scope, cacheName, key4) {
|
|
196463
197147
|
const file = this.file(scope, cacheName, key4);
|
|
196464
|
-
if (!
|
|
197148
|
+
if (!fs24.existsSync(file))
|
|
196465
197149
|
return null;
|
|
196466
197150
|
try {
|
|
196467
|
-
return JSON.parse(
|
|
197151
|
+
return JSON.parse(fs24.readFileSync(file, "utf-8"));
|
|
196468
197152
|
} catch {
|
|
196469
197153
|
return null;
|
|
196470
197154
|
}
|
|
196471
197155
|
}
|
|
196472
197156
|
async set(scope, cacheName, key4, value) {
|
|
196473
197157
|
const file = this.file(scope, cacheName, key4);
|
|
196474
|
-
|
|
196475
|
-
|
|
197158
|
+
fs24.mkdirSync(path28.dirname(file), { recursive: true });
|
|
197159
|
+
fs24.writeFileSync(file, JSON.stringify(value, null, 2));
|
|
196476
197160
|
}
|
|
196477
197161
|
};
|
|
196478
197162
|
var active6 = new FileKvCacheStore();
|
|
@@ -196554,7 +197238,7 @@ function docBody(doc) {
|
|
|
196554
197238
|
return doc.content;
|
|
196555
197239
|
if (doc.absPath) {
|
|
196556
197240
|
try {
|
|
196557
|
-
return
|
|
197241
|
+
return fs25.readFileSync(doc.absPath, "utf-8");
|
|
196558
197242
|
} catch {
|
|
196559
197243
|
}
|
|
196560
197244
|
}
|
|
@@ -197159,7 +197843,7 @@ function spawnRelationRunner(opts = {}) {
|
|
|
197159
197843
|
// packages/spec-consolidator/dist/overlap-detector.js
|
|
197160
197844
|
init_zod();
|
|
197161
197845
|
import { createHash as createHash7 } from "node:crypto";
|
|
197162
|
-
import
|
|
197846
|
+
import fs26 from "node:fs";
|
|
197163
197847
|
init_transport();
|
|
197164
197848
|
var DEFAULT_MAX_PAIRS_PER_AREA = 60;
|
|
197165
197849
|
async function flagOverlaps(repoRoot5, areas, docs, opts = {}) {
|
|
@@ -197340,7 +198024,7 @@ function docBody2(doc) {
|
|
|
197340
198024
|
return doc.content;
|
|
197341
198025
|
if (doc.absPath) {
|
|
197342
198026
|
try {
|
|
197343
|
-
return
|
|
198027
|
+
return fs26.readFileSync(doc.absPath, "utf-8");
|
|
197344
198028
|
} catch {
|
|
197345
198029
|
}
|
|
197346
198030
|
}
|
|
@@ -197432,14 +198116,14 @@ async function writeCache3(scope, cacheKey, verdict) {
|
|
|
197432
198116
|
|
|
197433
198117
|
// packages/spec-consolidator/dist/curate.js
|
|
197434
198118
|
init_dist5();
|
|
197435
|
-
import
|
|
198119
|
+
import fs29 from "node:fs";
|
|
197436
198120
|
import path31 from "node:path";
|
|
197437
198121
|
|
|
197438
198122
|
// packages/spec-consolidator/dist/discovery.js
|
|
197439
198123
|
init_dist5();
|
|
197440
198124
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
197441
198125
|
import { createHash as createHash8 } from "node:crypto";
|
|
197442
|
-
import
|
|
198126
|
+
import fs27 from "node:fs";
|
|
197443
198127
|
import path30 from "node:path";
|
|
197444
198128
|
var SKIP_DIR_PROBE = "__tc_skipdir_probe__.md";
|
|
197445
198129
|
var PREVIEW_LINE_LIMIT = 200;
|
|
@@ -197451,7 +198135,7 @@ function discoverDocs(rootDir, opts = {}) {
|
|
|
197451
198135
|
const visit = (dir) => {
|
|
197452
198136
|
let entries;
|
|
197453
198137
|
try {
|
|
197454
|
-
entries =
|
|
198138
|
+
entries = fs27.readdirSync(dir, { withFileTypes: true });
|
|
197455
198139
|
} catch {
|
|
197456
198140
|
return;
|
|
197457
198141
|
}
|
|
@@ -197490,8 +198174,8 @@ function makeCandidate(absPath, rootDir, previewLines, opts) {
|
|
|
197490
198174
|
let content;
|
|
197491
198175
|
let stat;
|
|
197492
198176
|
try {
|
|
197493
|
-
content =
|
|
197494
|
-
stat =
|
|
198177
|
+
content = fs27.readFileSync(absPath, "utf-8");
|
|
198178
|
+
stat = fs27.statSync(absPath);
|
|
197495
198179
|
} catch {
|
|
197496
198180
|
return null;
|
|
197497
198181
|
}
|
|
@@ -197559,7 +198243,7 @@ function looksLikePrd(content) {
|
|
|
197559
198243
|
// packages/spec-consolidator/dist/relevance-filter.js
|
|
197560
198244
|
init_zod();
|
|
197561
198245
|
import { createHash as createHash9 } from "node:crypto";
|
|
197562
|
-
import
|
|
198246
|
+
import fs28 from "node:fs";
|
|
197563
198247
|
init_transport();
|
|
197564
198248
|
function prefilterDocs(docs, manualIncludes = []) {
|
|
197565
198249
|
const manualSet = new Set(manualIncludes);
|
|
@@ -197683,7 +198367,7 @@ function docBody3(doc) {
|
|
|
197683
198367
|
return doc.content;
|
|
197684
198368
|
if (doc.absPath) {
|
|
197685
198369
|
try {
|
|
197686
|
-
return
|
|
198370
|
+
return fs28.readFileSync(doc.absPath, "utf-8");
|
|
197687
198371
|
} catch {
|
|
197688
198372
|
}
|
|
197689
198373
|
}
|
|
@@ -197944,10 +198628,10 @@ var EMPTY_DECISIONS = {
|
|
|
197944
198628
|
};
|
|
197945
198629
|
function readCorpusDecisions(repoRoot5) {
|
|
197946
198630
|
const file = path31.join(repoRoot5, ".truecourse", "specs", "decisions.json");
|
|
197947
|
-
if (!
|
|
198631
|
+
if (!fs29.existsSync(file))
|
|
197948
198632
|
return EMPTY_DECISIONS;
|
|
197949
198633
|
try {
|
|
197950
|
-
const raw = JSON.parse(
|
|
198634
|
+
const raw = JSON.parse(fs29.readFileSync(file, "utf-8"));
|
|
197951
198635
|
return DecisionsFileSchema.parse(raw);
|
|
197952
198636
|
} catch {
|
|
197953
198637
|
return EMPTY_DECISIONS;
|
|
@@ -197955,7 +198639,7 @@ function readCorpusDecisions(repoRoot5) {
|
|
|
197955
198639
|
}
|
|
197956
198640
|
|
|
197957
198641
|
// packages/spec-consolidator/dist/orchestrator.js
|
|
197958
|
-
import
|
|
198642
|
+
import fs30 from "node:fs";
|
|
197959
198643
|
import path32 from "node:path";
|
|
197960
198644
|
var EMPTY_DECISIONS2 = {
|
|
197961
198645
|
version: 1,
|
|
@@ -197969,10 +198653,10 @@ function decisionsPath(repoRoot5) {
|
|
|
197969
198653
|
}
|
|
197970
198654
|
function readDecisions(repoRoot5) {
|
|
197971
198655
|
const file = decisionsPath(repoRoot5);
|
|
197972
|
-
if (!
|
|
198656
|
+
if (!fs30.existsSync(file))
|
|
197973
198657
|
return EMPTY_DECISIONS2;
|
|
197974
198658
|
try {
|
|
197975
|
-
const raw = JSON.parse(
|
|
198659
|
+
const raw = JSON.parse(fs30.readFileSync(file, "utf-8"));
|
|
197976
198660
|
return DecisionsFileSchema.parse(raw);
|
|
197977
198661
|
} catch {
|
|
197978
198662
|
return EMPTY_DECISIONS2;
|
|
@@ -197980,8 +198664,8 @@ function readDecisions(repoRoot5) {
|
|
|
197980
198664
|
}
|
|
197981
198665
|
function writeDecisions(repoRoot5, decisions) {
|
|
197982
198666
|
const file = decisionsPath(repoRoot5);
|
|
197983
|
-
|
|
197984
|
-
|
|
198667
|
+
fs30.mkdirSync(path32.dirname(file), { recursive: true });
|
|
198668
|
+
fs30.writeFileSync(file, JSON.stringify(decisions, null, 2) + "\n");
|
|
197985
198669
|
}
|
|
197986
198670
|
|
|
197987
198671
|
// packages/contract-extractor/dist/corpus-diff.js
|
|
@@ -198133,7 +198817,7 @@ function validateMerged(artifacts) {
|
|
|
198133
198817
|
}
|
|
198134
198818
|
|
|
198135
198819
|
// packages/contract-extractor/dist/writer.js
|
|
198136
|
-
import
|
|
198820
|
+
import fs43 from "node:fs";
|
|
198137
198821
|
import path49 from "node:path";
|
|
198138
198822
|
|
|
198139
198823
|
// packages/contract-extractor/dist/identity.js
|
|
@@ -198170,14 +198854,14 @@ function writeContracts(repoRoot5, artifacts, options = {}) {
|
|
|
198170
198854
|
proposed.push(req.filePath);
|
|
198171
198855
|
continue;
|
|
198172
198856
|
}
|
|
198173
|
-
|
|
198174
|
-
const existing =
|
|
198857
|
+
fs43.mkdirSync(path49.dirname(req.filePath), { recursive: true });
|
|
198858
|
+
const existing = fs43.existsSync(req.filePath) ? fs43.readFileSync(req.filePath, "utf-8") : null;
|
|
198175
198859
|
if (existing === req.tcSource)
|
|
198176
198860
|
continue;
|
|
198177
|
-
|
|
198861
|
+
fs43.writeFileSync(req.filePath, req.tcSource);
|
|
198178
198862
|
written.push(req.filePath);
|
|
198179
198863
|
}
|
|
198180
|
-
if (options.prune && !options.dryRun &&
|
|
198864
|
+
if (options.prune && !options.dryRun && fs43.existsSync(root2)) {
|
|
198181
198865
|
const live = new Set(requests.map((r) => r.filePath));
|
|
198182
198866
|
pruneStale2(root2, live);
|
|
198183
198867
|
}
|
|
@@ -198243,16 +198927,16 @@ function inferKindDomain2(artifact) {
|
|
|
198243
198927
|
}
|
|
198244
198928
|
function pruneStale2(root2, live) {
|
|
198245
198929
|
const visit = (dir) => {
|
|
198246
|
-
if (!
|
|
198930
|
+
if (!fs43.existsSync(dir))
|
|
198247
198931
|
return false;
|
|
198248
198932
|
let dirEmpty = true;
|
|
198249
|
-
for (const entry of
|
|
198933
|
+
for (const entry of fs43.readdirSync(dir, { withFileTypes: true })) {
|
|
198250
198934
|
const full = path49.join(dir, entry.name);
|
|
198251
198935
|
if (entry.isDirectory()) {
|
|
198252
198936
|
const childEmpty = visit(full);
|
|
198253
198937
|
if (childEmpty) {
|
|
198254
198938
|
try {
|
|
198255
|
-
|
|
198939
|
+
fs43.rmdirSync(full);
|
|
198256
198940
|
} catch {
|
|
198257
198941
|
}
|
|
198258
198942
|
} else {
|
|
@@ -198260,7 +198944,7 @@ function pruneStale2(root2, live) {
|
|
|
198260
198944
|
}
|
|
198261
198945
|
} else if (entry.isFile()) {
|
|
198262
198946
|
if (entry.name.endsWith(".tc") && !live.has(full)) {
|
|
198263
|
-
|
|
198947
|
+
fs43.unlinkSync(full);
|
|
198264
198948
|
} else {
|
|
198265
198949
|
dirEmpty = false;
|
|
198266
198950
|
}
|
|
@@ -201192,7 +201876,7 @@ async function assembleArtifacts(ranked, slices, opts = {}) {
|
|
|
201192
201876
|
}
|
|
201193
201877
|
|
|
201194
201878
|
// packages/contract-extractor/dist/corpus-reader.js
|
|
201195
|
-
import
|
|
201879
|
+
import fs44 from "node:fs";
|
|
201196
201880
|
import path50 from "node:path";
|
|
201197
201881
|
function hasCorpusSpec(repoRoot5) {
|
|
201198
201882
|
return readCorpus(repoRoot5) !== null;
|
|
@@ -201290,7 +201974,7 @@ function orderByPrecedence(docs, areaId, relations) {
|
|
|
201290
201974
|
}
|
|
201291
201975
|
function defaultResolveContent(repoRoot5, ref) {
|
|
201292
201976
|
try {
|
|
201293
|
-
return
|
|
201977
|
+
return fs44.readFileSync(path50.join(repoRoot5, ref), "utf-8");
|
|
201294
201978
|
} catch {
|
|
201295
201979
|
return null;
|
|
201296
201980
|
}
|
|
@@ -201431,7 +202115,7 @@ init_transport();
|
|
|
201431
202115
|
init_dist8();
|
|
201432
202116
|
|
|
201433
202117
|
// packages/contract-extractor/dist/manifest.js
|
|
201434
|
-
import
|
|
202118
|
+
import fs45 from "node:fs";
|
|
201435
202119
|
import path51 from "node:path";
|
|
201436
202120
|
import { createHash as createHash12 } from "node:crypto";
|
|
201437
202121
|
var MANIFEST_REL = path51.join(".truecourse", "contracts", "manifest.json");
|
|
@@ -201450,7 +202134,7 @@ function manifestPath(repoRoot5) {
|
|
|
201450
202134
|
}
|
|
201451
202135
|
function readManifest(repoRoot5) {
|
|
201452
202136
|
try {
|
|
201453
|
-
const raw = JSON.parse(
|
|
202137
|
+
const raw = JSON.parse(fs45.readFileSync(manifestPath(repoRoot5), "utf-8"));
|
|
201454
202138
|
if (raw && raw.version === 1 && raw.areas)
|
|
201455
202139
|
return raw;
|
|
201456
202140
|
} catch {
|
|
@@ -201459,8 +202143,8 @@ function readManifest(repoRoot5) {
|
|
|
201459
202143
|
}
|
|
201460
202144
|
function writeManifest(repoRoot5, manifest) {
|
|
201461
202145
|
const file = manifestPath(repoRoot5);
|
|
201462
|
-
|
|
201463
|
-
|
|
202146
|
+
fs45.mkdirSync(path51.dirname(file), { recursive: true });
|
|
202147
|
+
fs45.writeFileSync(file, JSON.stringify(manifest, null, 2) + "\n");
|
|
201464
202148
|
}
|
|
201465
202149
|
function classifyAreas(areas, manifest) {
|
|
201466
202150
|
const prev = manifest?.areas ?? {};
|
|
@@ -201919,7 +202603,7 @@ function spawnGenerateRunner(opts = {}) {
|
|
|
201919
202603
|
|
|
201920
202604
|
// packages/core/dist/config/llm-models.js
|
|
201921
202605
|
init_paths();
|
|
201922
|
-
import
|
|
202606
|
+
import fs46 from "node:fs";
|
|
201923
202607
|
var STAGE_DEFAULTS = {
|
|
201924
202608
|
"spec.relevance": "haiku",
|
|
201925
202609
|
// Area tagging is load-bearing (wrong tags → wrong generate inputs) and Haiku
|
|
@@ -201967,10 +202651,10 @@ function stageEnvVar(stageId) {
|
|
|
201967
202651
|
}
|
|
201968
202652
|
function readConfigSync(repoDir) {
|
|
201969
202653
|
const file = getRepoConfigPath(repoDir);
|
|
201970
|
-
if (!
|
|
202654
|
+
if (!fs46.existsSync(file))
|
|
201971
202655
|
return {};
|
|
201972
202656
|
try {
|
|
201973
|
-
return JSON.parse(
|
|
202657
|
+
return JSON.parse(fs46.readFileSync(file, "utf-8"));
|
|
201974
202658
|
} catch {
|
|
201975
202659
|
return {};
|
|
201976
202660
|
}
|
|
@@ -202043,7 +202727,7 @@ function describeStageResolutions(repoDir = resolveRepoDir(process.cwd())) {
|
|
|
202043
202727
|
init_transport();
|
|
202044
202728
|
|
|
202045
202729
|
// packages/core/dist/lib/llm-call-log.js
|
|
202046
|
-
import
|
|
202730
|
+
import fs47 from "node:fs";
|
|
202047
202731
|
import path52 from "node:path";
|
|
202048
202732
|
import { randomUUID as randomUUID26 } from "node:crypto";
|
|
202049
202733
|
function truthyEnv(v) {
|
|
@@ -202065,20 +202749,20 @@ function createLlmCallLogger(repoRoot5, label = "scan") {
|
|
|
202065
202749
|
if (!log2 && !dump2)
|
|
202066
202750
|
return null;
|
|
202067
202751
|
const logDir = path52.join(repoRoot5, ".truecourse", "logs");
|
|
202068
|
-
|
|
202752
|
+
fs47.mkdirSync(logDir, { recursive: true });
|
|
202069
202753
|
const runId = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}_${randomUUID26().slice(0, 8)}`;
|
|
202070
202754
|
const callsPath = path52.join(logDir, `llm-${label}-${runId}.jsonl`);
|
|
202071
202755
|
const summaryPath = path52.join(logDir, `llm-${label}-${runId}.summary.json`);
|
|
202072
202756
|
const ioDir = dump2 ? path52.join(logDir, `llm-${label}-${runId}.io`) : null;
|
|
202073
202757
|
if (ioDir)
|
|
202074
|
-
|
|
202758
|
+
fs47.mkdirSync(ioDir, { recursive: true });
|
|
202075
202759
|
const createdAt = Date.now();
|
|
202076
202760
|
const records = [];
|
|
202077
202761
|
let seq2 = 0;
|
|
202078
202762
|
let finished = false;
|
|
202079
202763
|
let fd = null;
|
|
202080
202764
|
try {
|
|
202081
|
-
fd =
|
|
202765
|
+
fd = fs47.openSync(callsPath, "a");
|
|
202082
202766
|
} catch {
|
|
202083
202767
|
fd = null;
|
|
202084
202768
|
}
|
|
@@ -202088,14 +202772,14 @@ function createLlmCallLogger(repoRoot5, label = "scan") {
|
|
|
202088
202772
|
records.push(metrics);
|
|
202089
202773
|
if (fd !== null) {
|
|
202090
202774
|
try {
|
|
202091
|
-
|
|
202775
|
+
fs47.writeSync(fd, JSON.stringify(metrics) + "\n");
|
|
202092
202776
|
} catch {
|
|
202093
202777
|
}
|
|
202094
202778
|
}
|
|
202095
202779
|
if (ioDir) {
|
|
202096
202780
|
const fname = `${String(seq2).padStart(5, "0")}-${sanitize3(rec.id) || rec.stage}.json`;
|
|
202097
202781
|
try {
|
|
202098
|
-
|
|
202782
|
+
fs47.writeFileSync(path52.join(ioDir, fname), JSON.stringify({
|
|
202099
202783
|
stage: rec.stage,
|
|
202100
202784
|
model: rec.model,
|
|
202101
202785
|
ok: rec.ok,
|
|
@@ -202125,13 +202809,13 @@ function createLlmCallLogger(repoRoot5, label = "scan") {
|
|
|
202125
202809
|
process.removeListener(sig, h);
|
|
202126
202810
|
if (fd !== null) {
|
|
202127
202811
|
try {
|
|
202128
|
-
|
|
202812
|
+
fs47.closeSync(fd);
|
|
202129
202813
|
} catch {
|
|
202130
202814
|
}
|
|
202131
202815
|
}
|
|
202132
202816
|
const summary = summarizeLlmCalls(records, elapsedMs);
|
|
202133
202817
|
try {
|
|
202134
|
-
|
|
202818
|
+
fs47.writeFileSync(summaryPath, JSON.stringify(summary, null, 2));
|
|
202135
202819
|
} catch {
|
|
202136
202820
|
}
|
|
202137
202821
|
printSummary(summary, callsPath, ioDir);
|
|
@@ -202261,7 +202945,7 @@ import crypto5 from "node:crypto";
|
|
|
202261
202945
|
|
|
202262
202946
|
// packages/guard-runner/dist/recipe.js
|
|
202263
202947
|
init_zod();
|
|
202264
|
-
import
|
|
202948
|
+
import fs48 from "node:fs";
|
|
202265
202949
|
import path53 from "node:path";
|
|
202266
202950
|
import crypto3 from "node:crypto";
|
|
202267
202951
|
var RecipeSchema = external_exports.object({
|
|
@@ -202281,11 +202965,11 @@ var FINGERPRINT_INPUTS = [
|
|
|
202281
202965
|
var RecipeError = class extends Error {
|
|
202282
202966
|
};
|
|
202283
202967
|
function loadRecipe(repoRoot5, recipeFile) {
|
|
202284
|
-
if (!
|
|
202968
|
+
if (!fs48.existsSync(recipeFile))
|
|
202285
202969
|
return null;
|
|
202286
202970
|
let parsed;
|
|
202287
202971
|
try {
|
|
202288
|
-
parsed = JSON.parse(
|
|
202972
|
+
parsed = JSON.parse(fs48.readFileSync(recipeFile, "utf-8"));
|
|
202289
202973
|
} catch (e) {
|
|
202290
202974
|
throw new RecipeError(`recipe.json is not valid JSON: ${e instanceof Error ? e.message : e}`);
|
|
202291
202975
|
}
|
|
@@ -202299,11 +202983,11 @@ function computeRecipeFingerprint(repoRoot5) {
|
|
|
202299
202983
|
const hash = crypto3.createHash("sha256");
|
|
202300
202984
|
for (const rel of FINGERPRINT_INPUTS) {
|
|
202301
202985
|
const abs = path53.join(repoRoot5, rel);
|
|
202302
|
-
if (!
|
|
202986
|
+
if (!fs48.existsSync(abs) || !fs48.statSync(abs).isFile())
|
|
202303
202987
|
continue;
|
|
202304
202988
|
hash.update(rel);
|
|
202305
202989
|
hash.update("\0");
|
|
202306
|
-
hash.update(
|
|
202990
|
+
hash.update(fs48.readFileSync(abs));
|
|
202307
202991
|
hash.update("\0");
|
|
202308
202992
|
}
|
|
202309
202993
|
return `sha256:${hash.digest("hex")}`;
|
|
@@ -202315,7 +202999,7 @@ function resolveEntry(repoRoot5, entry) {
|
|
|
202315
202999
|
if (path53.isAbsolute(arg))
|
|
202316
203000
|
return arg;
|
|
202317
203001
|
const abs = path53.resolve(repoRoot5, arg);
|
|
202318
|
-
return
|
|
203002
|
+
return fs48.existsSync(abs) && fs48.statSync(abs).isFile() ? abs : arg;
|
|
202319
203003
|
});
|
|
202320
203004
|
return [resolvedCommand, ...resolvedRest];
|
|
202321
203005
|
}
|
|
@@ -202329,8 +203013,8 @@ function resolveOnHostPath(command) {
|
|
|
202329
203013
|
for (const ext2 of exts) {
|
|
202330
203014
|
const candidate = path53.join(dir, command + ext2);
|
|
202331
203015
|
try {
|
|
202332
|
-
if (
|
|
202333
|
-
|
|
203016
|
+
if (fs48.statSync(candidate).isFile()) {
|
|
203017
|
+
fs48.accessSync(candidate, fs48.constants.X_OK);
|
|
202334
203018
|
return candidate;
|
|
202335
203019
|
}
|
|
202336
203020
|
} catch {
|
|
@@ -202341,7 +203025,7 @@ function resolveOnHostPath(command) {
|
|
|
202341
203025
|
}
|
|
202342
203026
|
|
|
202343
203027
|
// packages/guard-runner/dist/scenario-loader.js
|
|
202344
|
-
import
|
|
203028
|
+
import fs50 from "node:fs";
|
|
202345
203029
|
import path55 from "node:path";
|
|
202346
203030
|
|
|
202347
203031
|
// node_modules/.pnpm/js-yaml@4.1.1/node_modules/js-yaml/dist/js-yaml.mjs
|
|
@@ -204973,7 +205657,7 @@ init_dist5();
|
|
|
204973
205657
|
|
|
204974
205658
|
// packages/guard-runner/dist/store.js
|
|
204975
205659
|
init_dist5();
|
|
204976
|
-
import
|
|
205660
|
+
import fs49 from "node:fs";
|
|
204977
205661
|
import path54 from "node:path";
|
|
204978
205662
|
var TRUECOURSE_DIR3 = ".truecourse";
|
|
204979
205663
|
var GUARD_DIR = "guard";
|
|
@@ -205029,10 +205713,10 @@ function sanitizeSegment(segment) {
|
|
|
205029
205713
|
return segment.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
205030
205714
|
}
|
|
205031
205715
|
function atomicWriteJson2(targetPath, data) {
|
|
205032
|
-
|
|
205716
|
+
fs49.mkdirSync(path54.dirname(targetPath), { recursive: true });
|
|
205033
205717
|
const tmp = `${targetPath}.tmp-${process.pid}-${Date.now()}`;
|
|
205034
|
-
|
|
205035
|
-
|
|
205718
|
+
fs49.writeFileSync(tmp, JSON.stringify(data, null, 2));
|
|
205719
|
+
fs49.renameSync(tmp, targetPath);
|
|
205036
205720
|
}
|
|
205037
205721
|
function writeGuardLatest(repoRoot5, latest) {
|
|
205038
205722
|
const target = guardLatestPath(repoRoot5);
|
|
@@ -205064,10 +205748,10 @@ function readGuardResult(repoRoot5) {
|
|
|
205064
205748
|
return readJsonOr(guardResultPath(repoRoot5), GuardGenerateReportSchema, null);
|
|
205065
205749
|
}
|
|
205066
205750
|
function readJsonOr(file, schema2, fallback) {
|
|
205067
|
-
if (!
|
|
205751
|
+
if (!fs49.existsSync(file))
|
|
205068
205752
|
return fallback;
|
|
205069
205753
|
try {
|
|
205070
|
-
const parsed = schema2.safeParse(JSON.parse(
|
|
205754
|
+
const parsed = schema2.safeParse(JSON.parse(fs49.readFileSync(file, "utf-8")));
|
|
205071
205755
|
return parsed.success ? parsed.data : fallback;
|
|
205072
205756
|
} catch {
|
|
205073
205757
|
return fallback;
|
|
@@ -205076,10 +205760,10 @@ function readJsonOr(file, schema2, fallback) {
|
|
|
205076
205760
|
|
|
205077
205761
|
// packages/guard-runner/dist/scenario-loader.js
|
|
205078
205762
|
function collectScenarioFiles(dir) {
|
|
205079
|
-
if (!
|
|
205763
|
+
if (!fs50.existsSync(dir))
|
|
205080
205764
|
return [];
|
|
205081
205765
|
const out = [];
|
|
205082
|
-
for (const entry of
|
|
205766
|
+
for (const entry of fs50.readdirSync(dir, { withFileTypes: true })) {
|
|
205083
205767
|
const full = path55.join(dir, entry.name);
|
|
205084
205768
|
if (entry.isDirectory())
|
|
205085
205769
|
out.push(...collectScenarioFiles(full));
|
|
@@ -205096,7 +205780,7 @@ function loadScenarios(repoRoot5) {
|
|
|
205096
205780
|
const rel = path55.relative(repoRoot5, file);
|
|
205097
205781
|
let doc;
|
|
205098
205782
|
try {
|
|
205099
|
-
doc = jsYaml.load(
|
|
205783
|
+
doc = jsYaml.load(fs50.readFileSync(file, "utf-8"));
|
|
205100
205784
|
} catch (e) {
|
|
205101
205785
|
errors.push({ file: rel, message: `YAML parse error: ${e instanceof Error ? e.message : e}` });
|
|
205102
205786
|
continue;
|
|
@@ -205160,11 +205844,11 @@ ${err.message}`;
|
|
|
205160
205844
|
}
|
|
205161
205845
|
|
|
205162
205846
|
// packages/guard-runner/dist/preflight.js
|
|
205163
|
-
import
|
|
205847
|
+
import fs52 from "node:fs";
|
|
205164
205848
|
import path57 from "node:path";
|
|
205165
205849
|
|
|
205166
205850
|
// packages/guard-runner/dist/sandbox.js
|
|
205167
|
-
import
|
|
205851
|
+
import fs51 from "node:fs";
|
|
205168
205852
|
import os11 from "node:os";
|
|
205169
205853
|
import path56 from "node:path";
|
|
205170
205854
|
var DETERMINISM_PINS = {
|
|
@@ -205176,13 +205860,13 @@ var DETERMINISM_PINS = {
|
|
|
205176
205860
|
var SandboxError = class extends Error {
|
|
205177
205861
|
};
|
|
205178
205862
|
function createSandbox(opts = {}) {
|
|
205179
|
-
const root2 =
|
|
205863
|
+
const root2 = fs51.mkdtempSync(path56.join(os11.tmpdir(), "tc-guard-"));
|
|
205180
205864
|
const cwd = path56.join(root2, "work");
|
|
205181
205865
|
const home = path56.join(root2, "home");
|
|
205182
205866
|
const tmp = path56.join(root2, "tmp");
|
|
205183
|
-
|
|
205184
|
-
|
|
205185
|
-
|
|
205867
|
+
fs51.mkdirSync(cwd, { recursive: true });
|
|
205868
|
+
fs51.mkdirSync(home, { recursive: true });
|
|
205869
|
+
fs51.mkdirSync(tmp, { recursive: true });
|
|
205186
205870
|
const xdg = {
|
|
205187
205871
|
XDG_CONFIG_HOME: path56.join(home, ".config"),
|
|
205188
205872
|
XDG_CACHE_HOME: path56.join(home, ".cache"),
|
|
@@ -205191,7 +205875,7 @@ function createSandbox(opts = {}) {
|
|
|
205191
205875
|
XDG_RUNTIME_DIR: path56.join(home, "run")
|
|
205192
205876
|
};
|
|
205193
205877
|
for (const dir of Object.values(xdg))
|
|
205194
|
-
|
|
205878
|
+
fs51.mkdirSync(dir, { recursive: true });
|
|
205195
205879
|
const env = {
|
|
205196
205880
|
// PATH: programs must resolve node/git; the only host value that passes through.
|
|
205197
205881
|
PATH: process.env.PATH ?? "",
|
|
@@ -205214,7 +205898,7 @@ function createSandbox(opts = {}) {
|
|
|
205214
205898
|
root: root2,
|
|
205215
205899
|
env,
|
|
205216
205900
|
cleanup() {
|
|
205217
|
-
|
|
205901
|
+
fs51.rmSync(root2, { recursive: true, force: true });
|
|
205218
205902
|
}
|
|
205219
205903
|
};
|
|
205220
205904
|
}
|
|
@@ -205224,14 +205908,14 @@ function seedFiles(cwd, files) {
|
|
|
205224
205908
|
if (target !== cwd && !target.startsWith(cwd + path56.sep)) {
|
|
205225
205909
|
throw new SandboxError(`setup.files path escapes the sandbox: ${rel}`);
|
|
205226
205910
|
}
|
|
205227
|
-
|
|
205228
|
-
|
|
205911
|
+
fs51.mkdirSync(path56.dirname(target), { recursive: true });
|
|
205912
|
+
fs51.writeFileSync(target, content);
|
|
205229
205913
|
}
|
|
205230
205914
|
}
|
|
205231
205915
|
function listSandboxFiles(dir) {
|
|
205232
205916
|
const out = [];
|
|
205233
205917
|
const walk20 = (current) => {
|
|
205234
|
-
for (const entry of
|
|
205918
|
+
for (const entry of fs51.readdirSync(current, { withFileTypes: true })) {
|
|
205235
205919
|
const full = path56.join(current, entry.name);
|
|
205236
205920
|
if (entry.isDirectory())
|
|
205237
205921
|
walk20(full);
|
|
@@ -205239,7 +205923,7 @@ function listSandboxFiles(dir) {
|
|
|
205239
205923
|
out.push(path56.relative(dir, full));
|
|
205240
205924
|
}
|
|
205241
205925
|
};
|
|
205242
|
-
if (
|
|
205926
|
+
if (fs51.existsSync(dir))
|
|
205243
205927
|
walk20(dir);
|
|
205244
205928
|
return out.sort();
|
|
205245
205929
|
}
|
|
@@ -205382,10 +206066,10 @@ function missingEntryScript(repoRoot5, entry) {
|
|
|
205382
206066
|
}
|
|
205383
206067
|
for (const arg of candidates) {
|
|
205384
206068
|
const resolved = path57.isAbsolute(arg) ? arg : path57.resolve(repoRoot5, arg);
|
|
205385
|
-
if (
|
|
206069
|
+
if (fs52.existsSync(resolved))
|
|
205386
206070
|
continue;
|
|
205387
206071
|
const parent = path57.dirname(resolved);
|
|
205388
|
-
const siblings =
|
|
206072
|
+
const siblings = fs52.existsSync(parent) ? fs52.readdirSync(parent).sort() : null;
|
|
205389
206073
|
return {
|
|
205390
206074
|
arg,
|
|
205391
206075
|
resolved,
|
|
@@ -205420,7 +206104,7 @@ function formatEntryPreflightError(opts) {
|
|
|
205420
206104
|
|
|
205421
206105
|
// packages/guard-runner/dist/capabilities/git.js
|
|
205422
206106
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
205423
|
-
import
|
|
206107
|
+
import fs53 from "node:fs";
|
|
205424
206108
|
import path58 from "node:path";
|
|
205425
206109
|
var GIT_IDENTITY = {
|
|
205426
206110
|
GIT_AUTHOR_NAME: "TrueCourse Guard",
|
|
@@ -205457,7 +206141,7 @@ function requireFiles(files, ctx) {
|
|
|
205457
206141
|
if (target !== ctx.cwd && !target.startsWith(ctx.cwd + path58.sep)) {
|
|
205458
206142
|
throw new CapabilityError("git", `path escapes the sandbox: ${rel}`);
|
|
205459
206143
|
}
|
|
205460
|
-
if (!
|
|
206144
|
+
if (!fs53.existsSync(target)) {
|
|
205461
206145
|
throw new CapabilityError("git", `declared file does not exist in the sandbox: ${rel} (seed it via setup.files or an earlier commit)`);
|
|
205462
206146
|
}
|
|
205463
206147
|
}
|
|
@@ -205545,7 +206229,7 @@ function normalize7(text4, normalizers, ctx) {
|
|
|
205545
206229
|
}
|
|
205546
206230
|
|
|
205547
206231
|
// packages/guard-runner/dist/expect.js
|
|
205548
|
-
import
|
|
206232
|
+
import fs54 from "node:fs";
|
|
205549
206233
|
import path59 from "node:path";
|
|
205550
206234
|
function evaluateExpect(params) {
|
|
205551
206235
|
const { expect } = params;
|
|
@@ -205618,7 +206302,7 @@ function matchStream(subject, matcher, value) {
|
|
|
205618
206302
|
}
|
|
205619
206303
|
function matchFile3(rel, matcher, sandboxCwd, normalizeText) {
|
|
205620
206304
|
const target = path59.resolve(sandboxCwd, rel);
|
|
205621
|
-
const exists2 =
|
|
206305
|
+
const exists2 = fs54.existsSync(target) && fs54.statSync(target).isFile();
|
|
205622
206306
|
if (matcher.exists === true || matcher.absent === false) {
|
|
205623
206307
|
if (!exists2)
|
|
205624
206308
|
return fileMiss(rel, "to exist", "missing");
|
|
@@ -205630,7 +206314,7 @@ function matchFile3(rel, matcher, sandboxCwd, normalizeText) {
|
|
|
205630
206314
|
if (matcher.equals !== void 0 || matcher.contains !== void 0) {
|
|
205631
206315
|
if (!exists2)
|
|
205632
206316
|
return fileMiss(rel, "to exist for a content check", "missing");
|
|
205633
|
-
const content = normalizeText(
|
|
206317
|
+
const content = normalizeText(fs54.readFileSync(target, "utf-8"));
|
|
205634
206318
|
if (matcher.equals !== void 0 && content !== matcher.equals) {
|
|
205635
206319
|
return {
|
|
205636
206320
|
subject: "files",
|
|
@@ -205660,12 +206344,12 @@ function fileMiss(rel, expectedPhrase, actualState) {
|
|
|
205660
206344
|
}
|
|
205661
206345
|
|
|
205662
206346
|
// packages/guard-runner/dist/evidence.js
|
|
205663
|
-
import
|
|
206347
|
+
import fs55 from "node:fs";
|
|
205664
206348
|
import path60 from "node:path";
|
|
205665
206349
|
function writeEvidence(params) {
|
|
205666
206350
|
const dir = evidenceScenarioDir(params.repoRoot, params.runId, params.scenarioId);
|
|
205667
|
-
|
|
205668
|
-
const
|
|
206351
|
+
fs55.mkdirSync(dir, { recursive: true });
|
|
206352
|
+
const focus = params.failingStep != null ? params.steps.find((s) => s.index === params.failingStep) : params.steps[params.steps.length - 1];
|
|
205669
206353
|
const invocation = {
|
|
205670
206354
|
scenarioId: params.scenarioId,
|
|
205671
206355
|
title: params.title,
|
|
@@ -205685,11 +206369,11 @@ function writeEvidence(params) {
|
|
|
205685
206369
|
}))
|
|
205686
206370
|
};
|
|
205687
206371
|
writeFile(dir, "invocation.json", JSON.stringify(invocation, null, 2));
|
|
205688
|
-
if (
|
|
205689
|
-
writeFile(dir, "stdout.raw.txt",
|
|
205690
|
-
writeFile(dir, "stdout.txt",
|
|
205691
|
-
writeFile(dir, "stderr.raw.txt",
|
|
205692
|
-
writeFile(dir, "stderr.txt",
|
|
206372
|
+
if (focus) {
|
|
206373
|
+
writeFile(dir, "stdout.raw.txt", focus.rawStdout);
|
|
206374
|
+
writeFile(dir, "stdout.txt", focus.normStdout);
|
|
206375
|
+
writeFile(dir, "stderr.raw.txt", focus.rawStderr);
|
|
206376
|
+
writeFile(dir, "stderr.txt", focus.normStderr);
|
|
205693
206377
|
}
|
|
205694
206378
|
const diffLines = [];
|
|
205695
206379
|
if (params.outcome === "fail" && params.mismatch) {
|
|
@@ -205697,8 +206381,10 @@ function writeEvidence(params) {
|
|
|
205697
206381
|
diffLines.push(`expected: ${params.mismatch.expected}`);
|
|
205698
206382
|
diffLines.push(`actual: ${params.mismatch.actual}`, "");
|
|
205699
206383
|
diffLines.push(...params.mismatch.detail);
|
|
205700
|
-
} else if (params.infraMessage) {
|
|
206384
|
+
} else if (params.outcome === "error" && params.infraMessage) {
|
|
205701
206385
|
diffLines.push(`step ${params.failingStep} \u2014 infrastructure error`, "", params.infraMessage);
|
|
206386
|
+
} else if (params.outcome === "pass") {
|
|
206387
|
+
diffLines.push(`all ${params.steps.length} step${params.steps.length === 1 ? "" : "s"} met their expectations`);
|
|
205702
206388
|
}
|
|
205703
206389
|
writeFile(dir, "diff.txt", diffLines.join("\n") + "\n");
|
|
205704
206390
|
writeFile(dir, "files.txt", listSandboxFiles(params.sandboxCwd).join("\n") + "\n");
|
|
@@ -205743,7 +206429,7 @@ function indent(text4) {
|
|
|
205743
206429
|
return body.split("\n").map((l) => ` ${l}`).join("\n");
|
|
205744
206430
|
}
|
|
205745
206431
|
function writeFile(dir, name, content) {
|
|
205746
|
-
|
|
206432
|
+
fs55.writeFileSync(path60.join(dir, name), content);
|
|
205747
206433
|
}
|
|
205748
206434
|
|
|
205749
206435
|
// packages/guard-runner/dist/run-scenario.js
|
|
@@ -205812,7 +206498,7 @@ async function runScenario(scenario, ctx) {
|
|
|
205812
206498
|
if (capture.spawnError || capture.timedOut) {
|
|
205813
206499
|
const infra = capture.timedOut ? `step timed out after ${ctx.stepTimeoutMs}ms` : `failed to spawn: ${capture.spawnError}`;
|
|
205814
206500
|
records.push(toRecord(stepIndex, argv, step.stdin, repeat3, iteration, capture, normText));
|
|
205815
|
-
const
|
|
206501
|
+
const evidencePath2 = writeEvidence({
|
|
205816
206502
|
repoRoot: ctx.repoRoot,
|
|
205817
206503
|
runId: ctx.runId,
|
|
205818
206504
|
scenarioId: scenario.id,
|
|
@@ -205830,7 +206516,7 @@ async function runScenario(scenario, ctx) {
|
|
|
205830
206516
|
outcome: "error",
|
|
205831
206517
|
durationMs: Date.now() - start,
|
|
205832
206518
|
failure: { step: stepIndex, expected: "the step to run", actual: infra },
|
|
205833
|
-
evidencePath
|
|
206519
|
+
evidencePath: evidencePath2
|
|
205834
206520
|
};
|
|
205835
206521
|
}
|
|
205836
206522
|
const normStdout = normText(capture.stdout);
|
|
@@ -205845,7 +206531,7 @@ async function runScenario(scenario, ctx) {
|
|
|
205845
206531
|
});
|
|
205846
206532
|
if (mismatch) {
|
|
205847
206533
|
records.push(toRecord(stepIndex, argv, step.stdin, repeat3, iteration, capture, normText));
|
|
205848
|
-
const
|
|
206534
|
+
const evidencePath2 = writeEvidence({
|
|
205849
206535
|
repoRoot: ctx.repoRoot,
|
|
205850
206536
|
runId: ctx.runId,
|
|
205851
206537
|
scenarioId: scenario.id,
|
|
@@ -205867,7 +206553,7 @@ async function runScenario(scenario, ctx) {
|
|
|
205867
206553
|
expected: mismatch.expected,
|
|
205868
206554
|
actual: mismatch.actual
|
|
205869
206555
|
},
|
|
205870
|
-
evidencePath
|
|
206556
|
+
evidencePath: evidencePath2
|
|
205871
206557
|
};
|
|
205872
206558
|
}
|
|
205873
206559
|
}
|
|
@@ -205875,7 +206561,18 @@ async function runScenario(scenario, ctx) {
|
|
|
205875
206561
|
records.push(toRecord(stepIndex, argv, step.stdin, repeat3, repeat3, lastCapture, normText));
|
|
205876
206562
|
}
|
|
205877
206563
|
}
|
|
205878
|
-
|
|
206564
|
+
const evidencePath = ctx.capturePassEvidence ? writeEvidence({
|
|
206565
|
+
repoRoot: ctx.repoRoot,
|
|
206566
|
+
runId: ctx.runId,
|
|
206567
|
+
scenarioId: scenario.id,
|
|
206568
|
+
title: scenario.title,
|
|
206569
|
+
binds: scenario.binds,
|
|
206570
|
+
outcome: "pass",
|
|
206571
|
+
steps: records,
|
|
206572
|
+
sandboxCwd: sandbox.cwd,
|
|
206573
|
+
envPins: ENV_PINS
|
|
206574
|
+
}) : void 0;
|
|
206575
|
+
return { ...base2, outcome: "pass", durationMs: Date.now() - start, ...evidencePath ? { evidencePath } : {} };
|
|
205879
206576
|
} finally {
|
|
205880
206577
|
sandbox.cleanup();
|
|
205881
206578
|
}
|
|
@@ -205900,7 +206597,7 @@ function toRecord(index, argv, stdin, repeat3, iterationsRun, capture, normText)
|
|
|
205900
206597
|
|
|
205901
206598
|
// packages/guard-runner/dist/doc-index.js
|
|
205902
206599
|
init_zod();
|
|
205903
|
-
import
|
|
206600
|
+
import fs56 from "node:fs";
|
|
205904
206601
|
import path62 from "node:path";
|
|
205905
206602
|
|
|
205906
206603
|
// packages/guard-runner/dist/section-index.js
|
|
@@ -206063,10 +206760,10 @@ function resolveBinding(index, anchor, fingerprint2) {
|
|
|
206063
206760
|
var CorpusShape = external_exports.object({ docs: external_exports.array(external_exports.object({ ref: external_exports.string() }).passthrough()).optional() }).passthrough();
|
|
206064
206761
|
function corpusKeptDocs(repoRoot5) {
|
|
206065
206762
|
const file = path62.join(repoRoot5, ".truecourse", "specs", "corpus.json");
|
|
206066
|
-
if (!
|
|
206763
|
+
if (!fs56.existsSync(file))
|
|
206067
206764
|
return [];
|
|
206068
206765
|
try {
|
|
206069
|
-
const parsed = CorpusShape.safeParse(JSON.parse(
|
|
206766
|
+
const parsed = CorpusShape.safeParse(JSON.parse(fs56.readFileSync(file, "utf-8")));
|
|
206070
206767
|
if (!parsed.success)
|
|
206071
206768
|
return [];
|
|
206072
206769
|
return (parsed.data.docs ?? []).map((d3) => d3.ref);
|
|
@@ -206082,24 +206779,24 @@ function indexRepoDocs(repoRoot5, boundDocs) {
|
|
|
206082
206779
|
const missing = /* @__PURE__ */ new Set();
|
|
206083
206780
|
for (const doc of wanted) {
|
|
206084
206781
|
const abs = path62.resolve(repoRoot5, doc);
|
|
206085
|
-
if (!
|
|
206782
|
+
if (!fs56.existsSync(abs) || !fs56.statSync(abs).isFile()) {
|
|
206086
206783
|
missing.add(doc);
|
|
206087
206784
|
continue;
|
|
206088
206785
|
}
|
|
206089
|
-
indexes.set(doc, buildDocSectionIndex(doc,
|
|
206786
|
+
indexes.set(doc, buildDocSectionIndex(doc, fs56.readFileSync(abs, "utf-8")));
|
|
206090
206787
|
}
|
|
206091
206788
|
return { indexes, missing };
|
|
206092
206789
|
}
|
|
206093
206790
|
|
|
206094
206791
|
// packages/guard-runner/dist/manifest.js
|
|
206095
206792
|
init_dist5();
|
|
206096
|
-
import
|
|
206793
|
+
import fs57 from "node:fs";
|
|
206097
206794
|
function readManifest2(repoRoot5) {
|
|
206098
206795
|
const file = manifestPath2(repoRoot5);
|
|
206099
|
-
if (!
|
|
206796
|
+
if (!fs57.existsSync(file))
|
|
206100
206797
|
return null;
|
|
206101
206798
|
try {
|
|
206102
|
-
const parsed = GuardManifestSchema.safeParse(JSON.parse(
|
|
206799
|
+
const parsed = GuardManifestSchema.safeParse(JSON.parse(fs57.readFileSync(file, "utf-8")));
|
|
206103
206800
|
return parsed.success ? parsed.data : null;
|
|
206104
206801
|
} catch {
|
|
206105
206802
|
return null;
|
|
@@ -206168,13 +206865,15 @@ async function runGuard(opts) {
|
|
|
206168
206865
|
settled += 1;
|
|
206169
206866
|
opts.onScenarioSettled?.(settled, selected.length, result);
|
|
206170
206867
|
}
|
|
206868
|
+
const capturePassEvidence = opts.persist !== false;
|
|
206171
206869
|
const executed = await mapWithConcurrency(executable, concurrency, async ({ scenario, resolution }) => {
|
|
206172
206870
|
const outcome = await runScenario(scenario, {
|
|
206173
206871
|
repoRoot: repoRoot5,
|
|
206174
206872
|
runId,
|
|
206175
206873
|
resolvedEntry,
|
|
206176
206874
|
recipeEnv: loaded.recipe.env,
|
|
206177
|
-
stepTimeoutMs
|
|
206875
|
+
stepTimeoutMs,
|
|
206876
|
+
capturePassEvidence
|
|
206178
206877
|
});
|
|
206179
206878
|
const result = resolution.kind === "remap" ? { ...outcome, remappedTo: resolution.section.anchor } : outcome;
|
|
206180
206879
|
settled += 1;
|
|
@@ -206273,13 +206972,13 @@ async function mapWithConcurrency(items, limit, fn) {
|
|
|
206273
206972
|
|
|
206274
206973
|
// packages/guard-runner/dist/decisions.js
|
|
206275
206974
|
init_dist5();
|
|
206276
|
-
import
|
|
206975
|
+
import fs58 from "node:fs";
|
|
206277
206976
|
function readGuardDecisions(repoRoot5) {
|
|
206278
206977
|
const file = guardDecisionsPath(repoRoot5);
|
|
206279
|
-
if (!
|
|
206978
|
+
if (!fs58.existsSync(file))
|
|
206280
206979
|
return EMPTY_GUARD_DECISIONS;
|
|
206281
206980
|
try {
|
|
206282
|
-
const parsed = GuardDecisionsSchema.safeParse(JSON.parse(
|
|
206981
|
+
const parsed = GuardDecisionsSchema.safeParse(JSON.parse(fs58.readFileSync(file, "utf-8")));
|
|
206283
206982
|
return parsed.success ? parsed.data : EMPTY_GUARD_DECISIONS;
|
|
206284
206983
|
} catch {
|
|
206285
206984
|
return EMPTY_GUARD_DECISIONS;
|
|
@@ -206291,7 +206990,7 @@ init_dist5();
|
|
|
206291
206990
|
|
|
206292
206991
|
// packages/guard-generator/dist/section-plan.js
|
|
206293
206992
|
init_zod();
|
|
206294
|
-
import
|
|
206993
|
+
import fs59 from "node:fs";
|
|
206295
206994
|
import path63 from "node:path";
|
|
206296
206995
|
import { createHash as createHash15 } from "node:crypto";
|
|
206297
206996
|
init_dist5();
|
|
@@ -206609,10 +207308,10 @@ var CorpusShape2 = external_exports.object({
|
|
|
206609
207308
|
function readCorpusAreaTags(repoRoot5) {
|
|
206610
207309
|
const file = path63.join(repoRoot5, ".truecourse", "specs", "corpus.json");
|
|
206611
207310
|
const map2 = /* @__PURE__ */ new Map();
|
|
206612
|
-
if (!
|
|
207311
|
+
if (!fs59.existsSync(file))
|
|
206613
207312
|
return map2;
|
|
206614
207313
|
try {
|
|
206615
|
-
const parsed = CorpusShape2.safeParse(JSON.parse(
|
|
207314
|
+
const parsed = CorpusShape2.safeParse(JSON.parse(fs59.readFileSync(file, "utf-8")));
|
|
206616
207315
|
if (!parsed.success)
|
|
206617
207316
|
return map2;
|
|
206618
207317
|
for (const d3 of parsed.data.docs ?? [])
|
|
@@ -206631,17 +207330,17 @@ function generationInputsHash(fingerprint2, recipeFingerprint) {
|
|
|
206631
207330
|
].join("\0")).digest("hex");
|
|
206632
207331
|
}
|
|
206633
207332
|
function hasGuardUniverse(repoRoot5) {
|
|
206634
|
-
return
|
|
207333
|
+
return fs59.existsSync(path63.join(repoRoot5, ".truecourse", "specs", "corpus.json"));
|
|
206635
207334
|
}
|
|
206636
207335
|
function planGuardWork(repoRoot5, recipeFingerprint) {
|
|
206637
207336
|
const recipeFp = recipeFingerprint ?? computeRecipeFingerprint(repoRoot5);
|
|
206638
|
-
const recipeMissing = !
|
|
207337
|
+
const recipeMissing = !fs59.existsSync(recipePath(repoRoot5));
|
|
206639
207338
|
const hasUniverse = hasGuardUniverse(repoRoot5);
|
|
206640
207339
|
const { indexes } = indexRepoDocs(repoRoot5, []);
|
|
206641
207340
|
const areaTags = readCorpusAreaTags(repoRoot5);
|
|
206642
207341
|
const sections = [];
|
|
206643
207342
|
for (const [doc, index] of indexes) {
|
|
206644
|
-
const texts = extractSectionTexts(doc,
|
|
207343
|
+
const texts = extractSectionTexts(doc, fs59.readFileSync(path63.resolve(repoRoot5, doc), "utf-8"));
|
|
206645
207344
|
for (const s of index.sections) {
|
|
206646
207345
|
const t2 = texts.get(s.anchor);
|
|
206647
207346
|
sections.push({
|
|
@@ -206686,7 +207385,7 @@ function collectWorkDocs(repoRoot5, plan) {
|
|
|
206686
207385
|
}
|
|
206687
207386
|
return [...byDoc].map(([doc, sections]) => ({
|
|
206688
207387
|
doc,
|
|
206689
|
-
content:
|
|
207388
|
+
content: fs59.readFileSync(path63.resolve(repoRoot5, doc), "utf-8"),
|
|
206690
207389
|
sections
|
|
206691
207390
|
}));
|
|
206692
207391
|
}
|
|
@@ -207073,7 +207772,7 @@ function truncate3(text4) {
|
|
|
207073
207772
|
}
|
|
207074
207773
|
|
|
207075
207774
|
// packages/guard-generator/dist/recipe-discovery.js
|
|
207076
|
-
import
|
|
207775
|
+
import fs60 from "node:fs";
|
|
207077
207776
|
import os13 from "node:os";
|
|
207078
207777
|
import path65 from "node:path";
|
|
207079
207778
|
import { createHash as createHash18 } from "node:crypto";
|
|
@@ -207129,8 +207828,8 @@ async function discoverRecipe(repoRoot5, runner) {
|
|
|
207129
207828
|
...proposal.env ? { env: proposal.env } : {}
|
|
207130
207829
|
};
|
|
207131
207830
|
const target = recipePath(repoRoot5);
|
|
207132
|
-
|
|
207133
|
-
|
|
207831
|
+
fs60.mkdirSync(path65.dirname(target), { recursive: true });
|
|
207832
|
+
fs60.writeFileSync(target, JSON.stringify(recipe, null, 2) + "\n");
|
|
207134
207833
|
return {
|
|
207135
207834
|
status: "discovered",
|
|
207136
207835
|
recipe,
|
|
@@ -207161,13 +207860,13 @@ async function proposeRecipeWithReask(input, runner) {
|
|
|
207161
207860
|
}
|
|
207162
207861
|
function readDiscoveryInputs(repoRoot5) {
|
|
207163
207862
|
const pkgPath = path65.join(repoRoot5, "package.json");
|
|
207164
|
-
const packageJson =
|
|
207165
|
-
const presentInputs = DISCOVERY_INPUTS.filter((f2) =>
|
|
207863
|
+
const packageJson = fs60.existsSync(pkgPath) ? fs60.readFileSync(pkgPath, "utf-8") : "(no package.json)";
|
|
207864
|
+
const presentInputs = DISCOVERY_INPUTS.filter((f2) => fs60.existsSync(path65.join(repoRoot5, f2)));
|
|
207166
207865
|
return { packageJson, presentInputs };
|
|
207167
207866
|
}
|
|
207168
207867
|
async function probeEntry(repoRoot5, entry) {
|
|
207169
207868
|
const resolved = resolveEntry(repoRoot5, entry);
|
|
207170
|
-
const cwd =
|
|
207869
|
+
const cwd = fs60.mkdtempSync(path65.join(os13.tmpdir(), "tc-guard-probe-"));
|
|
207171
207870
|
try {
|
|
207172
207871
|
for (const args of [["--help"], []]) {
|
|
207173
207872
|
const capture = await executeStep({
|
|
@@ -207184,7 +207883,7 @@ async function probeEntry(repoRoot5, entry) {
|
|
|
207184
207883
|
reason: `entrypoint ${JSON.stringify(entry)} did not answer to \`--help\` or a bare invocation`
|
|
207185
207884
|
};
|
|
207186
207885
|
} finally {
|
|
207187
|
-
|
|
207886
|
+
fs60.rmSync(cwd, { recursive: true, force: true });
|
|
207188
207887
|
}
|
|
207189
207888
|
}
|
|
207190
207889
|
|
|
@@ -207231,7 +207930,7 @@ async function birthValidate(repoRoot5, candidates, opts = {}) {
|
|
|
207231
207930
|
}
|
|
207232
207931
|
|
|
207233
207932
|
// packages/guard-generator/dist/serialize.js
|
|
207234
|
-
import
|
|
207933
|
+
import fs61 from "node:fs";
|
|
207235
207934
|
import path66 from "node:path";
|
|
207236
207935
|
init_dist5();
|
|
207237
207936
|
function anchorLeaf(anchor) {
|
|
@@ -207274,15 +207973,15 @@ function scenarioFileIndex(repoRoot5) {
|
|
|
207274
207973
|
const root2 = scenariosDir(repoRoot5);
|
|
207275
207974
|
const map2 = /* @__PURE__ */ new Map();
|
|
207276
207975
|
const walk20 = (dir) => {
|
|
207277
|
-
if (!
|
|
207976
|
+
if (!fs61.existsSync(dir))
|
|
207278
207977
|
return;
|
|
207279
|
-
for (const entry of
|
|
207978
|
+
for (const entry of fs61.readdirSync(dir, { withFileTypes: true })) {
|
|
207280
207979
|
const full = path66.join(dir, entry.name);
|
|
207281
207980
|
if (entry.isDirectory())
|
|
207282
207981
|
walk20(full);
|
|
207283
207982
|
else if (entry.isFile() && /\.ya?ml$/i.test(entry.name)) {
|
|
207284
207983
|
try {
|
|
207285
|
-
const doc = jsYaml.load(
|
|
207984
|
+
const doc = jsYaml.load(fs61.readFileSync(full, "utf-8"));
|
|
207286
207985
|
if (doc && typeof doc.id === "string")
|
|
207287
207986
|
map2.set(doc.id, full);
|
|
207288
207987
|
} catch {
|
|
@@ -207301,17 +208000,17 @@ function serializeScenarioYaml(scenario) {
|
|
|
207301
208000
|
}
|
|
207302
208001
|
function writeScenarioFile(repoRoot5, slug2, scenario) {
|
|
207303
208002
|
const dir = path66.join(scenariosDir(repoRoot5), slug2);
|
|
207304
|
-
|
|
208003
|
+
fs61.mkdirSync(dir, { recursive: true });
|
|
207305
208004
|
const file = path66.join(dir, `${scenario.id}.yaml`);
|
|
207306
|
-
|
|
208005
|
+
fs61.writeFileSync(file, serializeScenarioYaml(scenario));
|
|
207307
208006
|
return path66.relative(repoRoot5, file);
|
|
207308
208007
|
}
|
|
207309
208008
|
function deleteScenarioFiles(repoRoot5, ids) {
|
|
207310
208009
|
const index = scenarioFileIndex(repoRoot5);
|
|
207311
208010
|
for (const id of ids) {
|
|
207312
208011
|
const file = index.get(id);
|
|
207313
|
-
if (file &&
|
|
207314
|
-
|
|
208012
|
+
if (file && fs61.existsSync(file))
|
|
208013
|
+
fs61.rmSync(file);
|
|
207315
208014
|
}
|
|
207316
208015
|
}
|
|
207317
208016
|
|
|
@@ -208016,7 +208715,7 @@ init_context_router();
|
|
|
208016
208715
|
|
|
208017
208716
|
// packages/core/dist/services/llm/model-prices.js
|
|
208018
208717
|
init_paths();
|
|
208019
|
-
import
|
|
208718
|
+
import fs62 from "node:fs";
|
|
208020
208719
|
import path67 from "node:path";
|
|
208021
208720
|
var OPENROUTER_URL = "https://openrouter.ai/api/v1/models";
|
|
208022
208721
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -208037,7 +208736,7 @@ function cacheFilePath() {
|
|
|
208037
208736
|
}
|
|
208038
208737
|
function readCache7() {
|
|
208039
208738
|
try {
|
|
208040
|
-
const t2 = JSON.parse(
|
|
208739
|
+
const t2 = JSON.parse(fs62.readFileSync(cacheFilePath(), "utf-8"));
|
|
208041
208740
|
if (t2 && t2.tiers && t2.byId && typeof t2.fetchedAt === "number")
|
|
208042
208741
|
return t2;
|
|
208043
208742
|
} catch {
|
|
@@ -208046,8 +208745,8 @@ function readCache7() {
|
|
|
208046
208745
|
}
|
|
208047
208746
|
function writeCache7(t2) {
|
|
208048
208747
|
try {
|
|
208049
|
-
|
|
208050
|
-
|
|
208748
|
+
fs62.mkdirSync(path67.dirname(cacheFilePath()), { recursive: true });
|
|
208749
|
+
fs62.writeFileSync(cacheFilePath(), JSON.stringify(t2));
|
|
208051
208750
|
} catch {
|
|
208052
208751
|
}
|
|
208053
208752
|
}
|
|
@@ -208426,7 +209125,7 @@ function changedSubject(total, changed, noun) {
|
|
|
208426
209125
|
|
|
208427
209126
|
// packages/core/dist/commands/spec-in-process.js
|
|
208428
209127
|
init_dist8();
|
|
208429
|
-
import
|
|
209128
|
+
import fs67 from "node:fs";
|
|
208430
209129
|
import path72 from "node:path";
|
|
208431
209130
|
init_git();
|
|
208432
209131
|
import { createHash as createHash20, randomUUID as randomUUID27 } from "node:crypto";
|
|
@@ -208434,7 +209133,7 @@ import { createHash as createHash20, randomUUID as randomUUID27 } from "node:cry
|
|
|
208434
209133
|
// packages/core/dist/lib/verify-store.js
|
|
208435
209134
|
init_atomic_write();
|
|
208436
209135
|
init_analysis_store();
|
|
208437
|
-
import
|
|
209136
|
+
import fs63 from "node:fs";
|
|
208438
209137
|
import path68 from "node:path";
|
|
208439
209138
|
|
|
208440
209139
|
// packages/core/dist/types/verify-snapshot.js
|
|
@@ -208533,7 +209232,7 @@ var FileVerifyStore = class {
|
|
|
208533
209232
|
const file = verifyLatestPath(repoPath);
|
|
208534
209233
|
let mtime;
|
|
208535
209234
|
try {
|
|
208536
|
-
mtime =
|
|
209235
|
+
mtime = fs63.statSync(file).mtimeMs;
|
|
208537
209236
|
} catch (err) {
|
|
208538
209237
|
if (err.code === "ENOENT") {
|
|
208539
209238
|
latestCache2.delete(repoPath);
|
|
@@ -208544,7 +209243,7 @@ var FileVerifyStore = class {
|
|
|
208544
209243
|
const cached = latestCache2.get(repoPath);
|
|
208545
209244
|
if (cached && cached.mtime === mtime)
|
|
208546
209245
|
return cached.data;
|
|
208547
|
-
const data = JSON.parse(
|
|
209246
|
+
const data = JSON.parse(fs63.readFileSync(file, "utf-8"));
|
|
208548
209247
|
latestCache2.set(repoPath, { mtime, data });
|
|
208549
209248
|
return data;
|
|
208550
209249
|
}
|
|
@@ -208554,7 +209253,7 @@ var FileVerifyStore = class {
|
|
|
208554
209253
|
}
|
|
208555
209254
|
async deleteVerifyLatest(repoPath) {
|
|
208556
209255
|
try {
|
|
208557
|
-
|
|
209256
|
+
fs63.unlinkSync(verifyLatestPath(repoPath));
|
|
208558
209257
|
} catch (err) {
|
|
208559
209258
|
if (err.code !== "ENOENT")
|
|
208560
209259
|
throw err;
|
|
@@ -208568,21 +209267,21 @@ var FileVerifyStore = class {
|
|
|
208568
209267
|
}
|
|
208569
209268
|
async readVerifyRun(repoPath, filename) {
|
|
208570
209269
|
const file = verifyRunPath(repoPath, filename);
|
|
208571
|
-
if (!
|
|
209270
|
+
if (!fs63.existsSync(file))
|
|
208572
209271
|
return null;
|
|
208573
|
-
return JSON.parse(
|
|
209272
|
+
return JSON.parse(fs63.readFileSync(file, "utf-8"));
|
|
208574
209273
|
}
|
|
208575
209274
|
async listVerifyRuns(repoPath) {
|
|
208576
209275
|
const dir = runsDir(repoPath);
|
|
208577
|
-
if (!
|
|
209276
|
+
if (!fs63.existsSync(dir))
|
|
208578
209277
|
return [];
|
|
208579
|
-
return
|
|
209278
|
+
return fs63.readdirSync(dir).filter((n) => n.endsWith(".json")).sort();
|
|
208580
209279
|
}
|
|
208581
209280
|
async readVerifyHistory(repoPath) {
|
|
208582
209281
|
const file = verifyHistoryPath(repoPath);
|
|
208583
|
-
if (!
|
|
209282
|
+
if (!fs63.existsSync(file))
|
|
208584
209283
|
return { runs: [] };
|
|
208585
|
-
return JSON.parse(
|
|
209284
|
+
return JSON.parse(fs63.readFileSync(file, "utf-8"));
|
|
208586
209285
|
}
|
|
208587
209286
|
async appendVerifyHistory(repoPath, entry) {
|
|
208588
209287
|
const history = await this.readVerifyHistory(repoPath);
|
|
@@ -208595,7 +209294,7 @@ var FileVerifyStore = class {
|
|
|
208595
209294
|
if (!entry)
|
|
208596
209295
|
return false;
|
|
208597
209296
|
try {
|
|
208598
|
-
|
|
209297
|
+
fs63.unlinkSync(verifyRunPath(repoPath, entry.filename));
|
|
208599
209298
|
} catch (err) {
|
|
208600
209299
|
if (err.code !== "ENOENT")
|
|
208601
209300
|
throw err;
|
|
@@ -208617,16 +209316,16 @@ var FileVerifyStore = class {
|
|
|
208617
209316
|
}
|
|
208618
209317
|
async readVerifyDiff(repoPath, scope) {
|
|
208619
209318
|
const file = verifyDiffPath(repoPath, scope);
|
|
208620
|
-
if (!
|
|
209319
|
+
if (!fs63.existsSync(file))
|
|
208621
209320
|
return null;
|
|
208622
|
-
return JSON.parse(
|
|
209321
|
+
return JSON.parse(fs63.readFileSync(file, "utf-8"));
|
|
208623
209322
|
}
|
|
208624
209323
|
async writeVerifyDiff(repoPath, diff, scope) {
|
|
208625
209324
|
atomicWriteJson(verifyDiffPath(repoPath, scope), diff);
|
|
208626
209325
|
}
|
|
208627
209326
|
async deleteVerifyDiff(repoPath, scope) {
|
|
208628
209327
|
try {
|
|
208629
|
-
|
|
209328
|
+
fs63.unlinkSync(verifyDiffPath(repoPath, scope));
|
|
208630
209329
|
} catch (err) {
|
|
208631
209330
|
if (err.code !== "ENOENT")
|
|
208632
209331
|
throw err;
|
|
@@ -208660,7 +209359,7 @@ async function repoRef(repoRoot5, commitOverride) {
|
|
|
208660
209359
|
}
|
|
208661
209360
|
|
|
208662
209361
|
// packages/core/dist/lib/contract-store.js
|
|
208663
|
-
import
|
|
209362
|
+
import fs64 from "node:fs";
|
|
208664
209363
|
import path69 from "node:path";
|
|
208665
209364
|
var KIND_REL = {
|
|
208666
209365
|
contracts: [".truecourse", "contracts"],
|
|
@@ -208671,7 +209370,7 @@ function countTcFiles(dir) {
|
|
|
208671
209370
|
let n = 0;
|
|
208672
209371
|
let entries;
|
|
208673
209372
|
try {
|
|
208674
|
-
entries =
|
|
209373
|
+
entries = fs64.readdirSync(dir, { withFileTypes: true });
|
|
208675
209374
|
} catch {
|
|
208676
209375
|
return 0;
|
|
208677
209376
|
}
|
|
@@ -208688,7 +209387,7 @@ function walkTcRel(dir, excludeInferred) {
|
|
|
208688
209387
|
const walk20 = (rel) => {
|
|
208689
209388
|
let entries;
|
|
208690
209389
|
try {
|
|
208691
|
-
entries =
|
|
209390
|
+
entries = fs64.readdirSync(path69.join(dir, rel), { withFileTypes: true });
|
|
208692
209391
|
} catch {
|
|
208693
209392
|
return;
|
|
208694
209393
|
}
|
|
@@ -208726,13 +209425,13 @@ var FileContractStore = class {
|
|
|
208726
209425
|
}
|
|
208727
209426
|
async loadContracts(ref, kind) {
|
|
208728
209427
|
const dir = path69.join(ref.repoKey, ...KIND_REL[kind]);
|
|
208729
|
-
if (!
|
|
209428
|
+
if (!fs64.existsSync(dir))
|
|
208730
209429
|
return null;
|
|
208731
209430
|
return { dir, cleanup: async () => {
|
|
208732
209431
|
} };
|
|
208733
209432
|
}
|
|
208734
209433
|
async hasContracts(ref, kind) {
|
|
208735
|
-
return
|
|
209434
|
+
return fs64.existsSync(path69.join(ref.repoKey, ...KIND_REL[kind]));
|
|
208736
209435
|
}
|
|
208737
209436
|
// The file impl reads the live repo tree, which is whatever is checked out —
|
|
208738
209437
|
// there is no per-commit history, so `commitSha` is ignored (OSS is latest).
|
|
@@ -208741,21 +209440,21 @@ var FileContractStore = class {
|
|
|
208741
209440
|
}
|
|
208742
209441
|
async readContractFile(repoKey, kind, relPath, _commitSha) {
|
|
208743
209442
|
const dest = safeResolve(path69.join(repoKey, ...KIND_REL[kind]), relPath);
|
|
208744
|
-
if (!dest || !
|
|
209443
|
+
if (!dest || !fs64.existsSync(dest) || !fs64.statSync(dest).isFile())
|
|
208745
209444
|
return null;
|
|
208746
|
-
return
|
|
209445
|
+
return fs64.readFileSync(dest, "utf-8");
|
|
208747
209446
|
}
|
|
208748
209447
|
async putContractFile(ref, kind, relPath, content) {
|
|
208749
209448
|
const dest = safeResolve(path69.join(ref.repoKey, ...KIND_REL[kind]), relPath);
|
|
208750
209449
|
if (!dest)
|
|
208751
209450
|
throw new Error(`[contract-store] unsafe contract path: ${relPath}`);
|
|
208752
|
-
|
|
208753
|
-
|
|
209451
|
+
fs64.mkdirSync(path69.dirname(dest), { recursive: true });
|
|
209452
|
+
fs64.writeFileSync(dest, content);
|
|
208754
209453
|
}
|
|
208755
209454
|
async deleteContractFile(ref, kind, relPath) {
|
|
208756
209455
|
const dest = safeResolve(path69.join(ref.repoKey, ...KIND_REL[kind]), relPath);
|
|
208757
209456
|
if (dest)
|
|
208758
|
-
|
|
209457
|
+
fs64.rmSync(dest, { force: true });
|
|
208759
209458
|
}
|
|
208760
209459
|
// OSS/local has no workspace concept (mirrors the spec store). Writing throws
|
|
208761
209460
|
// (fail loud — a caller that reached here is mis-wired); reads are empty so an
|
|
@@ -208782,7 +209481,7 @@ var loadWorkspaceContracts = (ref, kind) => active8.loadWorkspaceContracts(ref,
|
|
|
208782
209481
|
var contractsMaterializeInPlace = () => active8.materializesInPlace;
|
|
208783
209482
|
|
|
208784
209483
|
// packages/core/dist/lib/spec-store.js
|
|
208785
|
-
import
|
|
209484
|
+
import fs65 from "node:fs";
|
|
208786
209485
|
import path70 from "node:path";
|
|
208787
209486
|
function specPath(repoKey, artifact) {
|
|
208788
209487
|
return path70.join(repoKey, ".truecourse", "specs", `${artifact}.json`);
|
|
@@ -208798,18 +209497,18 @@ var FileSpecStore = class {
|
|
|
208798
209497
|
throw new Error(PR_DECISIONS_FILE_ERROR);
|
|
208799
209498
|
}
|
|
208800
209499
|
const file = specPath(ref.repoKey, artifact);
|
|
208801
|
-
|
|
208802
|
-
|
|
209500
|
+
fs65.mkdirSync(path70.dirname(file), { recursive: true });
|
|
209501
|
+
fs65.writeFileSync(file, JSON.stringify(json2, null, 2) + "\n", "utf-8");
|
|
208803
209502
|
}
|
|
208804
209503
|
async loadSpec(ref, artifact) {
|
|
208805
209504
|
if (artifact === "decisions" && isPrDecisionsRef(ref.commitSha)) {
|
|
208806
209505
|
throw new Error(PR_DECISIONS_FILE_ERROR);
|
|
208807
209506
|
}
|
|
208808
209507
|
const file = specPath(ref.repoKey, artifact);
|
|
208809
|
-
if (!
|
|
209508
|
+
if (!fs65.existsSync(file))
|
|
208810
209509
|
return null;
|
|
208811
209510
|
try {
|
|
208812
|
-
return JSON.parse(
|
|
209511
|
+
return JSON.parse(fs65.readFileSync(file, "utf-8"));
|
|
208813
209512
|
} catch {
|
|
208814
209513
|
return null;
|
|
208815
209514
|
}
|
|
@@ -208819,8 +209518,8 @@ var FileSpecStore = class {
|
|
|
208819
209518
|
throw new Error(PR_DECISIONS_FILE_ERROR);
|
|
208820
209519
|
}
|
|
208821
209520
|
const file = specPath(ref.repoKey, artifact);
|
|
208822
|
-
if (
|
|
208823
|
-
|
|
209521
|
+
if (fs65.existsSync(file))
|
|
209522
|
+
fs65.rmSync(file);
|
|
208824
209523
|
}
|
|
208825
209524
|
// The file impl is single-document-per-repo, so "latest" === read the file.
|
|
208826
209525
|
async loadLatest(repoKey, artifact) {
|
|
@@ -208847,7 +209546,7 @@ var loadLatestSpec = (repoKey, artifact) => active9.loadLatest(repoKey, artifact
|
|
|
208847
209546
|
var specsMaterializeInPlace = () => active9.materializesInPlace;
|
|
208848
209547
|
|
|
208849
209548
|
// packages/core/dist/lib/inferred-action-store.js
|
|
208850
|
-
import
|
|
209549
|
+
import fs66 from "node:fs";
|
|
208851
209550
|
import path71 from "node:path";
|
|
208852
209551
|
function actionsFile(repoKey) {
|
|
208853
209552
|
return path71.join(repoKey, ".truecourse", "specs", "inferred-actions.json");
|
|
@@ -208855,15 +209554,15 @@ function actionsFile(repoKey) {
|
|
|
208855
209554
|
var FileInferredActionStore = class {
|
|
208856
209555
|
read(repoKey) {
|
|
208857
209556
|
try {
|
|
208858
|
-
return JSON.parse(
|
|
209557
|
+
return JSON.parse(fs66.readFileSync(actionsFile(repoKey), "utf-8"));
|
|
208859
209558
|
} catch {
|
|
208860
209559
|
return [];
|
|
208861
209560
|
}
|
|
208862
209561
|
}
|
|
208863
209562
|
write(repoKey, actions) {
|
|
208864
209563
|
const file = actionsFile(repoKey);
|
|
208865
|
-
|
|
208866
|
-
|
|
209564
|
+
fs66.mkdirSync(path71.dirname(file), { recursive: true });
|
|
209565
|
+
fs66.writeFileSync(file, JSON.stringify(actions, null, 2) + "\n", "utf-8");
|
|
208867
209566
|
}
|
|
208868
209567
|
async setAction(repoKey, action) {
|
|
208869
209568
|
const next = this.read(repoKey).filter((a) => !(a.kind === action.kind && a.identity === action.identity));
|
|
@@ -208998,7 +209697,7 @@ function generatedMarkerPath(repoRoot5) {
|
|
|
208998
209697
|
}
|
|
208999
209698
|
function stampGeneratedMarker(repoRoot5, summary) {
|
|
209000
209699
|
const file = generatedMarkerPath(repoRoot5);
|
|
209001
|
-
|
|
209700
|
+
fs67.mkdirSync(path72.dirname(file), { recursive: true });
|
|
209002
209701
|
const body = {
|
|
209003
209702
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
209004
209703
|
written: summary?.written ?? 0,
|
|
@@ -209006,7 +209705,7 @@ function stampGeneratedMarker(repoRoot5, summary) {
|
|
|
209006
209705
|
validationIssues: summary?.validationIssues ?? [],
|
|
209007
209706
|
enumerateFailures: summary?.enumerateFailures ?? []
|
|
209008
209707
|
};
|
|
209009
|
-
|
|
209708
|
+
fs67.writeFileSync(file, JSON.stringify(body, null, 2) + "\n");
|
|
209010
209709
|
}
|
|
209011
209710
|
function resolveCurateModels(repoRoot5) {
|
|
209012
209711
|
return {
|
|
@@ -209131,19 +209830,19 @@ async function curateInProcess(repoRoot5, options = {}) {
|
|
|
209131
209830
|
}
|
|
209132
209831
|
function buildPriorContracts(repoRoot5) {
|
|
209133
209832
|
const dir = path72.join(repoRoot5, ".truecourse", "contracts");
|
|
209134
|
-
if (!
|
|
209833
|
+
if (!fs67.existsSync(dir))
|
|
209135
209834
|
return void 0;
|
|
209136
209835
|
const targets = [];
|
|
209137
209836
|
const bodyByKey = /* @__PURE__ */ new Map();
|
|
209138
209837
|
const walk20 = (d3) => {
|
|
209139
|
-
for (const e of
|
|
209838
|
+
for (const e of fs67.readdirSync(d3, { withFileTypes: true })) {
|
|
209140
209839
|
if (e.isDirectory()) {
|
|
209141
209840
|
if (e.name === "_inferred")
|
|
209142
209841
|
continue;
|
|
209143
209842
|
walk20(path72.join(d3, e.name));
|
|
209144
209843
|
} else if (e.name.endsWith(".tc")) {
|
|
209145
209844
|
const abs = path72.join(d3, e.name);
|
|
209146
|
-
const src =
|
|
209845
|
+
const src = fs67.readFileSync(abs, "utf-8");
|
|
209147
209846
|
try {
|
|
209148
209847
|
const file = parser_ohm_exports.parseTcFile(path72.relative(dir, abs), src);
|
|
209149
209848
|
for (const key4 of resolver_exports.resolve([file]).index.keys()) {
|
|
@@ -209316,7 +210015,7 @@ async function withContracts(repoRoot5, options, tracker, fn) {
|
|
|
209316
210015
|
try {
|
|
209317
210016
|
let recorded;
|
|
209318
210017
|
if (options.contractsDir) {
|
|
209319
|
-
if (!
|
|
210018
|
+
if (!fs67.existsSync(options.contractsDir)) {
|
|
209320
210019
|
const err = new Error(`Contracts directory not found at ${options.contractsDir}. Run \`truecourse contracts generate\` first.`);
|
|
209321
210020
|
tracker?.error("load", err.message);
|
|
209322
210021
|
throw err;
|
|
@@ -209405,7 +210104,7 @@ async function verifyInProcess(repoRoot5, options = {}) {
|
|
|
209405
210104
|
bySeverity: summary.bySeverity
|
|
209406
210105
|
});
|
|
209407
210106
|
await deleteVerifyDiff(storeKey);
|
|
209408
|
-
|
|
210107
|
+
fs67.rmSync(legacyVerifyStatePath(repoRoot5), { force: true });
|
|
209409
210108
|
}
|
|
209410
210109
|
const state = {
|
|
209411
210110
|
verifiedAt,
|
|
@@ -209623,7 +210322,7 @@ async function persistInferred(repoRoot5, options, contractsDir, codeDir, starte
|
|
|
209623
210322
|
}
|
|
209624
210323
|
function autodetectCodeDir(repoRoot5) {
|
|
209625
210324
|
const codeSubdir = path72.join(repoRoot5, "code");
|
|
209626
|
-
if (
|
|
210325
|
+
if (fs67.existsSync(codeSubdir) && fs67.statSync(codeSubdir).isDirectory()) {
|
|
209627
210326
|
return codeSubdir;
|
|
209628
210327
|
}
|
|
209629
210328
|
return repoRoot5;
|
|
@@ -209944,7 +210643,7 @@ async function runContractsGenerate(options = {}) {
|
|
|
209944
210643
|
async function runContractsList(options = {}) {
|
|
209945
210644
|
const repoRoot5 = options.cwd ?? process.cwd();
|
|
209946
210645
|
const contractsDir = path73.join(repoRoot5, ".truecourse", "contracts");
|
|
209947
|
-
if (!
|
|
210646
|
+
if (!fs68.existsSync(contractsDir)) {
|
|
209948
210647
|
O2.info("No contracts found. Run `truecourse contracts generate` first.");
|
|
209949
210648
|
return;
|
|
209950
210649
|
}
|
|
@@ -209952,12 +210651,12 @@ async function runContractsList(options = {}) {
|
|
|
209952
210651
|
const fileNodes = [];
|
|
209953
210652
|
let parseErrors = 0;
|
|
209954
210653
|
const visit = (dir) => {
|
|
209955
|
-
for (const entry of
|
|
210654
|
+
for (const entry of fs68.readdirSync(dir, { withFileTypes: true })) {
|
|
209956
210655
|
const full = path73.join(dir, entry.name);
|
|
209957
210656
|
if (entry.isDirectory()) visit(full);
|
|
209958
210657
|
else if (entry.isFile() && entry.name.endsWith(".tc")) {
|
|
209959
210658
|
try {
|
|
209960
|
-
fileNodes.push(parserOhm.parseTcFile(full,
|
|
210659
|
+
fileNodes.push(parserOhm.parseTcFile(full, fs68.readFileSync(full, "utf-8")));
|
|
209961
210660
|
} catch {
|
|
209962
210661
|
parseErrors += 1;
|
|
209963
210662
|
}
|
|
@@ -209997,7 +210696,7 @@ async function runContractsList(options = {}) {
|
|
|
209997
210696
|
async function runContractsValidate(options = {}) {
|
|
209998
210697
|
const repoRoot5 = options.cwd ?? process.cwd();
|
|
209999
210698
|
const contractsDir = path73.join(repoRoot5, ".truecourse", "contracts");
|
|
210000
|
-
if (!
|
|
210699
|
+
if (!fs68.existsSync(contractsDir)) {
|
|
210001
210700
|
O2.error("No .truecourse/contracts/ directory found.");
|
|
210002
210701
|
process.exit(1);
|
|
210003
210702
|
}
|
|
@@ -210005,12 +210704,12 @@ async function runContractsValidate(options = {}) {
|
|
|
210005
210704
|
const fileNodes = [];
|
|
210006
210705
|
const issues = [];
|
|
210007
210706
|
const visit = (dir) => {
|
|
210008
|
-
for (const entry of
|
|
210707
|
+
for (const entry of fs68.readdirSync(dir, { withFileTypes: true })) {
|
|
210009
210708
|
const full = path73.join(dir, entry.name);
|
|
210010
210709
|
if (entry.isDirectory()) visit(full);
|
|
210011
210710
|
else if (entry.isFile() && entry.name.endsWith(".tc")) {
|
|
210012
210711
|
try {
|
|
210013
|
-
fileNodes.push(parserOhm.parseTcFile(full,
|
|
210712
|
+
fileNodes.push(parserOhm.parseTcFile(full, fs68.readFileSync(full, "utf-8")));
|
|
210014
210713
|
} catch (e) {
|
|
210015
210714
|
issues.push(`${path73.relative(repoRoot5, full)}: parse error: ${e instanceof Error ? e.message : e}`);
|
|
210016
210715
|
}
|
|
@@ -210253,7 +210952,7 @@ async function runInfer(opts = {}) {
|
|
|
210253
210952
|
|
|
210254
210953
|
// tools/cli/src/commands/spec-conflicts.ts
|
|
210255
210954
|
init_dist4();
|
|
210256
|
-
import
|
|
210955
|
+
import fs69 from "node:fs";
|
|
210257
210956
|
import path75 from "node:path";
|
|
210258
210957
|
var root = (opts) => opts.cwd ?? process.cwd();
|
|
210259
210958
|
var base = (ref) => ref.split("/").pop() ?? ref;
|
|
@@ -210301,7 +211000,7 @@ async function runSpecConflictsList(opts = {}) {
|
|
|
210301
211000
|
function excerpt(repoRoot5, ref, note, max = 20) {
|
|
210302
211001
|
let text4;
|
|
210303
211002
|
try {
|
|
210304
|
-
text4 =
|
|
211003
|
+
text4 = fs69.readFileSync(path75.join(repoRoot5, ref), "utf-8");
|
|
210305
211004
|
} catch {
|
|
210306
211005
|
return ` (could not read ${ref})`;
|
|
210307
211006
|
}
|
|
@@ -211249,7 +211948,7 @@ async function runConfigLlmShow(options = {}) {
|
|
|
211249
211948
|
|
|
211250
211949
|
// tools/cli/src/commands/hooks.ts
|
|
211251
211950
|
import { execSync as execSync4 } from "node:child_process";
|
|
211252
|
-
import
|
|
211951
|
+
import fs70 from "node:fs";
|
|
211253
211952
|
import path79 from "node:path";
|
|
211254
211953
|
init_dist4();
|
|
211255
211954
|
init_paths();
|
|
@@ -211285,11 +211984,11 @@ function findGitDir(from) {
|
|
|
211285
211984
|
let dir = from;
|
|
211286
211985
|
while (true) {
|
|
211287
211986
|
const gitPath = path79.join(dir, ".git");
|
|
211288
|
-
if (
|
|
211289
|
-
const stat =
|
|
211987
|
+
if (fs70.existsSync(gitPath)) {
|
|
211988
|
+
const stat = fs70.statSync(gitPath);
|
|
211290
211989
|
if (stat.isDirectory()) return gitPath;
|
|
211291
211990
|
if (stat.isFile()) {
|
|
211292
|
-
const content =
|
|
211991
|
+
const content = fs70.readFileSync(gitPath, "utf-8").trim();
|
|
211293
211992
|
const match4 = content.match(/^gitdir:\s*(.+)$/);
|
|
211294
211993
|
if (match4) return path79.resolve(dir, match4[1]);
|
|
211295
211994
|
}
|
|
@@ -211302,7 +212001,7 @@ function findGitDir(from) {
|
|
|
211302
212001
|
function findProjectRoot(from) {
|
|
211303
212002
|
let dir = from;
|
|
211304
212003
|
while (true) {
|
|
211305
|
-
if (
|
|
212004
|
+
if (fs70.existsSync(path79.join(dir, ".git"))) return dir;
|
|
211306
212005
|
const parent = path79.dirname(dir);
|
|
211307
212006
|
if (parent === dir) return null;
|
|
211308
212007
|
dir = parent;
|
|
@@ -211310,10 +212009,10 @@ function findProjectRoot(from) {
|
|
|
211310
212009
|
}
|
|
211311
212010
|
function loadConfig(projectRoot) {
|
|
211312
212011
|
const configPath = path79.join(projectRoot, ".truecourse", "hooks.yaml");
|
|
211313
|
-
if (!
|
|
212012
|
+
if (!fs70.existsSync(configPath)) return null;
|
|
211314
212013
|
let parsed;
|
|
211315
212014
|
try {
|
|
211316
|
-
const raw =
|
|
212015
|
+
const raw = fs70.readFileSync(configPath, "utf-8");
|
|
211317
212016
|
parsed = jsYaml.load(raw) || {};
|
|
211318
212017
|
} catch (err) {
|
|
211319
212018
|
console.error(`Error parsing ${configPath}: ${err.message}`);
|
|
@@ -211365,10 +212064,10 @@ async function runHooksInstall() {
|
|
|
211365
212064
|
console.log(INSTALL_WARNING);
|
|
211366
212065
|
}
|
|
211367
212066
|
const hooksDir = path79.join(gitDir, "hooks");
|
|
211368
|
-
|
|
212067
|
+
fs70.mkdirSync(hooksDir, { recursive: true });
|
|
211369
212068
|
const hookPath = path79.join(hooksDir, "pre-commit");
|
|
211370
|
-
if (
|
|
211371
|
-
const existing =
|
|
212069
|
+
if (fs70.existsSync(hookPath)) {
|
|
212070
|
+
const existing = fs70.readFileSync(hookPath, "utf-8");
|
|
211372
212071
|
if (!existing.includes(HOOK_IDENTIFIER)) {
|
|
211373
212072
|
console.error(
|
|
211374
212073
|
"Error: A pre-commit hook already exists and was not installed by TrueCourse."
|
|
@@ -211378,16 +212077,16 @@ async function runHooksInstall() {
|
|
|
211378
212077
|
process.exit(1);
|
|
211379
212078
|
}
|
|
211380
212079
|
}
|
|
211381
|
-
|
|
212080
|
+
fs70.writeFileSync(hookPath, HOOK_SCRIPT, { mode: 493 });
|
|
211382
212081
|
console.log("TrueCourse pre-commit hook installed.");
|
|
211383
212082
|
console.log(` ${hookPath}`);
|
|
211384
212083
|
const projectRoot = findProjectRoot(process.cwd());
|
|
211385
212084
|
if (projectRoot) {
|
|
211386
212085
|
const cfgDir = path79.join(projectRoot, ".truecourse");
|
|
211387
212086
|
const cfgPath = path79.join(cfgDir, "hooks.yaml");
|
|
211388
|
-
if (!
|
|
211389
|
-
|
|
211390
|
-
|
|
212087
|
+
if (!fs70.existsSync(cfgPath)) {
|
|
212088
|
+
fs70.mkdirSync(cfgDir, { recursive: true });
|
|
212089
|
+
fs70.writeFileSync(cfgPath, HOOKS_YAML_TEMPLATE);
|
|
211391
212090
|
console.log(` ${cfgPath} (starter config \u2014 edit to customize, commit to share with the team)`);
|
|
211392
212091
|
}
|
|
211393
212092
|
}
|
|
@@ -211399,16 +212098,16 @@ function runHooksUninstall() {
|
|
|
211399
212098
|
process.exit(1);
|
|
211400
212099
|
}
|
|
211401
212100
|
const hookPath = path79.join(gitDir, "hooks", "pre-commit");
|
|
211402
|
-
if (!
|
|
212101
|
+
if (!fs70.existsSync(hookPath)) {
|
|
211403
212102
|
console.log("No pre-commit hook installed.");
|
|
211404
212103
|
return;
|
|
211405
212104
|
}
|
|
211406
|
-
const content =
|
|
212105
|
+
const content = fs70.readFileSync(hookPath, "utf-8");
|
|
211407
212106
|
if (!content.includes(HOOK_IDENTIFIER)) {
|
|
211408
212107
|
console.error("Error: The pre-commit hook was not installed by TrueCourse. Leaving it in place.");
|
|
211409
212108
|
process.exit(1);
|
|
211410
212109
|
}
|
|
211411
|
-
|
|
212110
|
+
fs70.unlinkSync(hookPath);
|
|
211412
212111
|
console.log("TrueCourse pre-commit hook removed.");
|
|
211413
212112
|
}
|
|
211414
212113
|
function runHooksStatus() {
|
|
@@ -211418,7 +212117,7 @@ function runHooksStatus() {
|
|
|
211418
212117
|
process.exit(1);
|
|
211419
212118
|
}
|
|
211420
212119
|
const hookPath = path79.join(gitDir, "hooks", "pre-commit");
|
|
211421
|
-
const installed =
|
|
212120
|
+
const installed = fs70.existsSync(hookPath) && fs70.readFileSync(hookPath, "utf-8").includes(HOOK_IDENTIFIER);
|
|
211422
212121
|
if (installed) {
|
|
211423
212122
|
console.log("TrueCourse pre-commit hook: installed");
|
|
211424
212123
|
console.log(` ${hookPath}`);
|
|
@@ -211527,7 +212226,13 @@ async function runHooksRun() {
|
|
|
211527
212226
|
|
|
211528
212227
|
// tools/cli/src/index.ts
|
|
211529
212228
|
var program2 = new Command();
|
|
211530
|
-
program2.name("truecourse").version("0.7.0-next.
|
|
212229
|
+
program2.name("truecourse").version("0.7.0-next.5").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
|
|
212230
|
+
function warnDiscontinued(command) {
|
|
212231
|
+
process.stderr.write(
|
|
212232
|
+
`\u26A0 \`${command}\` is discontinued in favor of \`truecourse guard\` \u2014 see the README. Planned removal: 0.8.
|
|
212233
|
+
`
|
|
212234
|
+
);
|
|
212235
|
+
}
|
|
211531
212236
|
var dashboardCmd = program2.command("dashboard").description("Start the TrueCourse dashboard and open it in your browser").option("--reconfigure", "Re-prompt for console vs background service mode").option("--service", "Run as a background service (skips mode prompt)").option("--console", "Run in this terminal (skips mode prompt)").action(async (options) => {
|
|
211532
212237
|
if (options.service && options.console) {
|
|
211533
212238
|
console.error("error: --service and --console are mutually exclusive");
|
|
@@ -211581,14 +212286,17 @@ program2.command("list").description("List violations from the latest analysis")
|
|
|
211581
212286
|
});
|
|
211582
212287
|
}
|
|
211583
212288
|
});
|
|
211584
|
-
var contractsCmd = program2.command("contracts").description("Manage spec-driven contract artifacts");
|
|
212289
|
+
var contractsCmd = program2.command("contracts", { hidden: true }).description("Manage spec-driven contract artifacts");
|
|
211585
212290
|
contractsCmd.command("generate").description("Generate .tc artifacts from the curated corpus (corpus.json)").option("--diff", "Dry run \u2014 show what would change without writing").option("-y, --yes", "Skip the pre-flight LLM cost-estimate confirmation").option("--llm-transport <mode>", "How to reach the LLM: 'cli' (spawn claude -p, default) or 'agent' (filesystem mailbox)").option("--io <dir>", "Mailbox dir for --llm-transport agent (request/response files)").action(async (options) => {
|
|
212291
|
+
warnDiscontinued("contracts");
|
|
211586
212292
|
await runContractsGenerate({ diff: !!options.diff, yes: !!options.yes, llm: options.llmTransport, io: options.io });
|
|
211587
212293
|
});
|
|
211588
212294
|
contractsCmd.command("list").description("List the .tc artifacts in this repo (kind \xB7 identity \xB7 location)").option("--inferred", "Only inferred artifacts (reverse-engineered, in _inferred/)").option("--authored", "Only authored artifacts (exclude _inferred/)").action(async (options) => {
|
|
212295
|
+
warnDiscontinued("contracts");
|
|
211589
212296
|
await runContractsList({ inferred: !!options.inferred, authored: !!options.authored });
|
|
211590
212297
|
});
|
|
211591
212298
|
contractsCmd.command("validate").description("Parse and resolve all .tc files, report any issues").action(async () => {
|
|
212299
|
+
warnDiscontinued("contracts");
|
|
211592
212300
|
await runContractsValidate();
|
|
211593
212301
|
});
|
|
211594
212302
|
var specCmd = program2.command("spec").description("Curate scattered docs into a corpus of areas and doc relations");
|
|
@@ -211652,17 +212360,20 @@ docsCmd.command("exclude <path...>").description("Force-exclude one or more kept
|
|
|
211652
212360
|
docsCmd.command("unexclude <path>").description("Remove a force-exclude override").action(async (docPath) => {
|
|
211653
212361
|
await runSpecDocsUnexclude(docPath);
|
|
211654
212362
|
});
|
|
211655
|
-
program2.command("verify").description("Compare code against the canonical TC contracts").option("--code-dir <path>", "Override the code directory (default: auto-detect)").option("--diff", "Diff current drifts against the committed LATEST baseline").option("--stash", "Pre-approve stashing pending changes (verify committed state)").option("--no-stash", "Verify the working tree as-is without stashing").action(async (options) => {
|
|
212363
|
+
program2.command("verify", { hidden: true }).description("Compare code against the canonical TC contracts").option("--code-dir <path>", "Override the code directory (default: auto-detect)").option("--diff", "Diff current drifts against the committed LATEST baseline").option("--stash", "Pre-approve stashing pending changes (verify committed state)").option("--no-stash", "Verify the working tree as-is without stashing").action(async (options) => {
|
|
212364
|
+
warnDiscontinued("verify");
|
|
211656
212365
|
await runVerify({ codeDir: options.codeDir, diff: options.diff, stash: options.stash });
|
|
211657
212366
|
});
|
|
211658
|
-
program2.command("infer").description("Reverse-engineer undocumented decisions from code into inferred contracts").option("--code-dir <path>", "Override the code directory (default: auto-detect)").option("--dry-run", "Report what would be written without touching disk").action(async (options) => {
|
|
212367
|
+
program2.command("infer", { hidden: true }).description("Reverse-engineer undocumented decisions from code into inferred contracts").option("--code-dir <path>", "Override the code directory (default: auto-detect)").option("--dry-run", "Report what would be written without touching disk").action(async (options) => {
|
|
212368
|
+
warnDiscontinued("infer");
|
|
211659
212369
|
await runInfer({ codeDir: options.codeDir, dryRun: options.dryRun });
|
|
211660
212370
|
});
|
|
211661
|
-
var driftsCmd = program2.command("drifts").description("Inspect drifts from the latest verify");
|
|
212371
|
+
var driftsCmd = program2.command("drifts", { hidden: true }).description("Inspect drifts from the latest verify");
|
|
211662
212372
|
driftsCmd.command("list").description("List drifts from the latest verify (paginated)").option("--limit <n>", "Number of drifts to show (default: 20)", parseInt).option("--offset <n>", "Skip first N drifts", parseInt).option("--all", "Show all drifts").option(
|
|
211663
212373
|
"--severity <list>",
|
|
211664
212374
|
"Comma-separated severities to include (critical,high,medium,low,info)"
|
|
211665
212375
|
).action(async (options) => {
|
|
212376
|
+
warnDiscontinued("drifts");
|
|
211666
212377
|
await runDriftsList({
|
|
211667
212378
|
limit: options.all ? Infinity : options.limit ?? 20,
|
|
211668
212379
|
offset: options.offset ?? 0,
|