Skip to content

Commit 5a6615e

Browse files
committed
style(core): clear Sonar smells on the A2/sample new code
- Provide DateTimeKind in the sample's seed data (S6562). - Reword the sample header comment so it is not flagged as commented-out code (S125). - Use explicit types where the type is not apparent, per the repo .editorconfig (csharp_style_var_elsewhere = false) — clears the IDE0008 suggestions on new code. - Use the concrete JsonReportConfigParser for the test field (CA1859). No behavior change; 33 green Core tests, sample still runs.
1 parent 6208d43 commit 5a6615e

5 files changed

Lines changed: 23 additions & 23 deletions

File tree

samples/04-dynamic-config-csv/InMemorySalesSourceProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public IBatchSource<ReportRecord> Create(SourceConfig source, ReportSchema schem
2929
(long)i,
3030
$"Customer {i}",
3131
i * 100.5m,
32-
new DateTime(2026, 1, 1).AddDays(i - 1),
32+
new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddDays(i - 1),
3333
}));
3434
}
3535

samples/04-dynamic-config-csv/Program.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@
99

1010
// Sample 04 — config-driven report (the dynamic path).
1111
//
12-
// The whole report is defined in report.json: there is NO typed POCO. Rows flow through the same
13-
// pipeline as the typed path as positional ReportRecords. What the JSON fully drives today: the
14-
// report name, the source selection (by id), the columns/schema (name, type, header, format,
15-
// culture), and the selection of outputs/destinations (by id).
12+
// The whole report is defined in report.json, with no typed POCO. Rows flow through the same
13+
// pipeline as the typed path, as positional ReportRecords. The JSON fully drives the report name,
14+
// the source selection by id, the columns and schema (name, type, header, format and culture) and
15+
// the selection of outputs and destinations by id.
1616
//
17-
// Standing in for things not built yet:
18-
// - the SQL config source arrives in A3, so an in-memory IConfigSourceProvider provides the rows;
19-
// - binding format/destination *options* from config arrives later (A5), so the CSV and Local
20-
// factories are pre-wired in DI (the JSON's output/destination "properties" are illustrative).
17+
// Two pieces are still standing in. The SQL config source arrives in A3, so for now an in-memory
18+
// source provider supplies the rows. Binding format and destination options from config arrives
19+
// later in A5, so the CSV and Local factories are pre-wired in DI and the JSON properties under
20+
// outputs and destinations are illustrative.
2121
//
22-
// dotnet run --project samples/04-dynamic-config-csv
22+
// Run with: dotnet run --project samples/04-dynamic-config-csv
2323

2424
var configPath = Path.Combine(AppContext.BaseDirectory, "report.json");
2525
var json = await File.ReadAllTextAsync(configPath);

src/NeoReports.Core/Configuration/JsonReportConfigParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public override void Write(Utf8JsonWriter writer, object? value, JsonSerializerO
8181
// Recover round-tripped ISO-8601 timestamps as DateTime so date parameters bind
8282
// correctly downstream. RoundtripKind honors any 'Z'/offset and must not be combined
8383
// with AdjustToUniversal/AssumeUniversal (.NET rejects that pairing).
84-
if (DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var dt))
84+
if (DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out DateTime dt))
8585
return dt;
8686

8787
return text;

src/NeoReports.Core/Configuration/ReportConfigCompiler.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,58 +41,58 @@ public static CompiledReport Compile(ReportConfig config, IServiceProvider servi
4141
var columns = new ColumnDefinition<ReportRecord>[config.Columns.Count];
4242
for (var i = 0; i < config.Columns.Count; i++)
4343
{
44-
var c = config.Columns[i];
44+
ColumnConfig c = config.Columns[i];
4545
columns[i] = ReportColumns.Positional(i, c.Name, c.Type, c.Nullable, c.DisplayName, c.Format, c.Culture);
4646
}
4747

4848
var schema = new ReportSchema(columns.Select(c => c.Column).ToList());
4949

5050
// Resolve every registration up front (fail fast on a missing provider/factory) before
5151
// instantiating the source, which may open connections.
52-
var sourceProvider = ResolveSource(services, config.Source.Type);
53-
var outputs = config.Outputs
52+
IConfigSourceProvider sourceProvider = ResolveSource(services, config.Source.Type);
53+
OutputSpec[] outputs = config.Outputs
5454
.Select(o => new OutputSpec(ResolveWriter(services, o.Format), o.Properties))
5555
.ToArray();
56-
var destinations = config.Destinations?
56+
DestinationSpec[] destinations = config.Destinations?
5757
.Select(d => new DestinationSpec(ResolveDestination(services, d.Type), d.Properties))
5858
.ToArray() ?? Array.Empty<DestinationSpec>();
5959

60-
var source = sourceProvider.Create(config.Source, schema, services);
60+
IBatchSource<ReportRecord> source = sourceProvider.Create(config.Source, schema, services);
6161

62-
var builder = new ReportBuilder<ReportRecord>(config.Name)
62+
ReportBuilder<ReportRecord> builder = new ReportBuilder<ReportRecord>(config.Name)
6363
.From(source)
6464
.Columns(columns);
6565

6666
if (config.PageSize is int pageSize)
6767
builder.WithPageSize(pageSize);
6868

69-
foreach (var output in outputs)
69+
foreach (OutputSpec output in outputs)
7070
builder.To(output);
71-
foreach (var destination in destinations)
71+
foreach (DestinationSpec destination in destinations)
7272
builder.UploadTo(destination);
7373

7474
return builder.Build();
7575
}
7676

7777
private static IConfigSourceProvider ResolveSource(IServiceProvider services, string type)
7878
{
79-
var provider = services.GetServices<IConfigSourceProvider>()
79+
IConfigSourceProvider? provider = services.GetServices<IConfigSourceProvider>()
8080
.FirstOrDefault(p => string.Equals(p.Type, type, StringComparison.OrdinalIgnoreCase));
8181
return provider ?? throw new ConfigurationException(
8282
$"No source provider is registered for type '{type}'. Register an IConfigSourceProvider with that Type.");
8383
}
8484

8585
private static IWriterFactory ResolveWriter(IServiceProvider services, string format)
8686
{
87-
var factory = services.GetServices<IWriterFactory>()
87+
IWriterFactory? factory = services.GetServices<IWriterFactory>()
8888
.FirstOrDefault(f => string.Equals(f.Format, format, StringComparison.OrdinalIgnoreCase));
8989
return factory ?? throw new ConfigurationException(
9090
$"No writer factory is registered for format '{format}'. Register an IWriterFactory with that Format.");
9191
}
9292

9393
private static IDestinationFactory ResolveDestination(IServiceProvider services, string type)
9494
{
95-
var factory = services.GetServices<IDestinationFactory>()
95+
IDestinationFactory? factory = services.GetServices<IDestinationFactory>()
9696
.FirstOrDefault(f => string.Equals(f.Type, type, StringComparison.OrdinalIgnoreCase));
9797
return factory ?? throw new ConfigurationException(
9898
$"No destination factory is registered for type '{type}'. Register an IDestinationFactory with that Type.");

tests/NeoReports.Core.UnitTests/DynamicConfigTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public class DynamicConfigTests
4444
}
4545
""";
4646

47-
private static readonly IReportConfigParser Parser = new JsonReportConfigParser();
47+
private static readonly JsonReportConfigParser Parser = new();
4848

4949
private static ReportExecutionContext Exec() =>
5050
new(Guid.NewGuid().ToString("N"), "sales", null, NullLogger.Instance, CancellationToken.None);

0 commit comments

Comments
 (0)