From 5ebf7059ae5fb34045fa7904dae3630fe586432d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ng=C3=B4=20Qu=E1=BB=91c=20=C4=90=E1=BA=A1t?= Date: Tue, 19 May 2026 12:52:51 +0700 Subject: [PATCH 1/2] fix(plugins): register all SQLite file extensions end-to-end (#1327) --- CHANGELOG.md | 1 + Plugins/SQLiteDriverPlugin/SQLitePlugin.swift | 2 +- TablePro/Core/Plugins/PluginMetadataRegistry.swift | 2 +- TablePro/Info.plist | 2 ++ TableProMobile/TableProMobile/Views/ConnectionFormView.swift | 3 ++- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21128e6b0..ee3cc5ee7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - DuckDB schema reads handle apostrophes and concurrent schema switches correctly - DuckDB ENUMs in non-`main` schemas resolve correctly - DuckDB `DATE` and `TIMESTAMP` BC years use a leading minus +- `.db`, `.db3`, `.s3db`, `.sl3`, and `.sqlitedb` files now open in TablePro from Finder (#1327) ## [0.43.0] - 2026-05-18 diff --git a/Plugins/SQLiteDriverPlugin/SQLitePlugin.swift b/Plugins/SQLiteDriverPlugin/SQLitePlugin.swift index 9875ebe22..dccde405b 100644 --- a/Plugins/SQLiteDriverPlugin/SQLitePlugin.swift +++ b/Plugins/SQLiteDriverPlugin/SQLitePlugin.swift @@ -32,7 +32,7 @@ final class SQLitePlugin: NSObject, TableProPlugin, DriverPlugin { static let pathFieldRole: PathFieldRole = .filePath static let connectionMode: ConnectionMode = .fileBased static let urlSchemes: [String] = ["sqlite"] - static let fileExtensions: [String] = ["db", "sqlite", "sqlite3"] + static let fileExtensions: [String] = ["db", "db3", "s3db", "sl3", "sqlite", "sqlite3", "sqlitedb"] static let brandColorHex = "#003B57" static let supportsDatabaseSwitching = false static let databaseGroupingStrategy: GroupingStrategy = .flat diff --git a/TablePro/Core/Plugins/PluginMetadataRegistry.swift b/TablePro/Core/Plugins/PluginMetadataRegistry.swift index 2a2fef040..a3bf977a0 100644 --- a/TablePro/Core/Plugins/PluginMetadataRegistry.swift +++ b/TablePro/Core/Plugins/PluginMetadataRegistry.swift @@ -709,7 +709,7 @@ final class PluginMetadataRegistry: @unchecked Sendable { immutableColumns: [], systemDatabaseNames: [], systemSchemaNames: [], - fileExtensions: ["db", "sqlite", "sqlite3"], + fileExtensions: ["db", "db3", "s3db", "sl3", "sqlite", "sqlite3", "sqlitedb"], databaseGroupingStrategy: .flat, structureColumnFields: [.name, .type, .nullable, .defaultValue, .autoIncrement, .comment] ), diff --git a/TablePro/Info.plist b/TablePro/Info.plist index 024a846af..337c11170 100644 --- a/TablePro/Info.plist +++ b/TablePro/Info.plist @@ -52,6 +52,7 @@ sqlite sqlite3 + db db3 s3db sl3 @@ -174,6 +175,7 @@ sqlite sqlite3 + db db3 s3db sl3 diff --git a/TableProMobile/TableProMobile/Views/ConnectionFormView.swift b/TableProMobile/TableProMobile/Views/ConnectionFormView.swift index e042797a9..94052dc63 100644 --- a/TableProMobile/TableProMobile/Views/ConnectionFormView.swift +++ b/TableProMobile/TableProMobile/Views/ConnectionFormView.swift @@ -385,6 +385,7 @@ struct ConnectionFormView: View { // MARK: - Helpers private var sqliteContentTypes: [UTType] { - [UTType.database, UTType(filenameExtension: "sqlite3") ?? .data, .data] + let extensions = ["db", "db3", "s3db", "sl3", "sqlite", "sqlite3", "sqlitedb"] + return [UTType.database] + extensions.compactMap { UTType(filenameExtension: $0) } + [.data] } } From aa46315078e653bf58b918e7e24a433e100b4db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ng=C3=B4=20Qu=E1=BB=91c=20=C4=90=E1=BA=A1t?= Date: Tue, 19 May 2026 12:58:25 +0700 Subject: [PATCH 2/2] refactor(plugins): align Info.plist extension order and lower SQLite handler rank --- TablePro/Info.plist | 10 +++---- .../Plugins/SQLiteFileExtensionsTests.swift | 28 +++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 TableProTests/Plugins/SQLiteFileExtensionsTests.swift diff --git a/TablePro/Info.plist b/TablePro/Info.plist index 337c11170..fe3c5d7ae 100644 --- a/TablePro/Info.plist +++ b/TablePro/Info.plist @@ -50,12 +50,12 @@ CFBundleTypeExtensions - sqlite - sqlite3 db db3 s3db sl3 + sqlite + sqlite3 sqlitedb CFBundleTypeName @@ -63,7 +63,7 @@ CFBundleTypeRole Editor LSHandlerRank - Default + Alternate LSItemContentTypes com.apple.sqlite3 @@ -173,12 +173,12 @@ public.filename-extension - sqlite - sqlite3 db db3 s3db sl3 + sqlite + sqlite3 sqlitedb diff --git a/TableProTests/Plugins/SQLiteFileExtensionsTests.swift b/TableProTests/Plugins/SQLiteFileExtensionsTests.swift new file mode 100644 index 000000000..9f87680ce --- /dev/null +++ b/TableProTests/Plugins/SQLiteFileExtensionsTests.swift @@ -0,0 +1,28 @@ +// +// SQLiteFileExtensionsTests.swift +// TableProTests +// + +import Foundation +@testable import TablePro +import Testing + +@MainActor +@Suite("SQLite file extension registration") +struct SQLiteFileExtensionsTests { + private static let canonical: [String] = ["db", "db3", "s3db", "sl3", "sqlite", "sqlite3", "sqlitedb"] + + @Test("Plugin metadata registry exposes the canonical SQLite extensions") + func registryHasCanonicalExtensions() throws { + let snapshot = try #require(PluginMetadataRegistry.shared.snapshot(forTypeId: "SQLite")) + #expect(snapshot.schema.fileExtensions.sorted() == Self.canonical.sorted()) + } + + @Test("URLClassifier resolves every canonical extension to the SQLite database type") + func urlClassifierResolvesEveryExtension() { + let extensionMap = PluginManager.shared.allRegisteredFileExtensions + for ext in Self.canonical { + #expect(extensionMap[ext] != nil, "extension \(ext) is not registered") + } + } +}