Skip to content

Commit d4eb362

Browse files
committed
Source generator for ConfigurationsKeys2 (temporary) to replace ConfigurationsKeys.cs later
1 parent 9501463 commit d4eb362

File tree

82 files changed

+9124
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+9124
-1
lines changed

tracer/src/Datadog.Trace.SourceGenerators/Configuration/ConfigurationKeysGenerator.cs

Lines changed: 553 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
// <copyright file="JsonReader.cs" company="Datadog">
2+
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
4+
// </copyright>
5+
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Text;
9+
10+
namespace Datadog.Trace.SourceGenerators.Configuration;
11+
12+
/// <summary>
13+
/// Json reader as we can't really use vendored libraries here, for framework compatibility reasons
14+
/// </summary>
15+
internal static class JsonReader
16+
{
17+
internal static string ExtractJsonObjectSection(string json, string sectionName)
18+
{
19+
var searchPattern = $"\"{sectionName}\":";
20+
var startIndex = json.IndexOf(searchPattern, StringComparison.Ordinal);
21+
if (startIndex == -1)
22+
{
23+
return string.Empty;
24+
}
25+
26+
// Move to the start of the object value
27+
startIndex += searchPattern.Length;
28+
29+
// Skip whitespace to find the opening brace
30+
while (startIndex < json.Length && char.IsWhiteSpace(json[startIndex]))
31+
{
32+
startIndex++;
33+
}
34+
35+
if (startIndex >= json.Length || json[startIndex] != '{')
36+
{
37+
return string.Empty;
38+
}
39+
40+
// Find the matching closing brace
41+
var braceCount = 0;
42+
var endIndex = startIndex;
43+
var inString = false;
44+
var escapeNext = false;
45+
46+
for (int i = startIndex; i < json.Length; i++)
47+
{
48+
var ch = json[i];
49+
50+
if (escapeNext)
51+
{
52+
escapeNext = false;
53+
continue;
54+
}
55+
56+
if (ch == '\\')
57+
{
58+
escapeNext = true;
59+
continue;
60+
}
61+
62+
if (ch == '"')
63+
{
64+
inString = !inString;
65+
continue;
66+
}
67+
68+
if (!inString)
69+
{
70+
if (ch == '{')
71+
{
72+
braceCount++;
73+
}
74+
else if (ch == '}')
75+
{
76+
braceCount--;
77+
if (braceCount == 0)
78+
{
79+
endIndex = i;
80+
break;
81+
}
82+
}
83+
}
84+
}
85+
86+
if (braceCount != 0)
87+
{
88+
return string.Empty;
89+
}
90+
91+
return json.Substring(startIndex, endIndex - startIndex + 1);
92+
}
93+
94+
internal static Dictionary<string, string[]> ParseAliasesFromJson(string aliasesJson)
95+
{
96+
var aliases = new Dictionary<string, string[]>();
97+
var inString = false;
98+
var escapeNext = false;
99+
var currentToken = new StringBuilder();
100+
var currentKey = string.Empty;
101+
var currentAliases = new List<string>();
102+
var inArray = false;
103+
var collectingKey = true;
104+
105+
// Skip opening and closing braces
106+
for (int i = 1; i < aliasesJson.Length - 1; i++)
107+
{
108+
var ch = aliasesJson[i];
109+
110+
if (escapeNext)
111+
{
112+
if (inString)
113+
{
114+
currentToken.Append(ch);
115+
}
116+
117+
escapeNext = false;
118+
continue;
119+
}
120+
121+
if (ch == '\\')
122+
{
123+
if (inString)
124+
{
125+
currentToken.Append(ch);
126+
}
127+
128+
escapeNext = true;
129+
continue;
130+
}
131+
132+
if (ch == '"')
133+
{
134+
if (!inString)
135+
{
136+
// Start of string
137+
inString = true;
138+
currentToken.Clear();
139+
}
140+
else
141+
{
142+
// End of string
143+
inString = false;
144+
var tokenValue = currentToken.ToString();
145+
146+
if (collectingKey)
147+
{
148+
currentKey = tokenValue;
149+
collectingKey = false;
150+
}
151+
else if (inArray)
152+
{
153+
currentAliases.Add(tokenValue);
154+
}
155+
}
156+
157+
continue;
158+
}
159+
160+
if (inString)
161+
{
162+
currentToken.Append(ch);
163+
continue;
164+
}
165+
166+
// Handle structural characters outside of strings
167+
switch (ch)
168+
{
169+
case '[':
170+
inArray = true;
171+
currentAliases.Clear();
172+
break;
173+
174+
case ']':
175+
inArray = false;
176+
if (!string.IsNullOrEmpty(currentKey) && currentAliases.Count > 0)
177+
{
178+
aliases[currentKey] = currentAliases.ToArray();
179+
}
180+
181+
break;
182+
183+
case ',':
184+
if (!inArray)
185+
{
186+
// End of key-value pair, reset for next key
187+
collectingKey = true;
188+
currentKey = string.Empty;
189+
currentAliases.Clear();
190+
}
191+
192+
break;
193+
}
194+
}
195+
196+
return aliases;
197+
}
198+
}

tracer/src/Datadog.Trace.SourceGenerators/Constants.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// <copyright file="Constants.cs" company="Datadog">
1+
// <copyright file="Constants.cs" company="Datadog">
22
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
33
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
44
// </copyright>
@@ -20,5 +20,13 @@ internal static class Constants
2020
#nullable enable
2121
2222
23+
""";
24+
25+
public const string ConfigurationGeneratorComment =
26+
"""
27+
// This file is auto-generated from supported-configurations.json and supported-configurations-docs.yaml
28+
// Do not edit this file directly. The source generator will regenerate it on build.
29+
// NOTE: If you remove keys/products from the JSON, run 'dotnet clean' and remove old generated files.
30+
2331
""";
2432
}

tracer/src/Datadog.Trace.SourceGenerators/Helpers/TrackingNames.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,17 @@ internal class TrackingNames
3131
public const string AssemblyCallTargetDefinitionSource = nameof(AssemblyCallTargetDefinitionSource);
3232
public const string AdoNetCallTargetDefinitionSource = nameof(AdoNetCallTargetDefinitionSource);
3333
public const string AdoNetSignatures = nameof(AdoNetSignatures);
34+
35+
// Configuration key matcher
36+
public const string ConfigurationKeysParseConfiguration = nameof(ConfigurationKeysParseConfiguration);
37+
public const string ConfigurationKeyMatcherDiagnostics = nameof(ConfigurationKeyMatcherDiagnostics);
38+
public const string ConfigurationKeyMatcherValidData = nameof(ConfigurationKeyMatcherValidData);
39+
public const string ConfigurationKeysAdditionalText = nameof(ConfigurationKeysAdditionalText);
40+
41+
// Configuration key generator
42+
public const string ConfigurationKeysGenParseConfiguration = nameof(ConfigurationKeysGenParseConfiguration);
43+
public const string ConfigurationKeysGenContentExtracted = nameof(ConfigurationKeysGenContentExtracted);
44+
public const string ConfigurationKeysGenMatcherValidData = nameof(ConfigurationKeysGenMatcherValidData);
45+
public const string ConfigurationKeysGenAdditionalText = nameof(ConfigurationKeysGenAdditionalText);
46+
public const string ConfigurationKeysGenYamlAdditionalText = nameof(ConfigurationKeysGenYamlAdditionalText);
3447
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// <copyright file="YamlReader.cs" company="Datadog">
2+
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
4+
// </copyright>
5+
6+
using System.Collections.Generic;
7+
using System.Text;
8+
9+
namespace Datadog.Trace.SourceGenerators.Helpers
10+
{
11+
/// <summary>
12+
/// Simple YAML parser for reading documentation strings from YAML files.
13+
/// Supports basic YAML features needed for configuration documentation.
14+
/// </summary>
15+
internal static class YamlReader
16+
{
17+
/// <summary>
18+
/// Parses a YAML file containing configuration key documentation.
19+
/// Expects format: KEY: | followed by multi-line documentation
20+
/// </summary>
21+
public static Dictionary<string, string> ParseDocumentation(string yamlContent)
22+
{
23+
var result = new Dictionary<string, string>();
24+
var lines = yamlContent.Replace("\r\n", "\n").Split('\n');
25+
26+
string? currentKey = null;
27+
var currentDoc = new StringBuilder();
28+
var inMultiLine = false;
29+
var baseIndent = 0;
30+
31+
for (int i = 0; i < lines.Length; i++)
32+
{
33+
var line = lines[i];
34+
35+
// Skip empty lines and comments when not in multi-line
36+
if (!inMultiLine && (string.IsNullOrWhiteSpace(line) || line.TrimStart().StartsWith("#")))
37+
{
38+
continue;
39+
}
40+
41+
// Check for new key (starts at column 0, contains colon)
42+
if (!inMultiLine && line.Length > 0 && line[0] != ' ' && line.Contains(":"))
43+
{
44+
// Save previous key if exists
45+
if (currentKey != null)
46+
{
47+
result[currentKey] = currentDoc.ToString().TrimEnd();
48+
currentDoc.Clear();
49+
}
50+
51+
var colonIndex = line.IndexOf(':');
52+
currentKey = line.Substring(0, colonIndex).Trim();
53+
54+
// Check if it's a multi-line string (|)
55+
var afterColon = line.Substring(colonIndex + 1).Trim();
56+
if (afterColon == "|" || afterColon == ">")
57+
{
58+
inMultiLine = true;
59+
baseIndent = -1; // Will be set on first content line
60+
}
61+
else if (!string.IsNullOrEmpty(afterColon))
62+
{
63+
// Single line value
64+
currentDoc.Append(afterColon);
65+
result[currentKey] = currentDoc.ToString();
66+
currentDoc.Clear();
67+
currentKey = null;
68+
}
69+
70+
continue;
71+
}
72+
73+
// Handle multi-line content
74+
if (inMultiLine && currentKey != null)
75+
{
76+
// Check if we've reached the next key (no indentation)
77+
if (line.Length > 0 && line[0] != ' ' && line.Contains(":"))
78+
{
79+
// Save current key and process this line as new key
80+
result[currentKey] = currentDoc.ToString().TrimEnd();
81+
currentDoc.Clear();
82+
inMultiLine = false;
83+
84+
var colonIndex = line.IndexOf(':');
85+
currentKey = line.Substring(0, colonIndex).Trim();
86+
var afterColon = line.Substring(colonIndex + 1).Trim();
87+
if (afterColon == "|" || afterColon == ">")
88+
{
89+
inMultiLine = true;
90+
baseIndent = -1;
91+
}
92+
93+
continue;
94+
}
95+
96+
// Determine base indentation from first content line
97+
if (baseIndent == -1 && line.Length > 0 && line[0] == ' ')
98+
{
99+
baseIndent = 0;
100+
while (baseIndent < line.Length && line[baseIndent] == ' ')
101+
{
102+
baseIndent++;
103+
}
104+
}
105+
106+
// Add content line (remove base indentation)
107+
if (line.Length > 0)
108+
{
109+
var contentStart = 0;
110+
while (contentStart < line.Length && contentStart < baseIndent && line[contentStart] == ' ')
111+
{
112+
contentStart++;
113+
}
114+
115+
if (currentDoc.Length > 0)
116+
{
117+
currentDoc.AppendLine();
118+
}
119+
120+
currentDoc.Append(line.Substring(contentStart));
121+
}
122+
else
123+
{
124+
// Empty line in multi-line content
125+
if (currentDoc.Length > 0)
126+
{
127+
currentDoc.AppendLine();
128+
}
129+
}
130+
}
131+
}
132+
133+
// Save last key
134+
if (currentKey != null)
135+
{
136+
result[currentKey] = currentDoc.ToString().TrimEnd();
137+
}
138+
139+
return result;
140+
}
141+
}
142+
}

0 commit comments

Comments
 (0)