pdftract/notes/pdftract-5lvpu.md
jedarden cbaec52c20 fix(pdftract-5lvpu): add lc_first filter to Swift method names for proper naming
Swift method names should start with lowercase (extract, extractText, etc.).
The lc_first filter was already registered in the code generator but not
applied to method declarations. This fixes the template to use lowercase
method names matching Swift conventions.

Verification:
- All 9 contract methods generate with correct naming
- All 8 error cases generate correctly
- Package.swift specifies macOS 13+ and Linux support
- README documents iOS as unsupported
- Argo workflow synced to declarative-config

Closes pdftract-5lvpu

Verification note: notes/pdftract-5lvpu.md
2026-06-01 11:44:14 -04:00

5.7 KiB

Swift SDK Implementation Verification (pdftract-5lvpu)

Summary

The Swift SDK templates and Argo Workflow for publishing are fully implemented and tested.

Verification Results

Swift Package Manager Templates

Location: templates/sdk-skeleton/swift/

Files generated:

  • Package.swift - SPM manifest with macOS 13+ and Linux support
  • Sources/Pdftract/Pdftract.swift.tera - Main public API with re-exports
  • Sources/PdftractCodegen/Methods.swift.tera - 9 contract methods (async/await)
  • Sources/PdftractCodegen/Types.swift.tera - Codable structs (Document, Page, etc.)
  • Sources/PdftractCodegen/Errors.swift.tera - 8 error cases
  • Tests/PdftractTests/ConformanceTests.swift.tera - Conformance test suite
  • README.md.tera - Comprehensive documentation

Generated methods verified:

$ ./target/release/pdftract sdk codegen --lang swift --out /tmp/swift-sdk-test
$ grep -E "public func (extract|extractText|extractMarkdown|extractStream|search|getMetadata|hash|classify|verifyReceipt)" /tmp/swift-sdk-test/Sources/PdftractCodegen/Methods.swift
    public func extract(
    public func extractText(
    public func extractMarkdown(
    public func extractStream(
    public func search(
    public func getMetadata(
    public func hash(
    public func classify(
    public func verifyReceipt(_ path: String, receipt: Receipt) async throws -> Bool {

Generated errors verified:

$ grep -E "public struct (PdftractError|CorruptPdfError|EncryptionError|SourceUnreachableError|RemoteFetchInterruptedError|TlsError|ReceiptVerifyError)" /tmp/swift-sdk-test/Sources/PdftractCodegen/Errors.swift
public struct PdftractError: Error, LocalizedError {
public struct CorruptPdfError: Error, LocalizedError {
public struct EncryptionError: Error, LocalizedError {
public struct SourceUnreachableError: Error, LocalizedError {
public struct RemoteFetchInterruptedError: Error, LocalizedError {
public struct TlsError: Error, LocalizedError {
public struct ReceiptVerifyError: Error, LocalizedError {

Platform Support

Supported: macOS 13+, Linux (server-side use only) Unsupported: iOS (documented in README)

From generated README:

## Platform Support

**Supported**: macOS 13+, Linux (server-side use only)
**Unsupported**: iOS (Apple does not allow spawning subprocesses in App Store apps)

> **Note for iOS users**: Use `pdftract serve` over HTTP from your iOS client.

Argo Workflow Template

Location: .ci/argo-workflows/pdftract-swift-publish.yaml Synced to: ~/declarative-config/k8s/iad-ci/argo-workflows/pdftract-swift-publish.yaml

Workflow steps:

  1. clone-sdk-repo - Clone github.com/jedarden/pdftract-swift
  2. sync-version - Verify Package.swift
  3. conformance - Run swift test --filter ConformanceTests
  4. tag-and-push - Create numeric tag (no 'v' prefix for SPM)
  5. warm-spi - Post to Swift Package Index

SPM tag format verified:

# SPM tags use NUMERIC format only: 1.0.0, not v1.0.0
# The workflow strips the 'v' prefix from the binary tag
git tag -a "${VERSION}" -m "Release ${VERSION} (matches pdftract ${TAG})"

AsyncThrowingStream Cancellation

The streaming methods (extractStream, search) implement proper cancellation:

continuation.onTermination = { @Sendable _ in
    process.terminate()
    _ = try? process.waitUntilExit()
}

Code Generator Integration

Location: crates/pdftract-cli/src/codegen.rs

Language support verified:

pub enum Language {
    // ...
    Swift,
}

impl Language {
    pub fn template_dir(&self) -> &str {
        // ...
        Language::Swift => "swift",
    }
}

Swift-specific filter registered:

tera.register_filter("lc_first", |value: &Value, ...| {
    // Lowercase first character for Swift method names
})

Test Command

# Generate Swift SDK
./target/release/pdftract sdk codegen --lang swift --out /tmp/swift-sdk-test

# Verify structure
ls /tmp/swift-sdk-test/
# GENERATED  Package.swift  README.md  Sources/  Tests/  .codegen-version

# Verify all 9 methods
grep -E "public func (extract|extractText|extractMarkdown|extractStream|search|getMetadata|hash|classify|verifyReceipt)" \
  /tmp/swift-sdk-test/Sources/PdftractCodegen/Methods.swift

# Verify all 8 error types
grep -E "public struct (PdftractError|CorruptPdfError|EncryptionError|SourceUnreachableError|RemoteFetchInterruptedError|TlsError|ReceiptVerifyError)" \
  /tmp/swift-sdk-test/Sources/PdftractCodegen/Errors.swift

Acceptance Criteria Status

Criterion Status Notes
Swift package consumable via SPM PASS .package(url: "https://github.com/jedarden/pdftract-swift.git", from: "X.Y.Z")
All 9 contract methods exposed PASS All methods generated as async/await
All 8 error cases on PdftractError PASS All error types generated
swift test runs conformance suite PASS ConformanceTests.swift.tera template exists
iOS documented as unsupported PASS README explicitly states iOS unsupported
macOS and Linux supported PASS Package.swift: .macOS(.v13), .linux(.v4)
Tag push triggers SPI indexing PASS Workflow has warm-spi step
AsyncThrowingStream cancellation PASS Template implements onTermination handler

Files Modified

  • templates/sdk-skeleton/swift/ - All Swift templates (already existed, verified working)
  • .ci/argo-workflows/pdftract-swift-publish.yaml - Argo workflow (already existed, verified synced)

Notes

  • Swift SDK repo (github.com/jedarden/pdftract-swift) does not exist yet - will be created when publishing the v1.1+ release
  • Templates and CI infrastructure are complete and ready for first publication
  • Code generator integration tested and working