From 3c06b4c698bd9d596a6cdf8e9b71f39a2ffa881c Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Sun, 18 Oct 2026 13:19:12 +0700 Subject: [PATCH] fix(plugins): offer Parquet in Export until the manifest lists it --- .../Services/Export/ExportFormatCatalog.swift | 13 ++++- .../Export/ExportFormatCatalogTests.swift | 47 ++++++++++++++----- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/TablePro/Core/Services/Export/ExportFormatCatalog.swift b/TablePro/Core/Services/Export/ExportFormatCatalog.swift index afb640bcf6..f1ee56830a 100644 --- a/TablePro/Core/Services/Export/ExportFormatCatalog.swift +++ b/TablePro/Core/Services/Export/ExportFormatCatalog.swift @@ -12,12 +12,23 @@ internal enum ExportFormatCatalog { "csv", "json", "sql", "xlsx", "md", "parquet", "mql" ] + // scripts/release/registry.py writes no exportFormatIds yet, so Parquet stays offered by hand until it does. + private static let unlistedInstallable = [ + InstallableExportFormat( + formatId: "parquet", + displayName: "Parquet", + registryPluginId: "com.TablePro.ParquetExportPlugin" + ) + ] + internal static func installable(in manifest: RegistryManifest?) -> [InstallableExportFormat] { - (manifest?.plugins ?? []).flatMap { plugin in + let listed = (manifest?.plugins ?? []).flatMap { plugin in (plugin.exportFormatIds ?? []).map { formatId in InstallableExportFormat(formatId: formatId, displayName: plugin.name, registryPluginId: plugin.id) } } + let listedFormatIds = Set(listed.map(\.formatId)) + return listed + unlistedInstallable.filter { !listedFormatIds.contains($0.formatId) } } @MainActor diff --git a/TableProTests/Core/Export/ExportFormatCatalogTests.swift b/TableProTests/Core/Export/ExportFormatCatalogTests.swift index 9335d7627b..3a89827314 100644 --- a/TableProTests/Core/Export/ExportFormatCatalogTests.swift +++ b/TableProTests/Core/Export/ExportFormatCatalogTests.swift @@ -128,22 +128,45 @@ struct ExportFormatCatalogTests { ) } - @Test("The manifest's export-format ids are what the catalog offers to install") + private let handParquet = InstallableExportFormat( + formatId: "parquet", + displayName: "Parquet", + registryPluginId: "com.TablePro.ParquetExportPlugin" + ) + + @Test("Parquet is offered while the manifest names no export format") @MainActor - func installableComesFromTheManifest() { - let listed = manifest([ + func parquetOfferedWithoutManifestFormats() { + let unlisted = manifest([ registryPlugin(id: "com.TablePro.OracleDriver", name: "Oracle Driver", exportFormatIds: nil), - registryPlugin(id: "com.TablePro.ParquetExportPlugin", name: "Parquet Export", exportFormatIds: ["parquet"]) + registryPlugin(id: "com.TablePro.ParquetExportPlugin", name: "Parquet Export", exportFormatIds: nil) ]) - #expect(ExportFormatCatalog.installable(in: listed) == [ - InstallableExportFormat( - formatId: "parquet", - displayName: "Parquet Export", - registryPluginId: "com.TablePro.ParquetExportPlugin" - ) + #expect(ExportFormatCatalog.installable(in: nil) == [handParquet]) + #expect(ExportFormatCatalog.installable(in: unlisted) == [handParquet]) + #expect(ExportFormatCatalog.notInstalled(installedFormatIds: [], manifest: nil) == [handParquet]) + #expect(ExportFormatCatalog.notInstalled(installedFormatIds: ["parquet"], manifest: nil).isEmpty) + } + + @Test("A format the manifest lists is offered once, from the manifest") + @MainActor + func manifestFormatsReplaceTheHandEntry() { + let listed = manifest([ + registryPlugin(id: "com.TablePro.ParquetExportPlugin", name: "Parquet Export", exportFormatIds: ["parquet"]), + registryPlugin(id: "com.example.AvroExport", name: "Avro Export", exportFormatIds: ["avro"]) ]) - #expect(ExportFormatCatalog.notInstalled(installedFormatIds: ["parquet"], manifest: listed).isEmpty) - #expect(ExportFormatCatalog.notInstalled(installedFormatIds: [], manifest: nil).isEmpty) + let parquet = InstallableExportFormat( + formatId: "parquet", + displayName: "Parquet Export", + registryPluginId: "com.TablePro.ParquetExportPlugin" + ) + let avro = InstallableExportFormat( + formatId: "avro", + displayName: "Avro Export", + registryPluginId: "com.example.AvroExport" + ) + + #expect(ExportFormatCatalog.installable(in: listed) == [parquet, avro]) + #expect(ExportFormatCatalog.notInstalled(installedFormatIds: ["parquet"], manifest: listed) == [avro]) } }