From 8013bfadd479051d52a688ccb5ef542cdca32cdb Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Sun, 14 Sep 2025 21:57:54 +0200 Subject: [PATCH 01/14] Upgraded project to target the newest Blazor.FileAPI version and removed all warnings from missing documentation. --- .EditorConfig | 98 +++++++++++++++++ ...r.FileSystem.WasmExample.Benchmarks.csproj | 4 +- ...trube.Blazor.FileSystem.WasmExample.csproj | 23 ++-- .../BaseJSWrapper.cs | 43 +++++--- .../Converters/BlobConverter.cs | 18 ---- .../FileSystemHandleKindConverter.cs | 27 +++++ .../Converters/WriteCommandTypeConverter.cs | 29 +++++ .../EnumDescriptionConverter.cs | 45 -------- .../Enums/FileSystemCreateWritableOptions.cs | 13 --- .../Enums/FileSystemHandleKind.cs | 16 ++- .../Enums/WriteCommandType.cs | 19 +++- .../Extensions/IJSRuntimeExtensions.cs | 7 +- .../IServiceCollectionExtensions.cs | 24 ++++- .../FileSystemDirectoryHandle.InProcess.cs | 54 +++++++--- .../FileSystemDirectoryHandle.cs | 100 +++++++++++++++--- .../FileSystemFileHandle.InProcess.cs | 41 +++++-- .../FileSystemFileHandle.cs | 56 ++++++++-- .../FileSystemHandle.InProcess.cs | 36 +++++-- .../FileSystemHandle.cs | 40 +++++-- .../FileSystemWritableFileStream.InProcess.cs | 31 ++++-- .../FileSystemWritableFileStream.cs | 80 ++++++++++++-- .../IFileSystemHandle.InProcess.cs | 11 +- .../IFileSystemHandle.cs | 29 +++-- .../IStorageManagerService.InProcess.cs | 6 +- .../IStorageManagerService.cs | 16 ++- .../KristofferStrube.Blazor.FileSystem.csproj | 5 +- .../FileSystemCreateWritableOptions.cs | 17 +++ .../Options/FileSystemGetDirectoryOptions.cs | 6 +- .../Options/FileSystemGetFileOptions.cs | 6 +- .../Options/FileSystemOptions.cs | 30 +++++- .../Options/FileSystemRemoveOptions.cs | 6 +- .../Options/WriteParams.cs | 47 ++++++-- .../StorageManagerService.InProcess.cs | 5 + .../StorageManagerService.cs | 28 +++-- 34 files changed, 782 insertions(+), 234 deletions(-) create mode 100644 .EditorConfig delete mode 100644 src/KristofferStrube.Blazor.FileSystem/Converters/BlobConverter.cs create mode 100644 src/KristofferStrube.Blazor.FileSystem/Converters/FileSystemHandleKindConverter.cs create mode 100644 src/KristofferStrube.Blazor.FileSystem/Converters/WriteCommandTypeConverter.cs delete mode 100644 src/KristofferStrube.Blazor.FileSystem/EnumDescriptionConverter.cs delete mode 100644 src/KristofferStrube.Blazor.FileSystem/Enums/FileSystemCreateWritableOptions.cs create mode 100644 src/KristofferStrube.Blazor.FileSystem/Options/FileSystemCreateWritableOptions.cs diff --git a/.EditorConfig b/.EditorConfig new file mode 100644 index 0000000..c7f704a --- /dev/null +++ b/.EditorConfig @@ -0,0 +1,98 @@ +[*] +# All files +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_property = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_event = false +dotnet_diagnostic.IDE0003.severity = warning +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true +dotnet_diagnostic.IDE0049.severity = suggestion +csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async +dotnet_diagnostic.IDE0036.severity = error +dotnet_style_require_accessibility_modifiers = always +dotnet_diagnostic.IDE0040.severity = warning +dotnet_style_readonly_field = true +dotnet_diagnostic.IDE0044.severity = error +csharp_prefer_static_local_function = true +dotnet_diagnostic.IDE0062.severity = warning +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_diagnostic.IDE0047.severity = warning +dotnet_diagnostic.IDE0048.severity = warning +dotnet_diagnostic.IDE0010.severity = error +dotnet_style_object_initializer = true +dotnet_diagnostic.IDE0017.severity = suggestion +csharp_style_inlined_variable_declaration = true +dotnet_diagnostic.IDE0018.severity = suggestion +dotnet_style_collection_initializer = true +dotnet_diagnostic.IDE0028.severity = warning +dotnet_style_prefer_auto_properties = true +dotnet_diagnostic.IDE0032.severity = suggestion +dotnet_style_explicit_tuple_names = true +dotnet_diagnostic.IDE0033.severity = warning +csharp_prefer_simple_default_expression = false +dotnet_diagnostic.IDE0034.severity = warning +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_diagnostic.IDE0037.severity = suggestion +csharp_style_prefer_local_over_anonymous_function = true +dotnet_diagnostic.IDE0039.severity = warning +csharp_style_deconstructed_variable_declaration = true +dotnet_diagnostic.IDE0042.severity = suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_diagnostic.IDE0045.severity = warning +dotnet_style_prefer_conditional_expression_over_return = true +dotnet_diagnostic.IDE0046.severity = warning +dotnet_style_prefer_compound_assignment = true +dotnet_diagnostic.IDE0054.severity = warning +dotnet_diagnostic.IDE0074.severity = warning +csharp_style_prefer_index_operator = true +dotnet_diagnostic.IDE0056.severity = warning +csharp_style_prefer_range_operator = true +dotnet_diagnostic.IDE0057.severity = warning +dotnet_diagnostic.IDE0070.severity = error +dotnet_style_prefer_simplified_interpolation = true +dotnet_diagnostic.IDE0071.severity = warning +dotnet_diagnostic.IDE0072.severity = error +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_diagnostic.IDE0075.severity = warning +dotnet_diagnostic.IDE0082.severity = error +csharp_style_implicit_object_creation_when_type_is_apparent = true +dotnet_diagnostic.IDE0090.severity = error +dotnet_diagnostic.IDE0180.severity = warning +csharp_style_namespace_declarations = file_scoped +dotnet_diagnostic.IDE0160.severity = error +dotnet_diagnostic.IDE0161.severity = error +csharp_style_throw_expression = true +dotnet_diagnostic.IDE0016.severity = warning +dotnet_style_coalesce_expression = true +dotnet_diagnostic.IDE0029.severity = warning +dotnet_diagnostic.IDE0030.severity = warning +dotnet_style_null_propagation = true +dotnet_diagnostic.IDE0031.severity = warning +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_diagnostic.IDE0041.severity = warning +csharp_style_prefer_null_check_over_type_check = true +dotnet_diagnostic.IDE0150.severity = warning +csharp_style_conditional_delegate_call = false +dotnet_diagnostic.IDE1005.severity = warning +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = true +csharp_style_var_elsewhere = false +dotnet_diagnostic.IDE0007.severity = warning +dotnet_diagnostic.IDE0008.severity = warning +dotnet_diagnostic.IDE0001.severity = error +dotnet_diagnostic.IDE0002.severity = error +dotnet_diagnostic.IDE0004.severity = error +dotnet_diagnostic.IDE0005.severity = error +dotnet_diagnostic.IDE0035.severity = warning +dotnet_diagnostic.IDE0051.severity = warning +dotnet_diagnostic.IDE0052.severity = warning +csharp_style_unused_value_expression_statement_preference = discard_variable +dotnet_diagnostic.IDE0058.severity = warning +csharp_style_unused_value_assignment_preference = discard_variable +dotnet_diagnostic.IDE0059.severity = warning +# Ignore namespace mismatch as this is a library +dotnet_diagnostic.IDE0130.severity = none +# We don't want to adopt primary constructors yet +dotnet_diagnostic.IDE0290.severity = none \ No newline at end of file diff --git a/samples/KristofferStrube.Blazor.FileSystem.WasmExample.Benchmarks/KristofferStrube.Blazor.FileSystem.WasmExample.Benchmarks.csproj b/samples/KristofferStrube.Blazor.FileSystem.WasmExample.Benchmarks/KristofferStrube.Blazor.FileSystem.WasmExample.Benchmarks.csproj index bb64c43..ce7b915 100644 --- a/samples/KristofferStrube.Blazor.FileSystem.WasmExample.Benchmarks/KristofferStrube.Blazor.FileSystem.WasmExample.Benchmarks.csproj +++ b/samples/KristofferStrube.Blazor.FileSystem.WasmExample.Benchmarks/KristofferStrube.Blazor.FileSystem.WasmExample.Benchmarks.csproj @@ -2,15 +2,13 @@ Exe - net7.0 + net8.0 enable enable - - diff --git a/samples/KristofferStrube.Blazor.FileSystem.WasmExample/KristofferStrube.Blazor.FileSystem.WasmExample.csproj b/samples/KristofferStrube.Blazor.FileSystem.WasmExample/KristofferStrube.Blazor.FileSystem.WasmExample.csproj index c95adbd..5257e2c 100644 --- a/samples/KristofferStrube.Blazor.FileSystem.WasmExample/KristofferStrube.Blazor.FileSystem.WasmExample.csproj +++ b/samples/KristofferStrube.Blazor.FileSystem.WasmExample/KristofferStrube.Blazor.FileSystem.WasmExample.csproj @@ -1,17 +1,17 @@  - net7.0 + net8.0 enable enable - - - - - + + + + + @@ -20,15 +20,4 @@ - - - true - PreserveNewest - - - true - PreserveNewest - - - diff --git a/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs b/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs index 1ca9cb0..8696ca3 100644 --- a/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs +++ b/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs @@ -1,29 +1,48 @@ using KristofferStrube.Blazor.FileSystem.Extensions; +using KristofferStrube.Blazor.WebIDL; using Microsoft.JSInterop; namespace KristofferStrube.Blazor.FileSystem; -public abstract class BaseJSWrapper : IAsyncDisposable +/// +/// Base class for wrapping objects in the Blazor.WebAudio library. +/// +[IJSWrapperConverter] +public abstract class BaseJSWrapper : IAsyncDisposable, IJSWrapper { + /// + /// A lazily evaluated task that gives access to helper methods. + /// protected readonly Lazy> helperTask; - protected readonly IJSRuntime jSRuntime; - protected readonly FileSystemOptions options; /// - /// Constructs a wrapper instance for an equivalent JS instance. + /// Options for where it will find the script file that it needs to make complex JSInterop. /// - /// An instance. - /// A JS reference to an existing JS instance that should be wrapped. - internal BaseJSWrapper(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) + public FileSystemOptions FileSystemOptions { get; set; } + + /// + public IJSRuntime JSRuntime { get; } + + /// + public IJSObjectReference JSReference { get; } + + /// + public bool DisposesJSReference { get; } + + /// + protected BaseJSWrapper(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) { - this.options = options; - helperTask = new(async () => await jSRuntime.GetHelperAsync(options)); + FileSystemOptions = fileSystemOptions; + helperTask = new(async () => await jSRuntime.GetHelperAsync(fileSystemOptions)); JSReference = jSReference; - this.jSRuntime = jSRuntime; + JSRuntime = jSRuntime; + DisposesJSReference = options.DisposesJSReference; } - public IJSObjectReference JSReference { get; } - + /// + /// Disposes the underlying js object reference. + /// + /// public async ValueTask DisposeAsync() { if (helperTask.IsValueCreated) diff --git a/src/KristofferStrube.Blazor.FileSystem/Converters/BlobConverter.cs b/src/KristofferStrube.Blazor.FileSystem/Converters/BlobConverter.cs deleted file mode 100644 index a478b85..0000000 --- a/src/KristofferStrube.Blazor.FileSystem/Converters/BlobConverter.cs +++ /dev/null @@ -1,18 +0,0 @@ -using KristofferStrube.Blazor.FileAPI; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace KristofferStrube.Blazor.FileSystem.Converters; - -internal class BlobConverter : JsonConverter -{ - public override Blob Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - throw new NotSupportedException("Does not support deserializing Blobs"); - } - - public override void Write(Utf8JsonWriter writer, Blob value, JsonSerializerOptions options) - { - JsonSerializer.Serialize(writer, value.JSReference, options); - } -} diff --git a/src/KristofferStrube.Blazor.FileSystem/Converters/FileSystemHandleKindConverter.cs b/src/KristofferStrube.Blazor.FileSystem/Converters/FileSystemHandleKindConverter.cs new file mode 100644 index 0000000..e73b41f --- /dev/null +++ b/src/KristofferStrube.Blazor.FileSystem/Converters/FileSystemHandleKindConverter.cs @@ -0,0 +1,27 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace KristofferStrube.Blazor.FileSystem.Converters; + +internal class FileSystemHandleKindConverter : JsonConverter +{ + public override FileSystemHandleKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return reader.GetString() switch + { + "file" => FileSystemHandleKind.File, + "directory" => FileSystemHandleKind.Directory, + var value => throw new ArgumentException($"Value '{value}' was not a valid {nameof(FileSystemHandleKind)}."), + }; + } + + public override void Write(Utf8JsonWriter writer, FileSystemHandleKind value, JsonSerializerOptions options) + { + writer.WriteStringValue(value switch + { + FileSystemHandleKind.File => "file", + FileSystemHandleKind.Directory => "directory", + _ => throw new ArgumentException($"Value '{value}' was not a valid {nameof(FileSystemHandleKind)}.") + }); + } +} diff --git a/src/KristofferStrube.Blazor.FileSystem/Converters/WriteCommandTypeConverter.cs b/src/KristofferStrube.Blazor.FileSystem/Converters/WriteCommandTypeConverter.cs new file mode 100644 index 0000000..0e3ca56 --- /dev/null +++ b/src/KristofferStrube.Blazor.FileSystem/Converters/WriteCommandTypeConverter.cs @@ -0,0 +1,29 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace KristofferStrube.Blazor.FileSystem.Converters; + +internal class WriteCommandTypeConverter : JsonConverter +{ + public override WriteCommandType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return reader.GetString() switch + { + "write" => WriteCommandType.Write, + "seek" => WriteCommandType.Seek, + "truncate" => WriteCommandType.Truncate, + var value => throw new ArgumentException($"Value '{value}' was not a valid {nameof(WriteCommandType)}."), + }; + } + + public override void Write(Utf8JsonWriter writer, WriteCommandType value, JsonSerializerOptions options) + { + writer.WriteStringValue(value switch + { + WriteCommandType.Write => "write", + WriteCommandType.Seek => "seek", + WriteCommandType.Truncate => "truncate", + _ => throw new ArgumentException($"Value '{value}' was not a valid {nameof(WriteCommandType)}.") + }); + } +} diff --git a/src/KristofferStrube.Blazor.FileSystem/EnumDescriptionConverter.cs b/src/KristofferStrube.Blazor.FileSystem/EnumDescriptionConverter.cs deleted file mode 100644 index d4d5e52..0000000 --- a/src/KristofferStrube.Blazor.FileSystem/EnumDescriptionConverter.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.ComponentModel; -using System.Reflection; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace KristofferStrube.Blazor.FileSystem; - -#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. -#pragma warning disable CS8603 // Possible null reference return. -#pragma warning disable CS8604 // Possible null reference argument. -#pragma warning disable CS8602 // Dereference of a possibly null reference. -internal class EnumDescriptionConverter : JsonConverter where T : IComparable, IFormattable, IConvertible -{ - public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - string jsonValue = reader.GetString(); - - foreach (FieldInfo? fi in typeToConvert.GetFields()) - { - DescriptionAttribute description = (DescriptionAttribute)fi.GetCustomAttribute(typeof(DescriptionAttribute), false); - - if (description != null) - { - if (description.Description == jsonValue) - { - return (T)fi.GetValue(null); - } - } - } - throw new JsonException($"string {jsonValue} was not found as a description in the enum {typeToConvert}"); - } - - public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) - { - FieldInfo fi = value.GetType().GetField(value.ToString()); - - DescriptionAttribute description = (DescriptionAttribute)fi.GetCustomAttribute(typeof(DescriptionAttribute), false); - - writer.WriteStringValue(description.Description); - } -} -#pragma warning restore CS8602 // Dereference of a possibly null reference. -#pragma warning restore CS8604 // Possible null reference argument. -#pragma warning restore CS8603 // Possible null reference return. -#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. \ No newline at end of file diff --git a/src/KristofferStrube.Blazor.FileSystem/Enums/FileSystemCreateWritableOptions.cs b/src/KristofferStrube.Blazor.FileSystem/Enums/FileSystemCreateWritableOptions.cs deleted file mode 100644 index 4c36300..0000000 --- a/src/KristofferStrube.Blazor.FileSystem/Enums/FileSystemCreateWritableOptions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Text.Json.Serialization; - -namespace KristofferStrube.Blazor.FileSystem; - -/// -/// FileSystemCreateWritableOptions browser specs -/// -public class FileSystemCreateWritableOptions -{ - [JsonPropertyName("keepExistingData")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool KeepExistingData { get; set; } -} diff --git a/src/KristofferStrube.Blazor.FileSystem/Enums/FileSystemHandleKind.cs b/src/KristofferStrube.Blazor.FileSystem/Enums/FileSystemHandleKind.cs index fed1140..d23f0f7 100644 --- a/src/KristofferStrube.Blazor.FileSystem/Enums/FileSystemHandleKind.cs +++ b/src/KristofferStrube.Blazor.FileSystem/Enums/FileSystemHandleKind.cs @@ -1,16 +1,22 @@ -using System.ComponentModel; +using KristofferStrube.Blazor.FileSystem.Converters; using System.Text.Json.Serialization; namespace KristofferStrube.Blazor.FileSystem; /// -/// FileSystemHandleKind browser specs +/// The kind of a . /// -[JsonConverter(typeof(EnumDescriptionConverter))] +/// See the API definition here. +[JsonConverter(typeof(FileSystemHandleKindConverter))] public enum FileSystemHandleKind { - [Description("file")] + /// + /// Used to describe that the entry is a file. + /// File, - [Description("directory")] + + /// + /// Used to describe that the entry is a directory. + /// Directory, } \ No newline at end of file diff --git a/src/KristofferStrube.Blazor.FileSystem/Enums/WriteCommandType.cs b/src/KristofferStrube.Blazor.FileSystem/Enums/WriteCommandType.cs index 68b8158..4922347 100644 --- a/src/KristofferStrube.Blazor.FileSystem/Enums/WriteCommandType.cs +++ b/src/KristofferStrube.Blazor.FileSystem/Enums/WriteCommandType.cs @@ -1,18 +1,31 @@ -using System.ComponentModel; +using KristofferStrube.Blazor.FileSystem.Converters; +using System.ComponentModel; using System.Text.Json.Serialization; namespace KristofferStrube.Blazor.FileSystem; /// -/// WriteCommandType browser specs +/// The different kinds ways you can write to a . /// -[JsonConverter(typeof(EnumDescriptionConverter))] +/// See the API definition here. +[JsonConverter(typeof(WriteCommandTypeConverter))] public enum WriteCommandType { + /// + /// With this command type you can write to a file stream. + /// [Description("write")] Write, + + /// + /// With this command type you can move the cursor inside a file stream. + /// [Description("seek")] Seek, + + /// + /// With this command type you can truncate the size of the file that the file stream points to. + /// [Description("truncate")] Truncate, } diff --git a/src/KristofferStrube.Blazor.FileSystem/Extensions/IJSRuntimeExtensions.cs b/src/KristofferStrube.Blazor.FileSystem/Extensions/IJSRuntimeExtensions.cs index 226774f..c51ee7b 100644 --- a/src/KristofferStrube.Blazor.FileSystem/Extensions/IJSRuntimeExtensions.cs +++ b/src/KristofferStrube.Blazor.FileSystem/Extensions/IJSRuntimeExtensions.cs @@ -16,11 +16,6 @@ internal static async Task GetInProcessHelperAsync( private static async Task GetHelperAsync(IJSRuntime jSRuntime, FileSystemOptions options) { - return await jSRuntime.InvokeAsync("import", GetScriptPath(options)); - } - - private static string GetScriptPath(FileSystemOptions options) - { - return options.FullScriptPath; + return await jSRuntime.InvokeAsync("import", options.FullScriptPath); } } diff --git a/src/KristofferStrube.Blazor.FileSystem/Extensions/IServiceCollectionExtensions.cs b/src/KristofferStrube.Blazor.FileSystem/Extensions/IServiceCollectionExtensions.cs index bff61c3..07d4fcc 100644 --- a/src/KristofferStrube.Blazor.FileSystem/Extensions/IServiceCollectionExtensions.cs +++ b/src/KristofferStrube.Blazor.FileSystem/Extensions/IServiceCollectionExtensions.cs @@ -2,13 +2,25 @@ namespace KristofferStrube.Blazor.FileSystem; +/// +/// Extensions for adding and to the service collection. +/// public static class IServiceCollectionExtensions { + /// + /// Adds a to the service collection. + /// + /// The service collection to add the service to. public static IServiceCollection AddStorageManagerService(this IServiceCollection serviceCollection) { return AddStorageManagerService(serviceCollection, null); } + /// + /// Adds a to the service collection with the option to configure where the helper JS module is located. + /// + /// The service collection to add the service to. + /// An action to configure the that defines where the helper JS module is located. public static IServiceCollection AddStorageManagerService(this IServiceCollection serviceCollection, Action? configure) { ConfigureFsOptions(serviceCollection, configure); @@ -16,11 +28,20 @@ public static IServiceCollection AddStorageManagerService(this IServiceCollectio return serviceCollection.AddScoped(); } + /// + /// Adds a to the service collection. + /// + /// The service collection to add the service to. public static IServiceCollection AddStorageManagerServiceInProcess(this IServiceCollection serviceCollection) { return AddStorageManagerServiceInProcess(serviceCollection, null); } + /// + /// Adds a to the service collection with the option to configure where the helper JS module is located. + /// + /// The service collection to add the service to. + /// An action to configure the that defines where the helper JS module is located. public static IServiceCollection AddStorageManagerServiceInProcess(this IServiceCollection serviceCollection, Action? configure) { ConfigureFsOptions(serviceCollection, configure); @@ -38,8 +59,7 @@ private static void ConfigureFsOptions(IServiceCollection services, Action -/// FileSystemDirectoryHandle browser specs +/// An in-process version of a that represents a directory. /// -public class FileSystemDirectoryHandleInProcess : FileSystemDirectoryHandle, IFileSystemHandleInProcess +/// See the API definition here. +[IJSWrapperConverter] +public class FileSystemDirectoryHandleInProcess : FileSystemDirectoryHandle, IFileSystemHandleInProcess, IJSInProcessCreatable { - public new IJSInProcessObjectReference JSReference; + /// + public new IJSInProcessObjectReference JSReference { get; set; } + + /// + /// A lazily evaluated task that gives access to helper methods. + /// protected readonly IJSInProcessObjectReference inProcessHelper; + /// public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference) { - return await CreateAsync(jSRuntime, jSReference, FileSystemOptions.DefaultInstance); + return await CreateAsync(jSRuntime, jSReference, new CreationOptions()); + } + + /// + public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, CreationOptions options) + { + IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(FileSystemOptions.DefaultInstance); + return new FileSystemDirectoryHandleInProcess(jSRuntime, inProcessHelper, jSReference, FileSystemOptions.DefaultInstance, options); } + /// public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions options) { IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(options); - return new FileSystemDirectoryHandleInProcess(jSRuntime, inProcessHelper, jSReference, options); + return new FileSystemDirectoryHandleInProcess(jSRuntime, inProcessHelper, jSReference, options, new() { DisposesJSReference = true }); } - internal FileSystemDirectoryHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, FileSystemOptions options) : base(jSRuntime, jSReference, options) + /// + protected FileSystemDirectoryHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) : base(jSRuntime, jSReference, fileSystemOptions, options) { this.inProcessHelper = inProcessHelper; JSReference = jSReference; } + /// public FileSystemHandleKind Kind => inProcessHelper.Invoke("getAttribute", JSReference, "kind"); + /// public string Name => inProcessHelper.Invoke("getAttribute", JSReference, "name"); + /// public new async Task ValuesAsync() { IJSObjectReference helper = await helperTask.Value; @@ -43,28 +65,30 @@ internal FileSystemDirectoryHandleInProcess(IJSRuntime jSRuntime, IJSInProcessOb .Range(0, length) .Select>(async i => { - var fileSystemHandle = await FileSystemHandleInProcess.CreateAsync( - jSRuntime, + FileSystemHandleInProcess fileSystemHandle = await FileSystemHandleInProcess.CreateAsync( + JSRuntime, await jSEntries.InvokeAsync("at", i), - options); + FileSystemOptions); return (fileSystemHandle.Kind is FileSystemHandleKind.File) - ? await FileSystemFileHandleInProcess.CreateAsync(jSRuntime, fileSystemHandle.JSReference, options) - : await FileSystemDirectoryHandleInProcess.CreateAsync(jSRuntime, fileSystemHandle.JSReference, options); + ? await FileSystemFileHandleInProcess.CreateAsync(JSRuntime, fileSystemHandle.JSReference, FileSystemOptions) + : await FileSystemDirectoryHandleInProcess.CreateAsync(JSRuntime, fileSystemHandle.JSReference, FileSystemOptions); } ) .ToArray() ); } + /// public new async Task GetFileHandleAsync(string name, FileSystemGetFileOptions? options = null) { IJSInProcessObjectReference jSFileSystemFileHandle = await JSReference.InvokeAsync("getFileHandle", name, options); - return new FileSystemFileHandleInProcess(jSRuntime, inProcessHelper, jSFileSystemFileHandle, this.options); + return await FileSystemFileHandleInProcess.CreateAsync(JSRuntime, jSFileSystemFileHandle, FileSystemOptions); } + /// public new async Task GetDirectoryHandleAsync(string name, FileSystemGetDirectoryOptions? options = null) { - IJSInProcessObjectReference jSFileSystemDirectoryHandle = await JSReference.InvokeAsync("getDirectoryHandle", name, options); - return new FileSystemDirectoryHandleInProcess(jSRuntime, inProcessHelper, jSFileSystemDirectoryHandle, this.options); + IJSInProcessObjectReference jSFileSystemFileHandle = await JSReference.InvokeAsync("getDirectoryHandle", name, options); + return await CreateAsync(JSRuntime, jSFileSystemFileHandle, FileSystemOptions); } } diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.cs index 46dc96f..72ff4be 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.cs @@ -1,24 +1,53 @@ -using Microsoft.JSInterop; +using KristofferStrube.Blazor.WebIDL; +using Microsoft.JSInterop; namespace KristofferStrube.Blazor.FileSystem; /// -/// FileSystemDirectoryHandle browser specs +/// A that represents a directory. /// -public class FileSystemDirectoryHandle : FileSystemHandle +/// See the API definition here. +[IJSWrapperConverter] +public class FileSystemDirectoryHandle : FileSystemHandle, IJSCreatable { + /// + public static new async Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference) + { + return await CreateAsync(jSRuntime, jSReference); + } + + /// + public static new Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, CreationOptions options) + { + return Task.FromResult(new FileSystemDirectoryHandle(jSRuntime, jSReference, FileSystemOptions.DefaultInstance, options)); + } + + /// + public static new Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) + { + return Task.FromResult(new FileSystemDirectoryHandle(jSRuntime, jSReference, options, new() { DisposesJSReference = true })); + } + + /// + [Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")] public static new FileSystemDirectoryHandle Create(IJSRuntime jSRuntime, IJSObjectReference jSReference) { return Create(jSRuntime, jSReference, FileSystemOptions.DefaultInstance); } + /// + [Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")] public static new FileSystemDirectoryHandle Create(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) { - return new(jSRuntime, jSReference, options); + return new(jSRuntime, jSReference, options, new()); } - internal FileSystemDirectoryHandle(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) : base(jSRuntime, jSReference, options) { } + /// + protected FileSystemDirectoryHandle(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) : base(jSRuntime, jSReference, fileSystemOptions, options) { } + /// + /// Gets all s in the directory. + /// public async Task ValuesAsync() { IJSObjectReference helper = await helperTask.Value; @@ -30,36 +59,83 @@ public async Task ValuesAsync() .Range(0, length) .Select>(async i => { - var fileSystemHandle = new FileSystemHandle( - jSRuntime, + await using FileSystemHandle fileSystemHandle = await FileSystemHandle.CreateAsync( + JSRuntime, await jSEntries.InvokeAsync("at", i), - options); + new CreationOptions() { DisposesJSReference = true }); + fileSystemHandle.FileSystemOptions = FileSystemOptions; return (await fileSystemHandle.GetKindAsync() is FileSystemHandleKind.File) - ? FileSystemFileHandle.Create(jSRuntime, fileSystemHandle.JSReference, options) - : FileSystemDirectoryHandle.Create(jSRuntime, fileSystemHandle.JSReference, options); + ? await FileSystemFileHandle.CreateAsync(JSRuntime, fileSystemHandle.JSReference) + : await FileSystemDirectoryHandle.CreateAsync(JSRuntime, fileSystemHandle.JSReference); } ) .ToArray() ); } + /// + /// Returns a handle for a file named in the directory entry locatable by directoryHandle’s locator. + /// If defines that it should create the file then it will create it if it doesn't already exist. + /// Creation can fail because there already is a directory with the same name, because the name uses characters that aren’t supported in file names on the underlying file system, or because the user agent for security reasons decided not to allow creation of the file. + /// This operation requires write permission, even if the file being returned already exists. + /// If this handle does not already have write permission, this could result in a prompt being shown to the user. + /// To get an existing file without needing write permission, call this method with set to . + /// + /// The name of the file. + /// + /// If is or unspecified and the file doesn't exist, then this call fails; + /// Else if it is then it creates the file if it can. + /// public async Task GetFileHandleAsync(string name, FileSystemGetFileOptions? options = null) { IJSObjectReference jSFileSystemFileHandle = await JSReference.InvokeAsync("getFileHandle", name, options); - return new FileSystemFileHandle(jSRuntime, jSFileSystemFileHandle, this.options); + FileSystemFileHandle file = await FileSystemFileHandle.CreateAsync(JSRuntime, jSFileSystemFileHandle, new CreationOptions() { DisposesJSReference = true }); + file.FileSystemOptions = FileSystemOptions; + return file; } + /// + /// Returns a handle for a directory named in the directory entry locatable by directoryHandle’s locator . + /// If no such directory exists, this creates a new directory. If creating the directory failed, this rejects. + /// Creation can fail because there already is a file with the same name, or because the name uses characters that aren’t supported in directory names on the underlying file system. + /// This operation requires write permission, even if the directory being returned already exists. + /// If this handle does not already have write permission, this could result in a prompt being shown to the user. + /// To get an existing directory without needing write permission, call this method with set to . + /// + /// The name of the directory. + /// + /// If is or unspecified and the directory doesn't exist, then this call fails; + /// Else if it is then it creates the directory if it can. + /// public async Task GetDirectoryHandleAsync(string name, FileSystemGetDirectoryOptions? options = null) { IJSObjectReference jSFileSystemDirectoryHandle = await JSReference.InvokeAsync("getDirectoryHandle", name, options); - return new FileSystemDirectoryHandle(jSRuntime, jSFileSystemDirectoryHandle, this.options); + return new(JSRuntime, jSFileSystemDirectoryHandle, FileSystemOptions, new() { DisposesJSReference = true }); } + /// + /// If the directory entry locatable by directoryHandle’s locator contains a file named , or an empty directory named , this will attempt to delete that file or directory. + /// Attempting to delete a file or directory that does not exist is considered success. + /// If you attempt to delete a non-empty folder then it will fail if has not been set to recursively remove sub-directories. + /// + /// The name of the directory or file. + /// + /// If is or unspecified and the entry is a non-empty directory, then this call fails; + /// Else if it is then it will recursively remove all sub-directories and entries in the directory. + /// public async Task RemoveEntryAsync(string name, FileSystemRemoveOptions? options = null) { await JSReference.InvokeVoidAsync("removeEntry", name, options); } + /// + /// If is equal to the same as this directory, path will be an empty array.
+ /// If is a direct child of this directory, path will be an array containing child’s name.
+ /// If is a descendant of this directory, path will be an array containing the names of all the intermediate directories and child’s name as last element. + /// For example if directory represents /home/user/project and child represents /home/user/project/foo/bar, this will return ["foo", "bar"].
+ /// Otherwise (if this directory and are not related), path will be . + ///
+ /// Some that you want the path to from this . public async Task ResolveAsync(IFileSystemHandle possibleDescendant) { return await JSReference.InvokeAsync("resolve", possibleDescendant.JSReference); diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs index 081bae0..e4b5cb4 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs @@ -1,47 +1,70 @@ -using KristofferStrube.Blazor.FileAPI; +using KristofferStrube.Blazor.DOM.Extensions; +using KristofferStrube.Blazor.FileAPI; using KristofferStrube.Blazor.FileSystem.Extensions; +using KristofferStrube.Blazor.WebIDL; using Microsoft.JSInterop; namespace KristofferStrube.Blazor.FileSystem; /// -/// FileSystemFileHandle browser specs +/// A in-process version of a that represents a file. /// -public class FileSystemFileHandleInProcess : FileSystemFileHandle, IFileSystemHandleInProcess +/// See the API definition here. +[IJSWrapperConverter] +public class FileSystemFileHandleInProcess : FileSystemFileHandle, IFileSystemHandleInProcess, IJSInProcessCreatable { - public new IJSInProcessObjectReference JSReference; + /// + public new IJSInProcessObjectReference JSReference { get; set; } + + /// + /// A lazily evaluated task that gives access to helper methods. + /// protected readonly IJSInProcessObjectReference inProcessHelper; + /// public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference) { - return await CreateAsync(jSRuntime, jSReference, FileSystemOptions.DefaultInstance); + return await CreateAsync(jSRuntime, jSReference); + } + + /// + public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, CreationOptions options) + { + IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(FileSystemOptions.DefaultInstance); + return new FileSystemFileHandleInProcess(jSRuntime, inProcessHelper, jSReference, FileSystemOptions.DefaultInstance, options); } + /// public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions options) { IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(options); - return new FileSystemFileHandleInProcess(jSRuntime, inProcessHelper, jSReference, options); + return new FileSystemFileHandleInProcess(jSRuntime, inProcessHelper, jSReference, options, new() { DisposesJSReference = true }); } - internal FileSystemFileHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, FileSystemOptions options) : base(jSRuntime, jSReference, options) + /// + protected FileSystemFileHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) : base(jSRuntime, jSReference, fileSystemOptions, options) { this.inProcessHelper = inProcessHelper; JSReference = jSReference; } + /// public FileSystemHandleKind Kind => inProcessHelper.Invoke("getAttribute", JSReference, "kind"); + /// public string Name => inProcessHelper.Invoke("getAttribute", JSReference, "name"); + /// public new async Task GetFileAsync() { IJSInProcessObjectReference jSFile = await JSReference.InvokeAsync("getFile"); - return await FileInProcess.CreateAsync(jSRuntime, jSFile); + return await FileInProcess.CreateAsync(JSRuntime, jSFile); } + /// public new async Task CreateWritableAsync(FileSystemCreateWritableOptions? fileSystemCreateWritableOptions = null) { IJSInProcessObjectReference jSFileSystemWritableFileStream = await JSReference.InvokeAsync("createWritable", fileSystemCreateWritableOptions); - return new FileSystemWritableFileStreamInProcess(jSRuntime, inProcessHelper, jSFileSystemWritableFileStream); + return new FileSystemWritableFileStreamInProcess(JSRuntime, inProcessHelper, jSFileSystemWritableFileStream, new() { DisposesJSReference = true }); } } diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs index b9d46fb..cf3af7d 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs @@ -1,33 +1,73 @@ -using Microsoft.JSInterop; +using KristofferStrube.Blazor.WebIDL; +using Microsoft.JSInterop; +using File = KristofferStrube.Blazor.FileAPI.File; namespace KristofferStrube.Blazor.FileSystem; /// -/// FileSystemFileHandle browser specs +/// A that represents a file. /// -public class FileSystemFileHandle : FileSystemHandle +/// See the API definition here. +[IJSWrapperConverter] +public class FileSystemFileHandle : FileSystemHandle, IJSCreatable { + /// + public static new async Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference) + { + return await CreateAsync(jSRuntime, jSReference, new CreationOptions()); + } + + /// + public static new Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, CreationOptions options) + { + return Task.FromResult(new FileSystemFileHandle(jSRuntime, jSReference, FileSystemOptions.DefaultInstance, options)); + } + + /// + public static new Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) + { + return Task.FromResult(new FileSystemFileHandle(jSRuntime, jSReference, options, new() { DisposesJSReference = true })); + } + + /// + [Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")] public static new FileSystemFileHandle Create(IJSRuntime jSRuntime, IJSObjectReference jSReference) { return Create(jSRuntime, jSReference, FileSystemOptions.DefaultInstance); } + /// + [Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")] public static new FileSystemFileHandle Create(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) { - return new(jSRuntime, jSReference, options); + return new(jSRuntime, jSReference, options, new()); } - internal FileSystemFileHandle(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) : base(jSRuntime, jSReference, options) { } + /// + protected FileSystemFileHandle(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) : base(jSRuntime, jSReference, fileSystemOptions, options) { } - public async Task GetFileAsync() + /// + /// Returns a that that represents the state of the file on the disk. If the file on disk changes or is removed after this method has returned the file then this will likely no longer be readable. + /// + public async Task GetFileAsync() { IJSObjectReference jSFile = await JSReference.InvokeAsync("getFile"); - return FileAPI.File.Create(jSRuntime, jSFile); + return await File.CreateAsync(JSRuntime, jSFile); } + /// + /// Returns a that can be used to write to the file. + /// Any changes made through stream won’t be reflected in the file entry locatable by fileHandle’s locator until the stream has been closed (or disposed). + /// User agents try to ensure that no partial writes happen, i.e. the file will either contain its old contents or it will contain whatever data was written through stream up until the stream has been closed (or disposed). + /// This is typically implemented by writing data to a temporary file, and only replacing the file entry locatable by fileHandle’s locator with the temporary file when the writable filestream is closed (or disposed). + /// + /// + /// If is or not specified, the temporary file starts out empty, otherwise the existing file is first copied to this temporary file. + /// + /// public async Task CreateWritableAsync(FileSystemCreateWritableOptions? fileSystemCreateWritableOptions = null) { IJSObjectReference jSFileSystemWritableFileStream = await JSReference.InvokeAsync("createWritable", fileSystemCreateWritableOptions); - return await FileSystemWritableFileStream.CreateAsync(jSRuntime, jSFileSystemWritableFileStream); + return await FileSystemWritableFileStream.CreateAsync(JSRuntime, jSFileSystemWritableFileStream); } } diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs index c95f302..d2030bb 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs @@ -1,34 +1,52 @@ -using KristofferStrube.Blazor.FileSystem.Extensions; +using KristofferStrube.Blazor.DOM.Extensions; +using KristofferStrube.Blazor.FileSystem.Extensions; +using KristofferStrube.Blazor.WebIDL; using Microsoft.JSInterop; namespace KristofferStrube.Blazor.FileSystem; -/// -/// FileSystemHandle browser specs -/// -public class FileSystemHandleInProcess : FileSystemHandle, IFileSystemHandleInProcess +/// +[IJSWrapperConverter] +public class FileSystemHandleInProcess : FileSystemHandle, IFileSystemHandleInProcess, IJSInProcessCreatable { - public new IJSInProcessObjectReference JSReference; + /// + public new IJSInProcessObjectReference JSReference { get; set; } + + /// + /// A lazily evaluated task that gives access to helper methods. + /// protected readonly IJSInProcessObjectReference inProcessHelper; + /// public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference) { - return await CreateAsync(jSRuntime, jSReference, FileSystemOptions.DefaultInstance); + return await CreateAsync(jSRuntime, jSReference, new CreationOptions()); + } + + /// + public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, CreationOptions options) + { + IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(FileSystemOptions.DefaultInstance); + return new FileSystemHandleInProcess(jSRuntime, inProcessHelper, jSReference, FileSystemOptions.DefaultInstance, options); } + /// public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions options) { IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(options); - return new FileSystemHandleInProcess(jSRuntime, inProcessHelper, jSReference, options); + return new FileSystemHandleInProcess(jSRuntime, inProcessHelper, jSReference, options, new() { DisposesJSReference = true }); } - internal FileSystemHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, FileSystemOptions options) : base(jSRuntime, jSReference, options) + /// + protected FileSystemHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) : base(jSRuntime, jSReference, fileSystemOptions, options) { this.inProcessHelper = inProcessHelper; JSReference = jSReference; } + /// public FileSystemHandleKind Kind => inProcessHelper.Invoke("getAttribute", JSReference, "kind"); + /// public string Name => inProcessHelper.Invoke("getAttribute", JSReference, "name"); } diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.cs index 286c577..7de584c 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.cs @@ -1,36 +1,62 @@ -using Microsoft.JSInterop; +using KristofferStrube.Blazor.WebIDL; +using Microsoft.JSInterop; namespace KristofferStrube.Blazor.FileSystem; -/// -/// FileSystemHandle browser specs -/// -public class FileSystemHandle : BaseJSWrapper, IFileSystemHandle +/// +[IJSWrapperConverter] +public class FileSystemHandle : BaseJSWrapper, IFileSystemHandle, IJSCreatable { + /// + public static async Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference) + { + return await CreateAsync(jSRuntime, jSReference, new CreationOptions()); + } + + /// + public static Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, CreationOptions options) + { + return Task.FromResult(new FileSystemHandle(jSRuntime, jSReference, FileSystemOptions.DefaultInstance, options)); + } + + /// + public static Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) + { + return Task.FromResult(new FileSystemHandle(jSRuntime, jSReference, options, new() { DisposesJSReference = true })); + } + + /// + [Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")] public static FileSystemHandle Create(IJSRuntime jSRuntime, IJSObjectReference jSReference) { return Create(jSRuntime, jSReference, FileSystemOptions.DefaultInstance); } + /// + [Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")] public static FileSystemHandle Create(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) { - return new(jSRuntime, jSReference, options); + return new(jSRuntime, jSReference, options, new()); } - internal FileSystemHandle(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) : base(jSRuntime, jSReference, options) { } + /// + protected FileSystemHandle(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) : base(jSRuntime, jSReference, fileSystemOptions, options) { } + /// public async Task GetKindAsync() { IJSObjectReference helper = await helperTask.Value; return await helper.InvokeAsync("getAttribute", JSReference, "kind"); } + /// public async Task GetNameAsync() { IJSObjectReference helper = await helperTask.Value; return await helper.InvokeAsync("getAttribute", JSReference, "name"); } + /// public async Task IsSameEntryAsync(IFileSystemHandle other) { return await JSReference.InvokeAsync("isSameEntry", other.JSReference); diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs index 4f40ada..d290fc6 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs @@ -1,4 +1,6 @@ -using KristofferStrube.Blazor.FileSystem.Extensions; +using KristofferStrube.Blazor.DOM.Extensions; +using KristofferStrube.Blazor.FileSystem.Extensions; +using KristofferStrube.Blazor.WebIDL; using Microsoft.JSInterop; namespace KristofferStrube.Blazor.FileSystem; @@ -6,23 +8,38 @@ namespace KristofferStrube.Blazor.FileSystem; /// /// FileSystemWritableFileStream browser specs /// -public class FileSystemWritableFileStreamInProcess : FileSystemWritableFileStream +public class FileSystemWritableFileStreamInProcess : FileSystemWritableFileStream, IJSInProcessCreatable { - public new IJSInProcessObjectReference JSReference; + /// + public new IJSInProcessObjectReference JSReference { get; } + + /// + /// A lazily evaluated task that gives access to helper methods. + /// protected readonly IJSInProcessObjectReference inProcessHelper; + /// + public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions options) + { + IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(options); + return new FileSystemWritableFileStreamInProcess(jSRuntime, inProcessHelper, jSReference, new() { DisposesJSReference = true }); + } + + /// public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference) { return await CreateAsync(jSRuntime, jSReference, FileSystemOptions.DefaultInstance); } - public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions options) + /// + public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, CreationOptions options) { - IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(options); - return new FileSystemWritableFileStreamInProcess(jSRuntime, inProcessHelper, jSReference); + IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(FileSystemOptions.DefaultInstance); + return new FileSystemWritableFileStreamInProcess(jSRuntime, inProcessHelper, jSReference, options); } - internal FileSystemWritableFileStreamInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference) : base(jSRuntime, jSReference) + /// + protected internal FileSystemWritableFileStreamInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, CreationOptions options) : base(jSRuntime, jSReference, options) { this.inProcessHelper = inProcessHelper; JSReference = jSReference; diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs index e63f62c..f2ba73a 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs @@ -1,81 +1,145 @@ using KristofferStrube.Blazor.FileAPI; using KristofferStrube.Blazor.FileSystem.Extensions; using KristofferStrube.Blazor.Streams; +using KristofferStrube.Blazor.WebIDL; using Microsoft.JSInterop; +using File = KristofferStrube.Blazor.FileAPI.File; namespace KristofferStrube.Blazor.FileSystem; /// -/// FileSystemWritableFileStream browser specs +/// A that can write to and seek in a . /// -public class FileSystemWritableFileStream : WritableStream +/// See the API definition here. +[IJSWrapperConverter] +public class FileSystemWritableFileStream : WritableStream, IJSCreatable { /// /// A lazily evaluated task that gives access to helper methods for the File System API. /// - protected readonly Lazy> fileSystemHelperTask; + protected Lazy> FileSystemHelperTask { get; } + /// public override bool CanSeek => true; + /// public override long Position { get; set; } + /// [Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")] public static new FileSystemWritableFileStream Create(IJSRuntime jSRuntime, IJSObjectReference jSReference) { - return new FileSystemWritableFileStream(jSRuntime, jSReference); + return new FileSystemWritableFileStream(jSRuntime, jSReference, new() { DisposesJSReference = true }); } - public static new Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference) + /// + public static new async Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference) { - return Task.FromResult(new FileSystemWritableFileStream(jSRuntime, jSReference)); + return await CreateAsync(jSRuntime, jSReference, new()); } - protected FileSystemWritableFileStream(IJSRuntime jSRuntime, IJSObjectReference jSReference) : base(jSRuntime, jSReference) + /// + public static new Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, CreationOptions options) { - fileSystemHelperTask = new(() => jSRuntime.GetHelperAsync(FileSystemOptions.DefaultInstance)); + return Task.FromResult(new FileSystemWritableFileStream(jSRuntime, jSReference, options)); } + /// + protected FileSystemWritableFileStream(IJSRuntime jSRuntime, IJSObjectReference jSReference, CreationOptions options) : base(jSRuntime, jSReference, options) + { + FileSystemHelperTask = new(() => jSRuntime.GetHelperAsync(FileSystemOptions.DefaultInstance)); + } + + /// public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) { await JSReference.InvokeVoidAsync("write", buffer.ToArray()); } + /// + /// Writes the content of data into the file associated with stream at the current file cursor offset. + /// No changes are written to the actual file on disk until the stream has been closed. + /// Changes are typically written to a temporary file instead. + /// + /// The data that will be written to the stream. public async Task WriteAsync(string data) { await JSReference.InvokeVoidAsync("write", data); } + /// public async Task WriteAsync(byte[] data) { await JSReference.InvokeVoidAsync("write", data); } + /// public async Task WriteAsync(Blob data) { await JSReference.InvokeVoidAsync("write", data.JSReference); } + /// + /// + /// + /// If of is set to it will write the data into the file associated with the stream. + /// If the is set to some value then it will write the content at this position; + /// Else it will write the content at the current file cursor offset.
+ /// No changes are written to the actual file on disk until the stream has been closed.
+ /// Changes are typically written to a temporary file instead. + ///
+ /// + /// If of is set to + /// it will move the file cursor offset to the position specified in 's property. + /// + /// + /// If of is set to it will resize the file associated with the stream to be the size specified in 's property. + /// If is larger than the current file size this pads the file with null bytes, otherwise it truncates the file. + /// The file cursor is updated when truncate is called. + /// If the cursor is smaller than , it remains unchanged. + /// If the cursor is larger than , it is set to to ensure that subsequent writes do not error. + /// No changes are written to the actual file until on disk until the stream has been closed. + /// Changes are typically written to a temporary file instead. + /// + ///
+ ///
+ /// The argument for how to process by performing one of the actions: , , . public async Task WriteAsync(BlobWriteParams data) { await JSReference.InvokeVoidAsync("write", data); } + /// public async Task WriteAsync(StringWriteParams data) { await JSReference.InvokeVoidAsync("write", data); } + /// public async Task WriteAsync(ByteArrayWriteParams data) { await JSReference.InvokeVoidAsync("write", data); } + /// + /// Updates the current file cursor offset the position bytes from the top of the file. + /// + /// The new cursor position + /// public async Task SeekAsync(ulong position) { Position = (long)position; await JSReference.InvokeVoidAsync("seek", position); } + /// + /// Resizes the file associated with stream to be bytes long. If is larger than the current file size this pads the file with null bytes, otherwise it truncates the file. + /// The file cursor is updated when truncate is called. + /// If the cursor is smaller than , it remains unchanged. + /// If the cursor is larger than , it is set to to ensure that subsequent writes do not error. + /// No changes are written to the actual file until on disk until the stream has been closed. Changes are typically written to a temporary file instead. + /// + /// The new size public async Task TruncateAsync(ulong size) { await JSReference.InvokeVoidAsync("truncate", size); diff --git a/src/KristofferStrube.Blazor.FileSystem/IFileSystemHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/IFileSystemHandle.InProcess.cs index f54338e..f8433d8 100644 --- a/src/KristofferStrube.Blazor.FileSystem/IFileSystemHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/IFileSystemHandle.InProcess.cs @@ -1,7 +1,14 @@ namespace KristofferStrube.Blazor.FileSystem; +/// +/// An in-process version of a handle for a file or a directory in a file system. +/// +/// See the API definition here. public interface IFileSystemHandleInProcess : IFileSystemHandle { - FileSystemHandleKind Kind { get; } - string Name { get; } + /// + public FileSystemHandleKind Kind { get; } + + /// + public string Name { get; } } \ No newline at end of file diff --git a/src/KristofferStrube.Blazor.FileSystem/IFileSystemHandle.cs b/src/KristofferStrube.Blazor.FileSystem/IFileSystemHandle.cs index 4f87189..e8d4539 100644 --- a/src/KristofferStrube.Blazor.FileSystem/IFileSystemHandle.cs +++ b/src/KristofferStrube.Blazor.FileSystem/IFileSystemHandle.cs @@ -1,11 +1,28 @@ -using Microsoft.JSInterop; +using KristofferStrube.Blazor.WebIDL; namespace KristofferStrube.Blazor.FileSystem; -public interface IFileSystemHandle +/// +/// A handle for a file or a directory in a file system. +/// +/// See the API definition here. +[IJSWrapperConverter] +public interface IFileSystemHandle : IJSWrapper { - public IJSObjectReference JSReference { get; } - Task GetKindAsync(); - Task GetNameAsync(); - Task IsSameEntryAsync(IFileSystemHandle other); + /// + /// Is if the handle is a , or if the handle is a . + /// + public Task GetKindAsync(); + + /// + /// The last path component of the handles locator's path. + /// + public Task GetNameAsync(); + + /// + /// Checks if handle and the handle are the same. + /// + /// Some other handle + /// if handle is the same as the handle; else + public Task IsSameEntryAsync(IFileSystemHandle other); } \ No newline at end of file diff --git a/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.InProcess.cs index acec7d5..35f2f47 100644 --- a/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.InProcess.cs @@ -1,6 +1,10 @@ namespace KristofferStrube.Blazor.FileSystem; +/// +/// A service that exposes methods for getting an in-process version of a Origin Private Directory. +/// public interface IStorageManagerServiceInProcess : IStorageManagerService { - new Task GetOriginPrivateDirectoryAsync(); + /// + public new Task GetOriginPrivateDirectoryAsync(); } \ No newline at end of file diff --git a/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.cs b/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.cs index a2c4ab4..0486126 100644 --- a/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.cs +++ b/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.cs @@ -1,6 +1,20 @@ namespace KristofferStrube.Blazor.FileSystem; +/// +/// A service that exposes methods for getting the Origin Private Directory +/// +/// See the API definition here. public interface IStorageManagerService { - Task GetOriginPrivateDirectoryAsync(); + /// + /// Gets a that is a local bucket for the current domain. It is persistent across sessions. + /// + public Task GetOriginPrivateDirectoryAsync(); + + /// + /// + /// This overload has explicit options for how you want to import the JS helper module used in the library. + /// + /// Options for how the directory should construct its JS helper module + public Task GetOriginPrivateDirectoryAsync(FileSystemOptions options); } \ No newline at end of file diff --git a/src/KristofferStrube.Blazor.FileSystem/KristofferStrube.Blazor.FileSystem.csproj b/src/KristofferStrube.Blazor.FileSystem/KristofferStrube.Blazor.FileSystem.csproj index a78ff0b..e7d32dc 100644 --- a/src/KristofferStrube.Blazor.FileSystem/KristofferStrube.Blazor.FileSystem.csproj +++ b/src/KristofferStrube.Blazor.FileSystem/KristofferStrube.Blazor.FileSystem.csproj @@ -1,7 +1,7 @@ - net7.0 + net7.0;net8.0 enable enable Blazor File System API wrapper @@ -34,8 +34,7 @@ - - + diff --git a/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemCreateWritableOptions.cs b/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemCreateWritableOptions.cs new file mode 100644 index 0000000..f9a0153 --- /dev/null +++ b/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemCreateWritableOptions.cs @@ -0,0 +1,17 @@ +using System.Text.Json.Serialization; + +namespace KristofferStrube.Blazor.FileSystem; + +/// +/// The options for creating a using the method. +/// +/// See the API definition here. +public class FileSystemCreateWritableOptions +{ + /// + /// If set to then it keeps the existing data of the . + /// + [JsonPropertyName("keepExistingData")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool KeepExistingData { get; set; } = false; +} diff --git a/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemGetDirectoryOptions.cs b/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemGetDirectoryOptions.cs index 7d474f6..9382e8f 100644 --- a/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemGetDirectoryOptions.cs +++ b/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemGetDirectoryOptions.cs @@ -3,10 +3,14 @@ namespace KristofferStrube.Blazor.FileSystem; /// -/// FileSystemGetDirectoryOptions browser specs +/// The options for getting a using the method. /// +/// See the API definition here. public class FileSystemGetDirectoryOptions { + /// + /// If the directory does not already exist and this is set to it will create the directory; Else it will fail. + /// [JsonPropertyName("create")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool Create { get; set; } diff --git a/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemGetFileOptions.cs b/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemGetFileOptions.cs index 7216b10..5575f3d 100644 --- a/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemGetFileOptions.cs +++ b/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemGetFileOptions.cs @@ -3,10 +3,14 @@ namespace KristofferStrube.Blazor.FileSystem; /// -/// FileSystemGetFileOptions browser specs +/// The options for getting a using the method. /// +/// See the API definition here. public class FileSystemGetFileOptions { + /// + /// If the file does not already exist and this is set to it will create the file; Else it will fail. + /// [JsonPropertyName("create")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool Create { get; set; } diff --git a/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemOptions.cs b/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemOptions.cs index d9a9bdf..61c87e1 100644 --- a/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemOptions.cs +++ b/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemOptions.cs @@ -2,17 +2,43 @@ namespace KristofferStrube.Blazor.FileSystem; +/// +/// Options for what path the JS Helper module will be found at. +/// public class FileSystemOptions { + /// + /// The base path that is used by default. + /// public const string DefaultBasePath = "./_content/"; + + /// + /// The namespace that the JS module will be found in by default. + /// public static readonly string DefaultNamespace = Assembly.GetExecutingAssembly().GetName().Name ?? "KristofferStrube.Blazor.FileSystem"; + + /// + /// The standard fill path for the JS module. + /// public static readonly string DefaultScriptPath = $"{DefaultNamespace}/{DefaultNamespace}.js"; + /// + /// Option for changing the base path. + /// public string BasePath { get; set; } = DefaultBasePath; + + /// + /// Option for changing the relative path for the JS module. + /// public string ScriptPath { get; set; } = DefaultScriptPath; - public string FullScriptPath => Path.Combine(this.BasePath, this.ScriptPath); + /// + /// The calculated full script path that locates the JS module. + /// + public string FullScriptPath => Path.Combine(BasePath, ScriptPath); + /// + /// A static instance that can be reused in places where no other options are defined. + /// internal static FileSystemOptions DefaultInstance = new(); - } \ No newline at end of file diff --git a/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemRemoveOptions.cs b/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemRemoveOptions.cs index 860979a..93ca56e 100644 --- a/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemRemoveOptions.cs +++ b/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemRemoveOptions.cs @@ -3,10 +3,14 @@ namespace KristofferStrube.Blazor.FileSystem; /// -/// FileSystemRemoveOptions browser specs +/// The options for removing an entry in a with the method. /// +/// See the API definition here. public class FileSystemRemoveOptions { + /// + /// Whether it should recursively remove subfolder in case the + /// [JsonPropertyName("recursive")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool Recursive { get; set; } diff --git a/src/KristofferStrube.Blazor.FileSystem/Options/WriteParams.cs b/src/KristofferStrube.Blazor.FileSystem/Options/WriteParams.cs index 3216365..df0c8a5 100644 --- a/src/KristofferStrube.Blazor.FileSystem/Options/WriteParams.cs +++ b/src/KristofferStrube.Blazor.FileSystem/Options/WriteParams.cs @@ -1,53 +1,88 @@ using KristofferStrube.Blazor.FileAPI; -using KristofferStrube.Blazor.FileSystem.Converters; using System.Text.Json.Serialization; namespace KristofferStrube.Blazor.FileSystem; +/// +/// Write params that can be used to write a . +/// +/// See the API definition here. public class BlobWriteParams : BaseWriteParams { + /// + /// Creates the write params. + /// + /// The type of write that will be performed. The data of the write params will only be used if the is chosen. public BlobWriteParams(WriteCommandType type) { Type = type; } + /// + /// The data that will be written. + /// [JsonPropertyName("data")] - [JsonConverter(typeof(BlobConverter))] public Blob? Data { get; set; } } +/// +/// Write params that can be used to write a . +/// +/// See the API definition here. public class StringWriteParams : BaseWriteParams { + /// public StringWriteParams(WriteCommandType type) { Type = type; } + /// [JsonPropertyName("data")] public string? Data { get; set; } } +/// +/// Write params that can be used to write bytes in a byte-array. +/// +/// See the API definition here. public class ByteArrayWriteParams : BaseWriteParams { + /// public ByteArrayWriteParams(WriteCommandType type) { Type = type; } + /// [JsonPropertyName("data")] public byte[]? Data { get; set; } } +/// +/// A base class for the different kinds of write params. +/// +/// See the API definition here. public abstract class BaseWriteParams { + /// + /// The type write that will be performed. + /// [JsonPropertyName("type")] public WriteCommandType Type { get; init; } - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + /// + /// If is chosen for the then this is the new size of the underlying file. + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("size")] - public ulong Size { get; set; } + public ulong? Size { get; set; } - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + /// + /// If is chosen for the then the data will be written at this offset in the file.
+ /// And if is chosen for the then this position will be new position of the cursor into the file. + ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("position")] - public ulong Position { get; set; } + public ulong? Position { get; set; } } \ No newline at end of file diff --git a/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.InProcess.cs index 26e15c8..65055a0 100644 --- a/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.InProcess.cs @@ -2,8 +2,13 @@ namespace KristofferStrube.Blazor.FileSystem; +/// public class StorageManagerServiceInProcess : StorageManagerService, IStorageManagerServiceInProcess { + /// + /// Creates a + /// + /// An instance. public StorageManagerServiceInProcess(IJSRuntime jSRuntime) : base(jSRuntime) { } /// diff --git a/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs b/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs index ba2b877..fd6ae24 100644 --- a/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs +++ b/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs @@ -1,39 +1,45 @@ using KristofferStrube.Blazor.FileSystem.Extensions; -using Microsoft.Extensions.Options; using Microsoft.JSInterop; namespace KristofferStrube.Blazor.FileSystem; -public class StorageManagerService : IStorageManagerService +/// +public class StorageManagerService : IStorageManagerService, IAsyncDisposable { + /// + /// A lazily evaluated task that gives access to helper methods. + /// protected readonly Lazy> helperTask; + + /// + /// The used for making JSInterop calls. + /// protected readonly IJSRuntime jSRuntime; + /// + /// Creates the service. Should be a scoped service, especially when used in Blazor Server render mode. + /// + /// public StorageManagerService(IJSRuntime jSRuntime) { helperTask = new(() => jSRuntime.GetHelperAsync(FileSystemOptions.DefaultInstance)); this.jSRuntime = jSRuntime; } - /// - /// getDirectory() for StorageManager browser specs - /// - /// + /// public async Task GetOriginPrivateDirectoryAsync() { return await GetOriginPrivateDirectoryAsync(FileSystemOptions.DefaultInstance); } - /// - /// getDirectory() for StorageManager browser specs - /// - /// + /// public async Task GetOriginPrivateDirectoryAsync(FileSystemOptions options) { IJSObjectReference directoryHandle = await jSRuntime.InvokeAsync("navigator.storage.getDirectory"); - return new FileSystemDirectoryHandle(jSRuntime, directoryHandle, options); + return await FileSystemDirectoryHandle.CreateAsync(jSRuntime, directoryHandle, options); } + /// public async ValueTask DisposeAsync() { if (helperTask.IsValueCreated) From b7a0a9c120898a23acb501282f00f011623e664b Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Sun, 14 Sep 2025 22:20:35 +0200 Subject: [PATCH 02/14] Removed unnecessary descriptions. --- .../Enums/WriteCommandType.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/KristofferStrube.Blazor.FileSystem/Enums/WriteCommandType.cs b/src/KristofferStrube.Blazor.FileSystem/Enums/WriteCommandType.cs index 4922347..81c7866 100644 --- a/src/KristofferStrube.Blazor.FileSystem/Enums/WriteCommandType.cs +++ b/src/KristofferStrube.Blazor.FileSystem/Enums/WriteCommandType.cs @@ -1,5 +1,4 @@ using KristofferStrube.Blazor.FileSystem.Converters; -using System.ComponentModel; using System.Text.Json.Serialization; namespace KristofferStrube.Blazor.FileSystem; @@ -14,18 +13,15 @@ public enum WriteCommandType /// /// With this command type you can write to a file stream. /// - [Description("write")] Write, /// /// With this command type you can move the cursor inside a file stream. /// - [Description("seek")] Seek, /// /// With this command type you can truncate the size of the file that the file stream points to. /// - [Description("truncate")] Truncate, } From 8ddbefaf015a0eb6d0131442c5859df0d8f32aad Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Sun, 14 Sep 2025 22:22:43 +0200 Subject: [PATCH 03/14] Updated comment during self-review. --- .../Extensions/IServiceCollectionExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/KristofferStrube.Blazor.FileSystem/Extensions/IServiceCollectionExtensions.cs b/src/KristofferStrube.Blazor.FileSystem/Extensions/IServiceCollectionExtensions.cs index 07d4fcc..a36cb4b 100644 --- a/src/KristofferStrube.Blazor.FileSystem/Extensions/IServiceCollectionExtensions.cs +++ b/src/KristofferStrube.Blazor.FileSystem/Extensions/IServiceCollectionExtensions.cs @@ -38,7 +38,7 @@ public static IServiceCollection AddStorageManagerServiceInProcess(this IService } /// - /// Adds a to the service collection with the option to configure where the helper JS module is located. + /// Adds a to the service collection with the option to configure where the helper JS module is located. /// /// The service collection to add the service to. /// An action to configure the that defines where the helper JS module is located. From 2c8d1c2a303907ff248506798cdf31b7c3c6bc21 Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Sun, 14 Sep 2025 22:31:15 +0200 Subject: [PATCH 04/14] Updatet XML doc to point to correct method. --- .../FileSystemDirectoryHandle.InProcess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs index 1177e51..e893edc 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs @@ -53,7 +53,7 @@ protected FileSystemDirectoryHandleInProcess(IJSRuntime jSRuntime, IJSInProcessO /// public string Name => inProcessHelper.Invoke("getAttribute", JSReference, "name"); - /// + /// public new async Task ValuesAsync() { IJSObjectReference helper = await helperTask.Value; From d16a8d962a29b854e929d8eed2ddf33a15b21828 Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Sun, 14 Sep 2025 23:01:24 +0200 Subject: [PATCH 05/14] Ensure that File Handles correctly instantiate other wrappers to dispose references. --- .../FileSystemDirectoryHandle.InProcess.cs | 38 ++++++++++++++++--- .../FileSystemDirectoryHandle.cs | 30 +++++++++++---- .../FileSystemFileHandle.cs | 11 ++++-- .../StorageManagerService.cs | 8 +++- 4 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs index e893edc..a95382d 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs @@ -69,9 +69,27 @@ protected FileSystemDirectoryHandleInProcess(IJSRuntime jSRuntime, IJSInProcessO JSRuntime, await jSEntries.InvokeAsync("at", i), FileSystemOptions); - return (fileSystemHandle.Kind is FileSystemHandleKind.File) - ? await FileSystemFileHandleInProcess.CreateAsync(JSRuntime, fileSystemHandle.JSReference, FileSystemOptions) - : await FileSystemDirectoryHandleInProcess.CreateAsync(JSRuntime, fileSystemHandle.JSReference, FileSystemOptions); + + FileSystemHandleKind kind = await fileSystemHandle.GetKindAsync(); + + if (kind is FileSystemHandleKind.File) + { + FileSystemFileHandleInProcess instance = await FileSystemFileHandleInProcess.CreateAsync(JSRuntime, fileSystemHandle.JSReference, new CreationOptions() + { + DisposesJSReference = true + }); + instance.FileSystemOptions = FileSystemOptions; + return instance; + } + else + { + FileSystemDirectoryHandleInProcess instance = await CreateAsync(JSRuntime, fileSystemHandle.JSReference, new CreationOptions() + { + DisposesJSReference = true + }); + instance.FileSystemOptions = FileSystemOptions; + return instance; + } } ) .ToArray() @@ -82,13 +100,23 @@ await jSEntries.InvokeAsync("at", i), public new async Task GetFileHandleAsync(string name, FileSystemGetFileOptions? options = null) { IJSInProcessObjectReference jSFileSystemFileHandle = await JSReference.InvokeAsync("getFileHandle", name, options); - return await FileSystemFileHandleInProcess.CreateAsync(JSRuntime, jSFileSystemFileHandle, FileSystemOptions); + FileSystemFileHandleInProcess instance = await FileSystemFileHandleInProcess.CreateAsync(JSRuntime, jSFileSystemFileHandle, new CreationOptions() + { + DisposesJSReference = true + }); + instance.FileSystemOptions = FileSystemOptions; + return instance; } /// public new async Task GetDirectoryHandleAsync(string name, FileSystemGetDirectoryOptions? options = null) { IJSInProcessObjectReference jSFileSystemFileHandle = await JSReference.InvokeAsync("getDirectoryHandle", name, options); - return await CreateAsync(JSRuntime, jSFileSystemFileHandle, FileSystemOptions); + FileSystemDirectoryHandleInProcess instance = await CreateAsync(JSRuntime, jSFileSystemFileHandle, new CreationOptions() + { + DisposesJSReference = true + }); + instance.FileSystemOptions = FileSystemOptions; + return instance; } } diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.cs index 72ff4be..dd63718 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.cs @@ -13,7 +13,7 @@ public class FileSystemDirectoryHandle : FileSystemHandle, IJSCreatable public static new async Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference) { - return await CreateAsync(jSRuntime, jSReference); + return await CreateAsync(jSRuntime, jSReference, FileSystemOptions.DefaultInstance); } /// @@ -61,12 +61,28 @@ public async Task ValuesAsync() { await using FileSystemHandle fileSystemHandle = await FileSystemHandle.CreateAsync( JSRuntime, - await jSEntries.InvokeAsync("at", i), - new CreationOptions() { DisposesJSReference = true }); - fileSystemHandle.FileSystemOptions = FileSystemOptions; - return (await fileSystemHandle.GetKindAsync() is FileSystemHandleKind.File) - ? await FileSystemFileHandle.CreateAsync(JSRuntime, fileSystemHandle.JSReference) - : await FileSystemDirectoryHandle.CreateAsync(JSRuntime, fileSystemHandle.JSReference); + await jSEntries.InvokeAsync("at", i), FileSystemOptions); + + FileSystemHandleKind kind = await fileSystemHandle.GetKindAsync(); + + if (kind is FileSystemHandleKind.File) + { + FileSystemFileHandle instance = await FileSystemFileHandle.CreateAsync(JSRuntime, fileSystemHandle.JSReference, new CreationOptions() + { + DisposesJSReference = true + }); + instance.FileSystemOptions = FileSystemOptions; + return instance; + } + else + { + FileSystemDirectoryHandle instance = await CreateAsync(JSRuntime, fileSystemHandle.JSReference, new CreationOptions() + { + DisposesJSReference = true + }); + instance.FileSystemOptions = FileSystemOptions; + return instance; + } } ) .ToArray() diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs index cf3af7d..461ff2d 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs @@ -52,7 +52,10 @@ protected FileSystemFileHandle(IJSRuntime jSRuntime, IJSObjectReference jSRefere public async Task GetFileAsync() { IJSObjectReference jSFile = await JSReference.InvokeAsync("getFile"); - return await File.CreateAsync(JSRuntime, jSFile); + return await File.CreateAsync(JSRuntime, jSFile, new() + { + DisposesJSReference = true + }); } /// @@ -64,10 +67,12 @@ public async Task GetFileAsync() /// /// If is or not specified, the temporary file starts out empty, otherwise the existing file is first copied to this temporary file. /// - /// public async Task CreateWritableAsync(FileSystemCreateWritableOptions? fileSystemCreateWritableOptions = null) { IJSObjectReference jSFileSystemWritableFileStream = await JSReference.InvokeAsync("createWritable", fileSystemCreateWritableOptions); - return await FileSystemWritableFileStream.CreateAsync(JSRuntime, jSFileSystemWritableFileStream); + return await FileSystemWritableFileStream.CreateAsync(JSRuntime, jSFileSystemWritableFileStream, new CreationOptions() + { + DisposesJSReference = true + }); } } diff --git a/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs b/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs index fd6ae24..9782dc0 100644 --- a/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs +++ b/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs @@ -1,4 +1,5 @@ using KristofferStrube.Blazor.FileSystem.Extensions; +using KristofferStrube.Blazor.WebIDL; using Microsoft.JSInterop; namespace KristofferStrube.Blazor.FileSystem; @@ -36,7 +37,12 @@ public async Task GetOriginPrivateDirectoryAsync() public async Task GetOriginPrivateDirectoryAsync(FileSystemOptions options) { IJSObjectReference directoryHandle = await jSRuntime.InvokeAsync("navigator.storage.getDirectory"); - return await FileSystemDirectoryHandle.CreateAsync(jSRuntime, directoryHandle, options); + FileSystemDirectoryHandle instance = await FileSystemDirectoryHandle.CreateAsync(jSRuntime, directoryHandle, new CreationOptions() + { + DisposesJSReference = true + }); + instance.FileSystemOptions = options; + return instance; } /// From 10c5911edbe96a0fcc65f40cbdbc7ca5bcf30803 Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Sun, 14 Sep 2025 23:27:29 +0200 Subject: [PATCH 06/14] Ensure that references and helpers are disposed when wrappers are disposed. --- .../BaseJSWrapper.cs | 6 ++---- .../FileSystemDirectoryHandle.InProcess.cs | 8 ++++++++ .../FileSystemFileHandle.InProcess.cs | 8 ++++++++ .../FileSystemHandle.InProcess.cs | 8 ++++++++ .../FileSystemWritableFileStream.InProcess.cs | 8 ++++++++ .../FileSystemWritableFileStream.cs | 12 ++++++++++++ 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs b/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs index 8696ca3..eddbc55 100644 --- a/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs +++ b/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs @@ -39,10 +39,7 @@ protected BaseJSWrapper(IJSRuntime jSRuntime, IJSObjectReference jSReference, Fi DisposesJSReference = options.DisposesJSReference; } - /// - /// Disposes the underlying js object reference. - /// - /// + /// public async ValueTask DisposeAsync() { if (helperTask.IsValueCreated) @@ -50,6 +47,7 @@ public async ValueTask DisposeAsync() IJSObjectReference module = await helperTask.Value; await module.DisposeAsync(); } + await IJSWrapper.DisposeJSReference(this); GC.SuppressFinalize(this); } } diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs index a95382d..33e3b7a 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs @@ -119,4 +119,12 @@ await jSEntries.InvokeAsync("at", i), instance.FileSystemOptions = FileSystemOptions; return instance; } + + /// + public new async ValueTask DisposeAsync() + { + await base.DisposeAsync(); + await inProcessHelper.DisposeAsync(); + GC.SuppressFinalize(this); + } } diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs index e4b5cb4..0c6cd7a 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs @@ -67,4 +67,12 @@ protected FileSystemFileHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObject IJSInProcessObjectReference jSFileSystemWritableFileStream = await JSReference.InvokeAsync("createWritable", fileSystemCreateWritableOptions); return new FileSystemWritableFileStreamInProcess(JSRuntime, inProcessHelper, jSFileSystemWritableFileStream, new() { DisposesJSReference = true }); } + + /// + public new async ValueTask DisposeAsync() + { + await base.DisposeAsync(); + await inProcessHelper.DisposeAsync(); + GC.SuppressFinalize(this); + } } diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs index d2030bb..633b328 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs @@ -49,4 +49,12 @@ protected FileSystemHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObjectRefe /// public string Name => inProcessHelper.Invoke("getAttribute", JSReference, "name"); + + /// + public new async ValueTask DisposeAsync() + { + await base.DisposeAsync(); + await inProcessHelper.DisposeAsync(); + GC.SuppressFinalize(this); + } } diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs index d290fc6..f615518 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs @@ -44,4 +44,12 @@ protected internal FileSystemWritableFileStreamInProcess(IJSRuntime jSRuntime, I this.inProcessHelper = inProcessHelper; JSReference = jSReference; } + + /// + public new async ValueTask DisposeAsync() + { + await base.DisposeAsync(); + await inProcessHelper.DisposeAsync(); + GC.SuppressFinalize(this); + } } diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs index f2ba73a..922c4bf 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs @@ -144,4 +144,16 @@ public async Task TruncateAsync(ulong size) { await JSReference.InvokeVoidAsync("truncate", size); } + + /// + public new async ValueTask DisposeAsync() + { + await base.DisposeAsync(); + if (FileSystemHelperTask.IsValueCreated) + { + IJSObjectReference module = await FileSystemHelperTask.Value; + await module.DisposeAsync(); + } + GC.SuppressFinalize(this); + } } From 53ceff59e21cc873138291c755ca61d3584635f4 Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Sun, 14 Sep 2025 23:28:18 +0200 Subject: [PATCH 07/14] Ensure that FileInProcess is also created with `DisposesJSReference` set to true. --- .../FileSystemFileHandle.InProcess.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs index 0c6cd7a..4591b8a 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs @@ -58,7 +58,10 @@ protected FileSystemFileHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObject public new async Task GetFileAsync() { IJSInProcessObjectReference jSFile = await JSReference.InvokeAsync("getFile"); - return await FileInProcess.CreateAsync(JSRuntime, jSFile); + return await FileInProcess.CreateAsync(JSRuntime, jSFile, new() + { + DisposesJSReference = true + }); } /// From 75d1a16ee939929346a5dde726b6e4be3a18bc15 Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Tue, 16 Sep 2025 22:46:10 +0200 Subject: [PATCH 08/14] Updated all wrappers with fileSystemOptions to have CreateAsync overload that includes both creation options and file system options. --- .../BaseJSWrapper.cs | 22 +++++++---- .../FileSystemDirectoryHandle.InProcess.cs | 38 ++++++++++++------- .../FileSystemDirectoryHandle.cs | 35 +++++++++++------ .../FileSystemFileHandle.InProcess.cs | 20 +++++++++- .../FileSystemFileHandle.cs | 19 +++++++++- .../FileSystemHandle.InProcess.cs | 20 +++++++++- .../FileSystemHandle.cs | 19 +++++++++- .../FileSystemWritableFileStream.cs | 1 - .../IStorageManagerService.InProcess.cs | 11 +++++- .../IStorageManagerService.cs | 2 +- .../Options/FileSystemOptions.cs | 2 +- .../StorageManagerService.InProcess.cs | 20 +++++----- .../StorageManagerService.cs | 6 +-- 13 files changed, 159 insertions(+), 56 deletions(-) diff --git a/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs b/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs index eddbc55..0af6963 100644 --- a/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs +++ b/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs @@ -5,20 +5,25 @@ namespace KristofferStrube.Blazor.FileSystem; /// -/// Base class for wrapping objects in the Blazor.WebAudio library. +/// Base class for wrapping objects in the Blazor.FileSystem library. /// -[IJSWrapperConverter] public abstract class BaseJSWrapper : IAsyncDisposable, IJSWrapper { /// - /// A lazily evaluated task that gives access to helper methods. + /// A lazily evaluated JS module that gives access to helper methods. /// protected readonly Lazy> helperTask; /// - /// Options for where it will find the script file that it needs to make complex JSInterop. + /// Options for where the helper JS module is located. /// - public FileSystemOptions FileSystemOptions { get; set; } + protected readonly FileSystemOptions fileSystemOptions; + + /// + /// Options for where the helper JS module is located. + /// + [Obsolete("This is here for backwards compatibility. It was replaced by 'fileSystemOptions' as 'options' was ambiguous.")] + protected readonly FileSystemOptions options; /// public IJSRuntime JSRuntime { get; } @@ -30,9 +35,12 @@ public abstract class BaseJSWrapper : IAsyncDisposable, IJSWrapper public bool DisposesJSReference { get; } /// - protected BaseJSWrapper(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) + internal BaseJSWrapper(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) { - FileSystemOptions = fileSystemOptions; + this.fileSystemOptions = fileSystemOptions; +#pragma warning disable CS0618 // Type or member is obsolete + this.options = fileSystemOptions; +#pragma warning restore CS0618 // Type or member is obsolete helperTask = new(async () => await jSRuntime.GetHelperAsync(fileSystemOptions)); JSReference = jSReference; JSRuntime = jSRuntime; diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs index 33e3b7a..21b3f03 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs @@ -33,13 +33,31 @@ public static async Task CreateAsync(IJSRunt return new FileSystemDirectoryHandleInProcess(jSRuntime, inProcessHelper, jSReference, FileSystemOptions.DefaultInstance, options); } - /// + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions options) { IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(options); return new FileSystemDirectoryHandleInProcess(jSRuntime, inProcessHelper, jSReference, options, new() { DisposesJSReference = true }); } + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at and whether its JS reference should be disposed. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. + /// Options for what path the JS helper module will be found at. + public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions creationOptions) + { + IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(fileSystemOptions); + return new FileSystemDirectoryHandleInProcess(jSRuntime, inProcessHelper, jSReference, fileSystemOptions, creationOptions); + } + /// protected FileSystemDirectoryHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) : base(jSRuntime, jSReference, fileSystemOptions, options) { @@ -68,27 +86,23 @@ protected FileSystemDirectoryHandleInProcess(IJSRuntime jSRuntime, IJSInProcessO FileSystemHandleInProcess fileSystemHandle = await FileSystemHandleInProcess.CreateAsync( JSRuntime, await jSEntries.InvokeAsync("at", i), - FileSystemOptions); + fileSystemOptions); FileSystemHandleKind kind = await fileSystemHandle.GetKindAsync(); if (kind is FileSystemHandleKind.File) { - FileSystemFileHandleInProcess instance = await FileSystemFileHandleInProcess.CreateAsync(JSRuntime, fileSystemHandle.JSReference, new CreationOptions() + return await FileSystemFileHandleInProcess.CreateAsync(JSRuntime, fileSystemHandle.JSReference, fileSystemOptions, new CreationOptions() { DisposesJSReference = true }); - instance.FileSystemOptions = FileSystemOptions; - return instance; } else { - FileSystemDirectoryHandleInProcess instance = await CreateAsync(JSRuntime, fileSystemHandle.JSReference, new CreationOptions() + return await CreateAsync(JSRuntime, fileSystemHandle.JSReference, new CreationOptions() { DisposesJSReference = true }); - instance.FileSystemOptions = FileSystemOptions; - return instance; } } ) @@ -100,24 +114,20 @@ await jSEntries.InvokeAsync("at", i), public new async Task GetFileHandleAsync(string name, FileSystemGetFileOptions? options = null) { IJSInProcessObjectReference jSFileSystemFileHandle = await JSReference.InvokeAsync("getFileHandle", name, options); - FileSystemFileHandleInProcess instance = await FileSystemFileHandleInProcess.CreateAsync(JSRuntime, jSFileSystemFileHandle, new CreationOptions() + return await FileSystemFileHandleInProcess.CreateAsync(JSRuntime, jSFileSystemFileHandle, fileSystemOptions, new CreationOptions() { DisposesJSReference = true }); - instance.FileSystemOptions = FileSystemOptions; - return instance; } /// public new async Task GetDirectoryHandleAsync(string name, FileSystemGetDirectoryOptions? options = null) { IJSInProcessObjectReference jSFileSystemFileHandle = await JSReference.InvokeAsync("getDirectoryHandle", name, options); - FileSystemDirectoryHandleInProcess instance = await CreateAsync(JSRuntime, jSFileSystemFileHandle, new CreationOptions() + return await CreateAsync(JSRuntime, jSFileSystemFileHandle, fileSystemOptions, new CreationOptions() { DisposesJSReference = true }); - instance.FileSystemOptions = FileSystemOptions; - return instance; } /// diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.cs index dd63718..a0dd5d4 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.cs @@ -22,12 +22,29 @@ public class FileSystemDirectoryHandle : FileSystemHandle, IJSCreatable + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. public static new Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) { return Task.FromResult(new FileSystemDirectoryHandle(jSRuntime, jSReference, options, new() { DisposesJSReference = true })); } + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at and whether its JS reference should be disposed. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. + /// Options for what path the JS helper module will be found at. + public static new Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions creationOptions) + { + return Task.FromResult(new FileSystemDirectoryHandle(jSRuntime, jSReference, fileSystemOptions, creationOptions)); + } + /// [Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")] public static new FileSystemDirectoryHandle Create(IJSRuntime jSRuntime, IJSObjectReference jSReference) @@ -61,27 +78,23 @@ public async Task ValuesAsync() { await using FileSystemHandle fileSystemHandle = await FileSystemHandle.CreateAsync( JSRuntime, - await jSEntries.InvokeAsync("at", i), FileSystemOptions); + await jSEntries.InvokeAsync("at", i), fileSystemOptions); FileSystemHandleKind kind = await fileSystemHandle.GetKindAsync(); if (kind is FileSystemHandleKind.File) { - FileSystemFileHandle instance = await FileSystemFileHandle.CreateAsync(JSRuntime, fileSystemHandle.JSReference, new CreationOptions() + return await FileSystemFileHandle.CreateAsync(JSRuntime, fileSystemHandle.JSReference, fileSystemOptions, new CreationOptions() { DisposesJSReference = true }); - instance.FileSystemOptions = FileSystemOptions; - return instance; } else { - FileSystemDirectoryHandle instance = await CreateAsync(JSRuntime, fileSystemHandle.JSReference, new CreationOptions() + return await CreateAsync(JSRuntime, fileSystemHandle.JSReference, fileSystemOptions, new CreationOptions() { DisposesJSReference = true }); - instance.FileSystemOptions = FileSystemOptions; - return instance; } } ) @@ -105,9 +118,7 @@ public async Task ValuesAsync() public async Task GetFileHandleAsync(string name, FileSystemGetFileOptions? options = null) { IJSObjectReference jSFileSystemFileHandle = await JSReference.InvokeAsync("getFileHandle", name, options); - FileSystemFileHandle file = await FileSystemFileHandle.CreateAsync(JSRuntime, jSFileSystemFileHandle, new CreationOptions() { DisposesJSReference = true }); - file.FileSystemOptions = FileSystemOptions; - return file; + return await FileSystemFileHandle.CreateAsync(JSRuntime, jSFileSystemFileHandle, fileSystemOptions, new CreationOptions() { DisposesJSReference = true }); } /// @@ -126,7 +137,7 @@ public async Task GetFileHandleAsync(string name, FileSyst public async Task GetDirectoryHandleAsync(string name, FileSystemGetDirectoryOptions? options = null) { IJSObjectReference jSFileSystemDirectoryHandle = await JSReference.InvokeAsync("getDirectoryHandle", name, options); - return new(JSRuntime, jSFileSystemDirectoryHandle, FileSystemOptions, new() { DisposesJSReference = true }); + return new(JSRuntime, jSFileSystemDirectoryHandle, fileSystemOptions, new() { DisposesJSReference = true }); } /// diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs index 4591b8a..b92b4d6 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs @@ -34,13 +34,31 @@ public static async Task CreateAsync(IJSRuntime j return new FileSystemFileHandleInProcess(jSRuntime, inProcessHelper, jSReference, FileSystemOptions.DefaultInstance, options); } - /// + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions options) { IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(options); return new FileSystemFileHandleInProcess(jSRuntime, inProcessHelper, jSReference, options, new() { DisposesJSReference = true }); } + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at and whether its JS reference should be disposed. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. + /// Options for what path the JS helper module will be found at. + public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions creationOptions) + { + IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(fileSystemOptions); + return new FileSystemFileHandleInProcess(jSRuntime, inProcessHelper, jSReference, fileSystemOptions, creationOptions); + } + /// protected FileSystemFileHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) : base(jSRuntime, jSReference, fileSystemOptions, options) { diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs index 461ff2d..449aa49 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs @@ -23,12 +23,29 @@ public class FileSystemFileHandle : FileSystemHandle, IJSCreatable + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. public static new Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) { return Task.FromResult(new FileSystemFileHandle(jSRuntime, jSReference, options, new() { DisposesJSReference = true })); } + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at and whether its JS reference should be disposed. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. + /// Options for what path the JS helper module will be found at. + public static new Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions creationOptions) + { + return Task.FromResult(new FileSystemFileHandle(jSRuntime, jSReference, fileSystemOptions, creationOptions)); + } + /// [Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")] public static new FileSystemFileHandle Create(IJSRuntime jSRuntime, IJSObjectReference jSReference) diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs index 633b328..185b13d 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs @@ -30,13 +30,31 @@ public static async Task CreateAsync(IJSRuntime jSRun return new FileSystemHandleInProcess(jSRuntime, inProcessHelper, jSReference, FileSystemOptions.DefaultInstance, options); } - /// + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions options) { IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(options); return new FileSystemHandleInProcess(jSRuntime, inProcessHelper, jSReference, options, new() { DisposesJSReference = true }); } + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at and whether its JS reference should be disposed. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. + /// Options for what path the JS helper module will be found at. + public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions creationOptions) + { + IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(fileSystemOptions); + return new FileSystemHandleInProcess(jSRuntime, inProcessHelper, jSReference, fileSystemOptions, creationOptions); + } + /// protected FileSystemHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) : base(jSRuntime, jSReference, fileSystemOptions, options) { diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.cs index 7de584c..76fb10b 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.cs @@ -19,12 +19,29 @@ public static Task CreateAsync(IJSRuntime jSRuntime, IJSObject return Task.FromResult(new FileSystemHandle(jSRuntime, jSReference, FileSystemOptions.DefaultInstance, options)); } - /// + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. public static Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) { return Task.FromResult(new FileSystemHandle(jSRuntime, jSReference, options, new() { DisposesJSReference = true })); } + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at and whether its JS reference should be disposed. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. + /// Options for what path the JS helper module will be found at. + public static Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions creationOptions) + { + return Task.FromResult(new FileSystemHandle(jSRuntime, jSReference, fileSystemOptions, creationOptions)); + } + /// [Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")] public static FileSystemHandle Create(IJSRuntime jSRuntime, IJSObjectReference jSReference) diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs index 922c4bf..aa611fb 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs @@ -125,7 +125,6 @@ public async Task WriteAsync(ByteArrayWriteParams data) /// Updates the current file cursor offset the position bytes from the top of the file. /// /// The new cursor position - /// public async Task SeekAsync(ulong position) { Position = (long)position; diff --git a/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.InProcess.cs index 35f2f47..447ca95 100644 --- a/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.InProcess.cs @@ -5,6 +5,15 @@ /// public interface IStorageManagerServiceInProcess : IStorageManagerService { - /// + /// + /// Gets a that is a local bucket for the current domain. It is persistent across sessions. + /// public new Task GetOriginPrivateDirectoryAsync(); + + /// + /// + /// This overload has explicit options for how you want to import the JS helper module used in the library. + /// + /// Options for how the wrapper should construct its JS helper module + public new Task GetOriginPrivateDirectoryAsync(FileSystemOptions options); } \ No newline at end of file diff --git a/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.cs b/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.cs index 0486126..9291a2c 100644 --- a/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.cs +++ b/src/KristofferStrube.Blazor.FileSystem/IStorageManagerService.cs @@ -15,6 +15,6 @@ public interface IStorageManagerService /// /// This overload has explicit options for how you want to import the JS helper module used in the library. /// - /// Options for how the directory should construct its JS helper module + /// Options for how the wrapper should construct its JS helper module public Task GetOriginPrivateDirectoryAsync(FileSystemOptions options); } \ No newline at end of file diff --git a/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemOptions.cs b/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemOptions.cs index 61c87e1..bdbab79 100644 --- a/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemOptions.cs +++ b/src/KristofferStrube.Blazor.FileSystem/Options/FileSystemOptions.cs @@ -3,7 +3,7 @@ namespace KristofferStrube.Blazor.FileSystem; /// -/// Options for what path the JS Helper module will be found at. +/// Options for what path the JS helper module will be found at. /// public class FileSystemOptions { diff --git a/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.InProcess.cs index 65055a0..1fc9861 100644 --- a/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.InProcess.cs @@ -1,32 +1,30 @@ +using KristofferStrube.Blazor.WebIDL; using Microsoft.JSInterop; namespace KristofferStrube.Blazor.FileSystem; -/// +/// public class StorageManagerServiceInProcess : StorageManagerService, IStorageManagerServiceInProcess { /// - /// Creates a + /// Creates the service. /// /// An instance. public StorageManagerServiceInProcess(IJSRuntime jSRuntime) : base(jSRuntime) { } - /// - /// getDirectory() for StorageManager browser specs - /// - /// + /// public new async Task GetOriginPrivateDirectoryAsync() { return await GetOriginPrivateDirectoryAsync(FileSystemOptions.DefaultInstance); } - /// - /// getDirectory() for StorageManager browser specs - /// - /// + /// public new async Task GetOriginPrivateDirectoryAsync(FileSystemOptions options) { IJSInProcessObjectReference directoryHandle = await jSRuntime.InvokeAsync("navigator.storage.getDirectory"); - return await FileSystemDirectoryHandleInProcess.CreateAsync(jSRuntime, directoryHandle, options); + return await FileSystemDirectoryHandleInProcess.CreateAsync(jSRuntime, directoryHandle, options, new CreationOptions() + { + DisposesJSReference = true + }); } } diff --git a/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs b/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs index 9782dc0..3fc334f 100644 --- a/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs +++ b/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs @@ -20,7 +20,7 @@ public class StorageManagerService : IStorageManagerService, IAsyncDisposable /// /// Creates the service. Should be a scoped service, especially when used in Blazor Server render mode. /// - /// + /// An instance. public StorageManagerService(IJSRuntime jSRuntime) { helperTask = new(() => jSRuntime.GetHelperAsync(FileSystemOptions.DefaultInstance)); @@ -37,12 +37,10 @@ public async Task GetOriginPrivateDirectoryAsync() public async Task GetOriginPrivateDirectoryAsync(FileSystemOptions options) { IJSObjectReference directoryHandle = await jSRuntime.InvokeAsync("navigator.storage.getDirectory"); - FileSystemDirectoryHandle instance = await FileSystemDirectoryHandle.CreateAsync(jSRuntime, directoryHandle, new CreationOptions() + return await FileSystemDirectoryHandle.CreateAsync(jSRuntime, directoryHandle, options, new CreationOptions() { DisposesJSReference = true }); - instance.FileSystemOptions = options; - return instance; } /// From 4db8e5bd4bb0571cfe6c1cbf0a9a999c02ea2eb5 Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Tue, 16 Sep 2025 22:54:55 +0200 Subject: [PATCH 09/14] Ensured less duplicated documentation for JS helper modules. --- src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs | 2 +- .../FileSystemDirectoryHandle.InProcess.cs | 4 +--- .../FileSystemFileHandle.InProcess.cs | 4 +--- .../FileSystemHandle.InProcess.cs | 2 +- .../FileSystemWritableFileStream.InProcess.cs | 4 +--- .../FileSystemWritableFileStream.cs | 4 +--- .../StorageManagerService.cs | 4 +--- 7 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs b/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs index 0af6963..4f53289 100644 --- a/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs +++ b/src/KristofferStrube.Blazor.FileSystem/BaseJSWrapper.cs @@ -10,7 +10,7 @@ namespace KristofferStrube.Blazor.FileSystem; public abstract class BaseJSWrapper : IAsyncDisposable, IJSWrapper { /// - /// A lazily evaluated JS module that gives access to helper methods. + /// A lazily evaluated JS module that gives access to helper methods for the File System API. /// protected readonly Lazy> helperTask; diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs index 21b3f03..3cc8bd1 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs @@ -15,9 +15,7 @@ public class FileSystemDirectoryHandleInProcess : FileSystemDirectoryHandle, IFi /// public new IJSInProcessObjectReference JSReference { get; set; } - /// - /// A lazily evaluated task that gives access to helper methods. - /// + /// protected readonly IJSInProcessObjectReference inProcessHelper; /// diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs index b92b4d6..18876f4 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs @@ -16,9 +16,7 @@ public class FileSystemFileHandleInProcess : FileSystemFileHandle, IFileSystemHa /// public new IJSInProcessObjectReference JSReference { get; set; } - /// - /// A lazily evaluated task that gives access to helper methods. - /// + /// protected readonly IJSInProcessObjectReference inProcessHelper; /// diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs index 185b13d..9581771 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs @@ -13,7 +13,7 @@ public class FileSystemHandleInProcess : FileSystemHandle, IFileSystemHandleInPr public new IJSInProcessObjectReference JSReference { get; set; } /// - /// A lazily evaluated task that gives access to helper methods. + /// A JS module that gives access to helper methods for the File System API. /// protected readonly IJSInProcessObjectReference inProcessHelper; diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs index f615518..6069592 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs @@ -13,9 +13,7 @@ public class FileSystemWritableFileStreamInProcess : FileSystemWritableFileStrea /// public new IJSInProcessObjectReference JSReference { get; } - /// - /// A lazily evaluated task that gives access to helper methods. - /// + /// protected readonly IJSInProcessObjectReference inProcessHelper; /// diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs index aa611fb..71845f5 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs @@ -14,9 +14,7 @@ namespace KristofferStrube.Blazor.FileSystem; [IJSWrapperConverter] public class FileSystemWritableFileStream : WritableStream, IJSCreatable { - /// - /// A lazily evaluated task that gives access to helper methods for the File System API. - /// + /// protected Lazy> FileSystemHelperTask { get; } /// diff --git a/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs b/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs index 3fc334f..dc3e642 100644 --- a/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs +++ b/src/KristofferStrube.Blazor.FileSystem/StorageManagerService.cs @@ -7,9 +7,7 @@ namespace KristofferStrube.Blazor.FileSystem; /// public class StorageManagerService : IStorageManagerService, IAsyncDisposable { - /// - /// A lazily evaluated task that gives access to helper methods. - /// + /// protected readonly Lazy> helperTask; /// From 7edf2e793644ec0c8e1b5a1c89747a62f233dd88 Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Tue, 16 Sep 2025 23:01:37 +0200 Subject: [PATCH 10/14] Corrected again. --- .../FileSystemDirectoryHandle.InProcess.cs | 2 +- .../FileSystemFileHandle.InProcess.cs | 2 +- .../FileSystemWritableFileStream.InProcess.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs index 3cc8bd1..08bbac2 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemDirectoryHandle.InProcess.cs @@ -15,7 +15,7 @@ public class FileSystemDirectoryHandleInProcess : FileSystemDirectoryHandle, IFi /// public new IJSInProcessObjectReference JSReference { get; set; } - /// + /// protected readonly IJSInProcessObjectReference inProcessHelper; /// diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs index 18876f4..7e84032 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs @@ -16,7 +16,7 @@ public class FileSystemFileHandleInProcess : FileSystemFileHandle, IFileSystemHa /// public new IJSInProcessObjectReference JSReference { get; set; } - /// + /// protected readonly IJSInProcessObjectReference inProcessHelper; /// diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs index 6069592..2398aa8 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs @@ -13,7 +13,7 @@ public class FileSystemWritableFileStreamInProcess : FileSystemWritableFileStrea /// public new IJSInProcessObjectReference JSReference { get; } - /// + /// protected readonly IJSInProcessObjectReference inProcessHelper; /// From 8be0f8d95f9423017275611c4ad535ab308342ed Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Tue, 16 Sep 2025 23:18:30 +0200 Subject: [PATCH 11/14] Ensured that we also use FileSystemOptions in FileSystemWritableFileStream types. --- .../FileSystemFileHandle.InProcess.cs | 2 +- .../FileSystemFileHandle.cs | 2 +- .../FileSystemWritableFileStream.InProcess.cs | 36 +++++++++++---- .../FileSystemWritableFileStream.cs | 45 ++++++++++++++----- 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs index 7e84032..eb59288 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.InProcess.cs @@ -84,7 +84,7 @@ protected FileSystemFileHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObject public new async Task CreateWritableAsync(FileSystemCreateWritableOptions? fileSystemCreateWritableOptions = null) { IJSInProcessObjectReference jSFileSystemWritableFileStream = await JSReference.InvokeAsync("createWritable", fileSystemCreateWritableOptions); - return new FileSystemWritableFileStreamInProcess(JSRuntime, inProcessHelper, jSFileSystemWritableFileStream, new() { DisposesJSReference = true }); + return await FileSystemWritableFileStreamInProcess.CreateAsync(JSRuntime, jSFileSystemWritableFileStream, fileSystemOptions, new() { DisposesJSReference = true }); } /// diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs index 449aa49..0e1ed7e 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemFileHandle.cs @@ -87,7 +87,7 @@ public async Task GetFileAsync() public async Task CreateWritableAsync(FileSystemCreateWritableOptions? fileSystemCreateWritableOptions = null) { IJSObjectReference jSFileSystemWritableFileStream = await JSReference.InvokeAsync("createWritable", fileSystemCreateWritableOptions); - return await FileSystemWritableFileStream.CreateAsync(JSRuntime, jSFileSystemWritableFileStream, new CreationOptions() + return await FileSystemWritableFileStream.CreateAsync(JSRuntime, jSFileSystemWritableFileStream, fileSystemOptions, new CreationOptions() { DisposesJSReference = true }); diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs index 2398aa8..0a630ba 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs @@ -16,13 +16,6 @@ public class FileSystemWritableFileStreamInProcess : FileSystemWritableFileStrea /// protected readonly IJSInProcessObjectReference inProcessHelper; - /// - public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions options) - { - IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(options); - return new FileSystemWritableFileStreamInProcess(jSRuntime, inProcessHelper, jSReference, new() { DisposesJSReference = true }); - } - /// public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference) { @@ -33,11 +26,36 @@ public static async Task CreateAsync(IJSR public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, CreationOptions options) { IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(FileSystemOptions.DefaultInstance); - return new FileSystemWritableFileStreamInProcess(jSRuntime, inProcessHelper, jSReference, options); + return new FileSystemWritableFileStreamInProcess(jSRuntime, inProcessHelper, jSReference, FileSystemOptions.DefaultInstance, options); + } + + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. + public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions options) + { + IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(options); + return new FileSystemWritableFileStreamInProcess(jSRuntime, inProcessHelper, jSReference, options, new() { DisposesJSReference = true }); + } + + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at and whether its JS reference should be disposed. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. + /// Options for what path the JS helper module will be found at. + public static async Task CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions creationOptions) + { + IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync(fileSystemOptions); + return new FileSystemWritableFileStreamInProcess(jSRuntime, inProcessHelper, jSReference, fileSystemOptions, creationOptions); } /// - protected internal FileSystemWritableFileStreamInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, CreationOptions options) : base(jSRuntime, jSReference, options) + protected FileSystemWritableFileStreamInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) : base(jSRuntime, jSReference, fileSystemOptions, options) { this.inProcessHelper = inProcessHelper; JSReference = jSReference; diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs index 71845f5..5dfb5cc 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.cs @@ -23,29 +23,52 @@ public class FileSystemWritableFileStream : WritableStream, IJSCreatable public override long Position { get; set; } - /// - [Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")] - public static new FileSystemWritableFileStream Create(IJSRuntime jSRuntime, IJSObjectReference jSReference) - { - return new FileSystemWritableFileStream(jSRuntime, jSReference, new() { DisposesJSReference = true }); - } - /// public static new async Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference) { - return await CreateAsync(jSRuntime, jSReference, new()); + return await CreateAsync(jSRuntime, jSReference, new CreationOptions()); } /// public static new Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, CreationOptions options) { - return Task.FromResult(new FileSystemWritableFileStream(jSRuntime, jSReference, options)); + return Task.FromResult(new FileSystemWritableFileStream(jSRuntime, jSReference, FileSystemOptions.DefaultInstance, options)); + } + + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. + public static Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions options) + { + return Task.FromResult(new FileSystemWritableFileStream(jSRuntime, jSReference, options, new() { DisposesJSReference = true })); + } + + /// + /// Constructs a wrapper instance for an equivalent JS instance of a with options for where the JS helper module will be found at and whether its JS reference should be disposed. + /// + /// An instance. + /// A JS reference to an existing JS instance that should be wrapped. + /// Options for what path the JS helper module will be found at. + /// Options for what path the JS helper module will be found at. + public static Task CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions creationOptions) + { + return Task.FromResult(new FileSystemWritableFileStream(jSRuntime, jSReference, fileSystemOptions, creationOptions)); + } + + /// + [Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")] + public static new FileSystemWritableFileStream Create(IJSRuntime jSRuntime, IJSObjectReference jSReference) + { + return new FileSystemWritableFileStream(jSRuntime, jSReference, FileSystemOptions.DefaultInstance, new() { DisposesJSReference = true }); } /// - protected FileSystemWritableFileStream(IJSRuntime jSRuntime, IJSObjectReference jSReference, CreationOptions options) : base(jSRuntime, jSReference, options) + protected FileSystemWritableFileStream(IJSRuntime jSRuntime, IJSObjectReference jSReference, FileSystemOptions fileSystemOptions, CreationOptions options) : base(jSRuntime, jSReference, options) { - FileSystemHelperTask = new(() => jSRuntime.GetHelperAsync(FileSystemOptions.DefaultInstance)); + FileSystemHelperTask = new(() => jSRuntime.GetHelperAsync(fileSystemOptions)); } /// From a9a3eafdc871d498169248a30bbd9e321072c02f Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Tue, 16 Sep 2025 23:22:41 +0200 Subject: [PATCH 12/14] Ensure that `FileSystemWritableFileStreamInProcess` is marked as `IJSWrapperConverter` and has correct summary for type. --- .../FileSystemWritableFileStream.InProcess.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs index 0a630ba..4449ac3 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemWritableFileStream.InProcess.cs @@ -1,13 +1,16 @@ using KristofferStrube.Blazor.DOM.Extensions; using KristofferStrube.Blazor.FileSystem.Extensions; +using KristofferStrube.Blazor.Streams; using KristofferStrube.Blazor.WebIDL; using Microsoft.JSInterop; namespace KristofferStrube.Blazor.FileSystem; /// -/// FileSystemWritableFileStream browser specs +/// An in-process that can write to and seek in a . /// +/// See the API definition here. +[IJSWrapperConverter] public class FileSystemWritableFileStreamInProcess : FileSystemWritableFileStream, IJSInProcessCreatable { /// From 147677a914e1f9ec6ceba7ad2ea9607fdaf0fd8d Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Tue, 16 Sep 2025 23:25:40 +0200 Subject: [PATCH 13/14] Use ref to interface in `FileSystemHandleInProcess` and interface. --- .../FileSystemHandle.InProcess.cs | 2 +- .../IFileSystemHandle.InProcess.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs index 9581771..3212b7b 100644 --- a/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/FileSystemHandle.InProcess.cs @@ -65,7 +65,7 @@ protected FileSystemHandleInProcess(IJSRuntime jSRuntime, IJSInProcessObjectRefe /// public FileSystemHandleKind Kind => inProcessHelper.Invoke("getAttribute", JSReference, "kind"); - /// + /// public string Name => inProcessHelper.Invoke("getAttribute", JSReference, "name"); /// diff --git a/src/KristofferStrube.Blazor.FileSystem/IFileSystemHandle.InProcess.cs b/src/KristofferStrube.Blazor.FileSystem/IFileSystemHandle.InProcess.cs index f8433d8..bac9687 100644 --- a/src/KristofferStrube.Blazor.FileSystem/IFileSystemHandle.InProcess.cs +++ b/src/KristofferStrube.Blazor.FileSystem/IFileSystemHandle.InProcess.cs @@ -6,9 +6,9 @@ /// See the API definition here. public interface IFileSystemHandleInProcess : IFileSystemHandle { - /// + /// public FileSystemHandleKind Kind { get; } - /// + /// public string Name { get; } } \ No newline at end of file From d763cb8cc24815c991bed302c9bda9b6ccda0b62 Mon Sep 17 00:00:00 2001 From: KristofferStrube Date: Tue, 16 Sep 2025 23:33:50 +0200 Subject: [PATCH 14/14] Updated readme while we are at it as they simply corrected a mistake in their web-idl specification. --- .../Pages/Status.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/KristofferStrube.Blazor.FileSystem.WasmExample/Pages/Status.razor b/samples/KristofferStrube.Blazor.FileSystem.WasmExample/Pages/Status.razor index 1a8cad1..9997dd4 100644 --- a/samples/KristofferStrube.Blazor.FileSystem.WasmExample/Pages/Status.razor +++ b/samples/KristofferStrube.Blazor.FileSystem.WasmExample/Pages/Status.razor @@ -103,7 +103,7 @@ dictionary FileSystemRemoveOptions { [Exposed=(Window,Worker), SecureContext, Serializable] interface FileSystemDirectoryHandle : FileSystemHandle { - async iterable; + async_iterable; Promise getFileHandle(USVString name, optional FileSystemGetFileOptions options = {}); Promise getDirectoryHandle(USVString name, optional FileSystemGetDirectoryOptions options = {});