@@ -15291,6 +15291,75 @@ public void Extract_Dockerfile_JsonFormsIgnorePayloadsBeyondParserDepthLimit(str
1529115291 Assert.Empty(symbols);
1529215292 }
1529315293
15294+ [Fact]
15295+ public void Extract_Dockerfile_JsonVolumeCapsArrayItems()
15296+ {
15297+ var maxItems = SymbolExtractor.DockerfileJsonFormMaxItems;
15298+ var items = Enumerable.Range(0, maxItems)
15299+ .Select(i => $"/vol{i}")
15300+ .Concat(["/too-many"]);
15301+ var content = "VOLUME [" + string.Join(", ", items.Select(item => JsonSerializer.Serialize(item))) + "]\n";
15302+
15303+ var symbols = SymbolExtractor.Extract(1, "dockerfile", content);
15304+
15305+ Assert.Equal(maxItems, symbols.Count);
15306+ Assert.Contains(symbols, s => s.Kind == "property" && s.Name == "/vol0");
15307+ Assert.Contains(symbols, s => s.Kind == "property" && s.Name == "/vol" + (maxItems - 1));
15308+ Assert.DoesNotContain(symbols, s => s.Kind == "property" && s.Name == "/too-many");
15309+ }
15310+
15311+ [Fact]
15312+ public void Extract_Dockerfile_JsonVolumeSkipsOverlongStrings()
15313+ {
15314+ var tooLong = "/" + new string('v', SymbolExtractor.DockerfileJsonFormMaxStringLength);
15315+ var content = "VOLUME [" + JsonSerializer.Serialize(tooLong) + ", \"/ok\"]\n";
15316+
15317+ var symbols = SymbolExtractor.Extract(1, "dockerfile", content);
15318+
15319+ Assert.Contains(symbols, s => s.Kind == "property" && s.Name == "/ok");
15320+ Assert.DoesNotContain(symbols, s => s.Kind == "property" && s.Name == tooLong);
15321+ Assert.Single(symbols);
15322+ }
15323+
15324+ [Fact]
15325+ public void Extract_Dockerfile_JsonShellSkipsOverlongExecutable()
15326+ {
15327+ var tooLong = "/" + new string('s', SymbolExtractor.DockerfileJsonFormMaxStringLength);
15328+ var content = "SHELL [" + JsonSerializer.Serialize(tooLong) + ", \"-c\"]\n";
15329+
15330+ var symbols = SymbolExtractor.Extract(1, "dockerfile", content);
15331+
15332+ Assert.Empty(symbols);
15333+ }
15334+
15335+ [Theory]
15336+ [InlineData("COPY")]
15337+ [InlineData("ADD")]
15338+ public void Extract_Dockerfile_JsonCopyAddSkipOverlongDestinations(string instruction)
15339+ {
15340+ var tooLong = "/" + new string('d', SymbolExtractor.DockerfileJsonFormMaxStringLength);
15341+ var content = instruction + " [\"source\", " + JsonSerializer.Serialize(tooLong) + "]\n";
15342+
15343+ var symbols = SymbolExtractor.Extract(1, "dockerfile", content);
15344+
15345+ Assert.Empty(symbols);
15346+ }
15347+
15348+ [Theory]
15349+ [InlineData("COPY")]
15350+ [InlineData("ADD")]
15351+ public void Extract_Dockerfile_JsonCopyAddSkipArraysBeyondItemBudget(string instruction)
15352+ {
15353+ var maxItems = SymbolExtractor.DockerfileJsonFormMaxItems;
15354+ var items = Enumerable.Range(0, maxItems + 1)
15355+ .Select(i => $"/src{i}");
15356+ var content = instruction + " [" + string.Join(", ", items.Select(item => JsonSerializer.Serialize(item))) + "]\n";
15357+
15358+ var symbols = SymbolExtractor.Extract(1, "dockerfile", content);
15359+
15360+ Assert.Empty(symbols);
15361+ }
15362+
1529415363 [Fact]
1529515364 public void Extract_Dockerfile_DetectsOnbuildCopyDestinationPathSymbols()
1529615365 {
@@ -18269,6 +18338,59 @@ public void Extract_TypeScript_ExcessiveTsconfigPathAliasTargetsTruncatesWithWar
1826918338 }
1827018339 }
1827118340
18341+ [Fact]
18342+ public void Extract_TypeScript_ExcessiveTsconfigPathAliasTotalTargetsTruncatesWithWarning()
18343+ {
18344+ var projectRoot = TestProjectHelper.CreateTempProject("tsconfig_alias_total_targets_symbols");
18345+ try
18346+ {
18347+ var maxTargetsPerRule = GetSymbolExtractorIntConstant("MaxTypeScriptPathAliasTargetsPerRule");
18348+ var maxTotalTargets = GetSymbolExtractorIntConstant("MaxTypeScriptPathAliasTotalTargets");
18349+ var paths = new StringBuilder();
18350+ var remainingTargets = maxTotalTargets;
18351+ var rule = 0;
18352+ while (remainingTargets > 0)
18353+ {
18354+ if (paths.Length > 0)
18355+ paths.Append(',');
18356+
18357+ var targetsForRule = Math.Min(maxTargetsPerRule, remainingTargets);
18358+ paths.Append('"').Append("@skip").Append(rule).Append("/*").Append("\":[");
18359+ for (var target = 0; target < targetsForRule; target++)
18360+ {
18361+ if (target > 0)
18362+ paths.Append(',');
18363+ paths.Append('"').Append("missing").Append(rule).Append('_').Append(target).Append("/*").Append('"');
18364+ }
18365+
18366+ paths.Append(']');
18367+ remainingTargets -= targetsForRule;
18368+ rule++;
18369+ }
18370+
18371+ paths.Append(",\"@hit/*\":[\"src/*\"]");
18372+
18373+ WriteFile(
18374+ projectRoot,
18375+ "tsconfig.json",
18376+ "{\"compilerOptions\":{\"baseUrl\":\".\",\"paths\":{" + paths + "}}}");
18377+ WriteFile(projectRoot, "src/Button.ts", "export const Button = 1;\n");
18378+ var sourcePath = WriteFile(projectRoot, "src/main.ts", "import { Button } from \"@hit/Button\";\n");
18379+
18380+ List<SymbolRecord> symbols = [];
18381+ var stderr = ConsoleCapture.CaptureError(() =>
18382+ symbols = SymbolExtractor.Extract(1, "typescript", File.ReadAllText(sourcePath), sourcePath));
18383+
18384+ Assert.Contains(symbols, s => s.Kind == "import" && s.Name == "@hit/Button");
18385+ Assert.DoesNotContain(symbols, s => s.Kind == "import" && s.Name == "src/Button.ts");
18386+ Assert.Contains("Truncated TypeScript path alias targets", stderr, StringComparison.Ordinal);
18387+ }
18388+ finally
18389+ {
18390+ TestProjectHelper.DeleteDirectory(projectRoot);
18391+ }
18392+ }
18393+
1827218394 [Fact]
1827318395 public void Extract_TypeScript_OverlongTsconfigPathAliasStringsAreIgnoredWithBoundedWarning()
1827418396 {
0 commit comments