Skip to content

Commit e849f22

Browse files
Various Fixes
1 parent 7e8ba4f commit e849f22

File tree

10 files changed

+88
-22
lines changed

10 files changed

+88
-22
lines changed

THIRD_PARTY_NOTICES.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
22

33
This product incorporates components from the projects listed below. The original
44
copyright notices and the licenses under which Dyalog Ltd. received such components
5-
are set forth below. Dyalog Ltd. licenses these components to you under the terms
6-
described in this file; Dyalog Ltd. reserves all other rights not expressly granted.
5+
are set forth below. These components are licensed to you under their respective
6+
licenses as set below. Dyalog Ltd. reserves all other rights not expressly granted.
77

88
=======================================================================
99

mkdocs.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ extra_javascript:
2222

2323
extra:
2424
generator: false
25+
version_maj: 20
26+
version_min: 0
27+
version_majmin: 20.0
28+
version_condensed: 200
2529

2630
nav:
2731
- Home: index.md

src/OpenAPIDyalog/Constants/GeneratorConstants.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ public static class GeneratorConstants
1717
public const string VersionTemplate = "APLSource/Version.aplf.scriban";
1818
public const string ReadmeTemplate = "README.md.scriban";
1919
public const string ModelTemplate = "APLSource/models/model.aplc.scriban";
20-
public const string HttpCommandResource = "APLSource/HttpCommand.aplc";
20+
public const string HttpCommandResource = "APLSource/HttpCommand.aplc";
21+
public const string ThirdPartyNoticesResource = "OpenAPIDyalog.THIRD_PARTY_NOTICES.txt";
2122

2223
// ── Content types ─────────────────────────────────────────────────────────
2324
public const string ContentTypeJson = "application/json";

src/OpenAPIDyalog/GeneratorApplication.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Reflection;
12
using Microsoft.Extensions.Logging;
23
using OpenAPIDyalog.Constants;
34
using OpenAPIDyalog.Models;
@@ -12,6 +13,18 @@ public static class GeneratorApplication
1213
{
1314
public static async Task<int> RunAsync(string[] args)
1415
{
16+
if (args.Contains("--help") || args.Contains("-h"))
17+
{
18+
DisplayUsage();
19+
return 0;
20+
}
21+
22+
if (args.Contains("--third-party-notices"))
23+
{
24+
DisplayThirdPartyNotices();
25+
return 0;
26+
}
27+
1528
if (args.Length == 0)
1629
{
1730
DisplayUsage();
@@ -147,6 +160,15 @@ public static async Task<int> RunAsync(string[] args)
147160
};
148161
}
149162

163+
private static void DisplayThirdPartyNotices()
164+
{
165+
using var stream = Assembly.GetExecutingAssembly()
166+
.GetManifestResourceStream(GeneratorConstants.ThirdPartyNoticesResource)
167+
?? throw new InvalidOperationException("Third-party notices resource not found. This is a build defect.");
168+
using var reader = new StreamReader(stream);
169+
Console.Write(reader.ReadToEnd());
170+
}
171+
150172
// DisplayUsage is UI output, not a logging concern — Console.WriteLine is intentional.
151173
private static void DisplayUsage()
152174
{
@@ -159,7 +181,9 @@ private static void DisplayUsage()
159181
Console.WriteLine(" [output-directory] Directory for generated files (default: ./generated)");
160182
Console.WriteLine();
161183
Console.WriteLine("Options:");
162-
Console.WriteLine(" --no-validation, -nv Disable OpenAPI specification validation rules");
184+
Console.WriteLine(" --help, -h Show this help message and exit");
185+
Console.WriteLine(" --no-validation, -nv Disable OpenAPI specification validation rules");
186+
Console.WriteLine(" --third-party-notices Print third-party software notices and exit");
163187
Console.WriteLine();
164188
Console.WriteLine("Examples:");
165189
Console.WriteLine(" OpenAPIDyalog openapispec.json");

src/OpenAPIDyalog/Models/TemplateContext.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Microsoft.OpenApi;
2+
using OpenAPIDyalog.Constants;
23

34
namespace OpenAPIDyalog.Models;
45

@@ -117,15 +118,24 @@ public IEnumerable<string> GetAllTags()
117118
{
118119
if (Paths == null) return Enumerable.Empty<string>();
119120

120-
return Paths.Values
121+
var operations = Paths.Values
121122
.Where(path => path.Operations != null)
122123
.SelectMany(path => path.Operations!.Values)
123-
.Where(op => op.Tags != null)
124+
.ToList();
125+
126+
var explicitTags = operations
127+
.Where(op => op.Tags is { Count: > 0 })
124128
.SelectMany(op => op.Tags!)
125129
.Select(tag => tag.Name)
126130
.Where(name => name != null)
127131
.Cast<string>()
128132
.Distinct();
133+
134+
var hasTaglessOperations = operations.Any(op => op.Tags == null || op.Tags.Count == 0);
135+
if (hasTaglessOperations)
136+
return explicitTags.Append(GeneratorConstants.DefaultTagName).Distinct();
137+
138+
return explicitTags;
129139
}
130140

131141
/// <summary>

src/OpenAPIDyalog/OpenAPIDyalog.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
<!-- Embed all templates into the assembly for single-file distribution -->
2424
<ItemGroup>
2525
<EmbeddedResource Include="Templates\**\*" />
26+
<EmbeddedResource Include="..\..\THIRD_PARTY_NOTICES.txt" LogicalName="OpenAPIDyalog.THIRD_PARTY_NOTICES.txt" />
2627
</ItemGroup>
2728

2829
</Project>

src/OpenAPIDyalog/Services/ArtifactGeneratorService.cs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,22 +51,36 @@ public async Task GenerateVersionAsync(OpenApiDocument document, string outputDi
5151
}
5252

5353
/// <summary>
54-
/// Copies the embedded HttpCommand.aplc binary resource to the output directory.
54+
/// Copies the embedded HttpCommand.aplc binary resource to the output directory,
55+
/// skipping the write if the existing file is already identical.
5556
/// </summary>
5657
public async Task CopyHttpCommandAsync(string outputDirectory)
5758
{
5859
var destPath = Path.Combine(outputDirectory, GeneratorConstants.AplSourceDir, "HttpCommand.aplc");
5960
Directory.CreateDirectory(Path.GetDirectoryName(destPath)!);
6061

61-
using var srcStream = _templateService.GetEmbeddedResourceStream(GeneratorConstants.HttpCommandResource);
62-
using var destStream = File.Create(destPath);
63-
await srcStream.CopyToAsync(destStream);
62+
using var srcStream = _templateService.GetEmbeddedResourceStream(GeneratorConstants.HttpCommandResource);
63+
using var memStream = new MemoryStream();
64+
await srcStream.CopyToAsync(memStream);
65+
var srcBytes = memStream.ToArray();
6466

67+
if (File.Exists(destPath))
68+
{
69+
var destBytes = await File.ReadAllBytesAsync(destPath);
70+
if (srcBytes.SequenceEqual(destBytes))
71+
{
72+
_logger.LogInformation("Unchanged: {AplSourceDir}/HttpCommand.aplc", GeneratorConstants.AplSourceDir);
73+
return;
74+
}
75+
}
76+
77+
await File.WriteAllBytesAsync(destPath, srcBytes);
6578
_logger.LogInformation("Copied: {AplSourceDir}/HttpCommand.aplc", GeneratorConstants.AplSourceDir);
6679
}
6780

6881
/// <summary>
69-
/// Copies the OpenAPI specification file to the output directory.
82+
/// Copies the OpenAPI specification file to the output directory,
83+
/// skipping the write if the existing file is already identical.
7084
/// </summary>
7185
/// <exception cref="IOException">Re-thrown after logging if the copy fails.</exception>
7286
public async Task CopySpecificationAsync(string sourcePath, string outputDirectory)
@@ -76,9 +90,20 @@ public async Task CopySpecificationAsync(string sourcePath, string outputDirecto
7690

7791
try
7892
{
79-
File.Copy(sourcePath, destPath, overwrite: true);
93+
var srcBytes = await File.ReadAllBytesAsync(sourcePath);
94+
95+
if (File.Exists(destPath))
96+
{
97+
var destBytes = await File.ReadAllBytesAsync(destPath);
98+
if (srcBytes.SequenceEqual(destBytes))
99+
{
100+
_logger.LogInformation("Unchanged: {FileName}", fileName);
101+
return;
102+
}
103+
}
104+
105+
await File.WriteAllBytesAsync(destPath, srcBytes);
80106
_logger.LogInformation("Copied: {FileName}", fileName);
81-
await Task.CompletedTask; // async for consistent caller pattern
82107
}
83108
catch (Exception ex)
84109
{

src/OpenAPIDyalog/Services/TemplateService.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public string Render(Template template, object context)
7171
try
7272
{
7373
var scriptObject = BuildScriptObject(context);
74-
var templateContext = new TemplateContext();
74+
var templateContext = new TemplateContext { LoopLimit = int.MaxValue };
7575
templateContext.PushGlobal(scriptObject);
7676
return template.Render(templateContext);
7777
}
@@ -89,7 +89,7 @@ public async Task<string> RenderAsync(Template template, object context)
8989
try
9090
{
9191
var scriptObject = BuildScriptObject(context);
92-
var templateContext = new TemplateContext();
92+
var templateContext = new TemplateContext { LoopLimit = int.MaxValue };
9393
templateContext.PushGlobal(scriptObject);
9494
return await template.RenderAsync(templateContext);
9595
}
@@ -109,7 +109,7 @@ public async Task<string> LoadAndRenderAsync(string templateName, object context
109109
}
110110

111111
/// <summary>
112-
/// Saves rendered output to a file.
112+
/// Saves rendered output to a file, skipping the write if the existing content is identical.
113113
/// </summary>
114114
public async Task SaveOutputAsync(string output, string outputPath)
115115
{
@@ -119,6 +119,9 @@ public async Task SaveOutputAsync(string output, string outputPath)
119119
Directory.CreateDirectory(directory);
120120
}
121121

122+
if (File.Exists(outputPath) && await File.ReadAllTextAsync(outputPath) == output)
123+
return;
124+
122125
await File.WriteAllTextAsync(outputPath, output);
123126
}
124127

src/OpenAPIDyalog/Templates/APLSource/Client.aplc.scriban

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
:Class {{ class_name ?? "Client" }}
2-
⍝ Generated on {{ generated_at | date.to_string "%Y-%m-%d %H:%M:%S" }} UTC
32
⍝ {{ title }} - Version {{ version }}
43
{{~ if description ~}}
54
{{ comment_lines description }}

src/OpenAPIDyalog/Templates/APLSource/utils.apln.scriban

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
:Namespace utils
2-
⍝ Generated on {{ generated_at | date.to_string "%Y-%m-%d %H:%M:%S" }} UTC
32
⍝ {{ title }} - Version {{ version }}
43
⍝ Utility functions for HTTP requests and parameter validation
54

@@ -98,12 +97,12 @@
9897

9998
10099

101-
isValidPathParam←{
100+
isValidPathParam←{
102101
⍝ True if argument is a character vector or a scalar number
103-
isChar←(0=10|⎕DR)⍵
102+
isChar←(1=≢⍴1∘/⍵)∧(0=10|⎕DR)⍵
104103
isScalarNum←(0=≢⍴⍵)∧2|⎕DR ⍵
105-
isCharisScalarNum
106-
}
104+
isCharisScalarNum
105+
}
107106

108107
base64←{⎕IO ⎕ML←0 1 ⍝ Base64 encoding and decoding as used in MIME.
109108

0 commit comments

Comments
 (0)