diff options
| author | Leitwolf11 | 2026-10-29 12:42:13 +0300 |
|---|---|---|
| committer | Leitwolf11 | 2026-10-29 12:42:13 +0300 |
| commit | 285e1024da64234b30b0fa425ffd6bf348119db4 (patch) | |
| tree | 9801dc805a397052264cc5bc0a6c56cf870b179a /apps/api | |
| parent | 3d1c6d52b830d201a68b0440a8a81c13b74c8b92 (diff) | |
| download | progmaweb-285e1024da64234b30b0fa425ffd6bf348119db4.tar.gz | |
Document the ViGet API in full and take zod 4.6.7 for eslint
The documentation check of the backend found the private members of
ViGet/ without a summary and no page for its namespace:
- Summaries for every field and helper method of the catalog, the
descriptor, the properties reader, publishing and the endpoints.
- docs/api/namespaces/Progmasoft.Progmaweb.Api.ViGet.md describes the
namespace.
- The two regular expressions of TazelPluginDescriptor are excluded from the
reference like AccountNamePolicy.CanonicalPattern: the generator replaces
their comment with its own.
The dependency audit found GHSA for zod < 4.6.6, which can exhaust memory
while validating oversized constrained collections. Only
eslint-plugin-react-hooks reaches it, and it accepts any zod 4, so an
override takes 4.6.7 until the plugin resolves a fixed release itself.
pnpm audit --audit-level high finds nothing.
Diffstat (limited to 'apps/api')
| -rw-r--r-- | apps/api/ViGet/JavaProperties.cs | 6 | ||||
| -rw-r--r-- | apps/api/ViGet/PostgresTazelPluginCatalog.cs | 19 | ||||
| -rw-r--r-- | apps/api/ViGet/TazelPluginCatalog.cs | 2 | ||||
| -rw-r--r-- | apps/api/ViGet/TazelPluginDescriptor.cs | 4 | ||||
| -rw-r--r-- | apps/api/ViGet/TazelPluginPublishing.cs | 3 | ||||
| -rw-r--r-- | apps/api/ViGet/ViGetEndpoints.cs | 6 | ||||
| -rw-r--r-- | apps/api/ViGet/ViGetRegistration.cs | 1 |
7 files changed, 41 insertions, 0 deletions
diff --git a/apps/api/ViGet/JavaProperties.cs b/apps/api/ViGet/JavaProperties.cs index e55991e..1b42f20 100644 --- a/apps/api/ViGet/JavaProperties.cs +++ b/apps/api/ViGet/JavaProperties.cs @@ -93,10 +93,16 @@ internal static class JavaProperties } } + /// <summary>Whether a character is white space of the format: space, tab or form feed.</summary> private static bool IsBlank(char character) => character is ' ' or '\t' or '\f'; + /// <summary>Whether an unescaped character ends a key.</summary> private static bool IsKeyEnd(char character) => character is '=' or ':' || IsBlank(character); + /// <summary>Resolves the escapes of a key or a value.</summary> + /// <param name="text">The text as the file writes it.</param> + /// <returns>The text it stands for.</returns> + /// <exception cref="FormatException">A <c>\u</c> escape is not followed by four hexadecimal digits.</exception> private static string Unescape(string text) { StringBuilder result = new(text.Length); diff --git a/apps/api/ViGet/PostgresTazelPluginCatalog.cs b/apps/api/ViGet/PostgresTazelPluginCatalog.cs index 07fa86f..9ae20b0 100644 --- a/apps/api/ViGet/PostgresTazelPluginCatalog.cs +++ b/apps/api/ViGet/PostgresTazelPluginCatalog.cs @@ -15,6 +15,7 @@ internal static class ViGetSchema /// <summary>Key of the advisory lock that lets one process at a time change these tables.</summary> private const long MigrationLockKey = 0x5669476574; + /// <summary>The steps, in order. The version of a step is its position, counted from one.</summary> private static readonly string[] Steps = [ // 1: Tazel plugins and their versions. @@ -101,6 +102,12 @@ internal static class ViGetSchema return taken; } + /// <summary>Runs statements that return nothing.</summary> + /// <param name="connection">The connection to run them on.</param> + /// <param name="transaction">The transaction they belong to.</param> + /// <param name="sql">The statements.</param> + /// <param name="cancellationToken">Cancels the operation.</param> + /// <returns>A task that completes when the statements have run.</returns> private static async Task ExecuteAsync( NpgsqlConnection connection, NpgsqlTransaction transaction, @@ -116,6 +123,7 @@ internal static class ViGetSchema /// <param name="dataSource">Connections to the database of the accounts.</param> internal sealed class PostgresTazelPluginCatalog(NpgsqlDataSource dataSource) : ITazelPluginCatalog { + /// <summary>The columns of a plugin row, in the order <see cref="ReadPlugin"/> reads them.</summary> private const string PluginColumns = "publisher, name, description, authors, license, homepage, repository"; /// <inheritdoc/> @@ -265,6 +273,10 @@ internal sealed class PostgresTazelPluginCatalog(NpgsqlDataSource dataSource) : return await command.ExecuteNonQueryAsync(cancellationToken) == 1; } + /// <summary>A plugin from a row of <see cref="PluginColumns"/>.</summary> + /// <param name="reader">A reader on the row.</param> + /// <param name="versions">The versions of the plugin.</param> + /// <returns>The plugin.</returns> private static TazelPlugin ReadPlugin(NpgsqlDataReader reader, IReadOnlyList<TazelPluginVersion> versions) => new( reader.GetString(0), reader.GetString(1), @@ -275,6 +287,13 @@ internal sealed class PostgresTazelPluginCatalog(NpgsqlDataSource dataSource) : reader.IsDBNull(6) ? null : reader.GetString(6), versions); + /// <summary>The versions of a plugin, newest publication first.</summary> + /// <param name="connection">The connection to read on.</param> + /// <param name="transaction">The transaction to read in, if any.</param> + /// <param name="publisher">The publisher of the plugin.</param> + /// <param name="name">The name of the plugin.</param> + /// <param name="cancellationToken">Cancels the operation.</param> + /// <returns>The versions.</returns> private static async Task<IReadOnlyList<TazelPluginVersion>> VersionsAsync( NpgsqlConnection connection, NpgsqlTransaction? transaction, diff --git a/apps/api/ViGet/TazelPluginCatalog.cs b/apps/api/ViGet/TazelPluginCatalog.cs index e6fa2e9..ea7ff7a 100644 --- a/apps/api/ViGet/TazelPluginCatalog.cs +++ b/apps/api/ViGet/TazelPluginCatalog.cs @@ -85,7 +85,9 @@ internal interface ITazelPluginCatalog /// <summary>A catalog that lives as long as the process, for development and tests.</summary> internal sealed class InMemoryTazelPluginCatalog : ITazelPluginCatalog { + /// <summary>Guards <see cref="plugins"/>.</summary> private readonly Lock gate = new(); + /// <summary>The plugins by their exact publisher and name.</summary> private readonly Dictionary<(string Publisher, string Name), TazelPlugin> plugins = []; /// <inheritdoc/> diff --git a/apps/api/ViGet/TazelPluginDescriptor.cs b/apps/api/ViGet/TazelPluginDescriptor.cs index eddd541..7495e46 100644 --- a/apps/api/ViGet/TazelPluginDescriptor.cs +++ b/apps/api/ViGet/TazelPluginDescriptor.cs @@ -126,9 +126,13 @@ internal sealed partial record TazelPluginDescriptor( return null; } + /// <summary>One identifier: a letter or <c>_</c>, then letters, digits or <c>_</c>.</summary> + /// <returns>The compiled expression.</returns> [GeneratedRegex("^[A-Za-z_][A-Za-z0-9_]*$")] private static partial Regex IdentifierPattern(); + /// <summary>An exact semantic version without leading zeros or build metadata, as Tazel accepts it.</summary> + /// <returns>The compiled expression.</returns> [GeneratedRegex(@"^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:-[0-9A-Za-z.-]+)?$")] private static partial Regex VersionPattern(); } diff --git a/apps/api/ViGet/TazelPluginPublishing.cs b/apps/api/ViGet/TazelPluginPublishing.cs index 625e55d..02c1d6b 100644 --- a/apps/api/ViGet/TazelPluginPublishing.cs +++ b/apps/api/ViGet/TazelPluginPublishing.cs @@ -144,5 +144,8 @@ internal sealed class TazelPluginPublishing( return true; } + /// <summary>The result of a refused publication.</summary> + /// <param name="error">Why it was refused.</param> + /// <returns>The result.</returns> private static PublishResult Refused(string error) => new(null, error); } diff --git a/apps/api/ViGet/ViGetEndpoints.cs b/apps/api/ViGet/ViGetEndpoints.cs index 4e2337f..00f6dc4 100644 --- a/apps/api/ViGet/ViGetEndpoints.cs +++ b/apps/api/ViGet/ViGetEndpoints.cs @@ -96,6 +96,12 @@ internal static class ViGetEndpoints }); } + /// <summary>A plugin of the catalog, or <see langword="null"/> when a route value is not an identifier.</summary> + /// <param name="catalog">The catalog.</param> + /// <param name="publisher">The publisher from the route.</param> + /// <param name="name">The name from the route.</param> + /// <param name="cancellationToken">Cancels the operation.</param> + /// <returns>The plugin, if there is one.</returns> private static ValueTask<TazelPlugin?> FindAsync( ITazelPluginCatalog catalog, string publisher, diff --git a/apps/api/ViGet/ViGetRegistration.cs b/apps/api/ViGet/ViGetRegistration.cs index bb2bf6f..42da18e 100644 --- a/apps/api/ViGet/ViGetRegistration.cs +++ b/apps/api/ViGet/ViGetRegistration.cs @@ -40,6 +40,7 @@ internal sealed class ViGetSchemaInitializer( NpgsqlDataSource dataSource, ILogger<ViGetSchemaInitializer> logger) : IHostedService { + /// <summary>Writes the schema version and the number of steps taken at this start.</summary> private static readonly Action<ILogger, int, int, Exception?> SchemaReport = LoggerMessage.Define<int, int>( LogLevel.Information, new EventId(1, "ViGetSchema"), |