From ad8847e652596e6832965067016476c35150ceaf Mon Sep 17 00:00:00 2001 From: Etherlink Intern Date: Mon, 1 Jun 2026 01:58:24 +0800 Subject: [PATCH] Add runnable iOS demo app --- .github/workflows/ci.yml | 34 ++ App/SwiftMarkItDownApp/ContentView.swift | 140 +++++++ .../SwiftMarkItDownApp.swift | 10 + README.md | 50 ++- Scripts/smoke-test.sh | 31 ++ .../Converters/HTMLConverter.swift | 4 + SwiftMarkItDownApp.xcodeproj/project.pbxproj | 352 ++++++++++++++++++ .../xcschemes/SwiftMarkItDownApp.xcscheme | 79 ++++ Tests/Expected/data.md | 4 + Tests/Expected/note.md | 2 + Tests/Expected/page.md | 5 + Tests/Expected/table.md | 4 + Tests/Fixtures/data.json | 1 + Tests/Fixtures/note.txt | 2 + Tests/Fixtures/page.html | 13 + Tests/Fixtures/table.csv | 3 + .../SwiftMarkItDownTests.swift | 2 +- 17 files changed, 731 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 App/SwiftMarkItDownApp/ContentView.swift create mode 100644 App/SwiftMarkItDownApp/SwiftMarkItDownApp.swift create mode 100755 Scripts/smoke-test.sh create mode 100644 SwiftMarkItDownApp.xcodeproj/project.pbxproj create mode 100644 SwiftMarkItDownApp.xcodeproj/xcshareddata/xcschemes/SwiftMarkItDownApp.xcscheme create mode 100644 Tests/Expected/data.md create mode 100644 Tests/Expected/note.md create mode 100644 Tests/Expected/page.md create mode 100644 Tests/Expected/table.md create mode 100644 Tests/Fixtures/data.json create mode 100644 Tests/Fixtures/note.txt create mode 100644 Tests/Fixtures/page.html create mode 100644 Tests/Fixtures/table.csv diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c5a0e45 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + +jobs: + test: + name: Swift tests and smoke tests + runs-on: macos-15 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Show Swift version + run: swift --version + + - name: Run unit tests + run: swift test + + - name: Run CLI smoke tests + run: Scripts/smoke-test.sh + + - name: Build iOS demo app + run: > + xcodebuild + -project SwiftMarkItDownApp.xcodeproj + -scheme SwiftMarkItDownApp + -destination 'generic/platform=iOS Simulator' + CODE_SIGNING_ALLOWED=NO + build diff --git a/App/SwiftMarkItDownApp/ContentView.swift b/App/SwiftMarkItDownApp/ContentView.swift new file mode 100644 index 0000000..3f68806 --- /dev/null +++ b/App/SwiftMarkItDownApp/ContentView.swift @@ -0,0 +1,140 @@ +import Foundation +import SwiftMarkItDown +import SwiftUI + +struct ContentView: View { + @State private var selectedFormat = DemoFormat.html + @State private var input = DemoFormat.html.sampleInput + @State private var output = "" + @State private var errorMessage: String? + + var body: some View { + NavigationStack { + Form { + Section("Input") { + Picker("Format", selection: $selectedFormat) { + ForEach(DemoFormat.allCases) { format in + Text(format.label).tag(format) + } + } + .pickerStyle(.segmented) + .onChange(of: selectedFormat) { newValue in + input = newValue.sampleInput + output = "" + errorMessage = nil + } + + TextEditor(text: $input) + .font(.system(.body, design: .monospaced)) + .frame(minHeight: 180) + .accessibilityIdentifier("conversionInput") + } + + Section { + Button("Convert to Markdown", action: convert) + .buttonStyle(.borderedProminent) + .accessibilityIdentifier("convertButton") + } + + if let errorMessage { + Section("Error") { + Text(errorMessage) + .foregroundStyle(.red) + } + } + + Section("Markdown Output") { + TextEditor(text: .constant(output)) + .font(.system(.body, design: .monospaced)) + .frame(minHeight: 180) + .accessibilityIdentifier("conversionOutput") + } + } + .navigationTitle("SwiftMarkItDown") + } + } + + private func convert() { + do { + let request = ConversionRequest( + data: Data(input.utf8), + fileName: "sample.\(selectedFormat.fileExtension)", + formatHint: selectedFormat.documentFormat + ) + output = try MarkItDown().convert(request).markdown + errorMessage = nil + } catch { + output = "" + errorMessage = error.localizedDescription + } + } +} + +private enum DemoFormat: String, CaseIterable, Identifiable { + case plainText + case html + case csv + case json + + var id: String { rawValue } + + var label: String { + switch self { + case .plainText: "Text" + case .html: "HTML" + case .csv: "CSV" + case .json: "JSON" + } + } + + var fileExtension: String { + switch self { + case .plainText: "txt" + case .html: "html" + case .csv: "csv" + case .json: "json" + } + } + + var documentFormat: DocumentFormat { + switch self { + case .plainText: .plainText + case .html: .html + case .csv: .csv + case .json: .json + } + } + + var sampleInput: String { + switch self { + case .plainText: + """ + Hello SwiftMarkItDown + This text is passed through as Markdown. + """ + case .html: + """ + + Ignored title + +

Hello from iOS

+

Convert native Swift content.

+ Example + + + """ + case .csv: + """ + Name,Note + Swift,Native + "Mark, It Down","CSV | escaped" + """ + case .json: + #"{"title":"Roadmap","formats":["txt","html","csv","json"]}"# + } + } +} + +#Preview { + ContentView() +} diff --git a/App/SwiftMarkItDownApp/SwiftMarkItDownApp.swift b/App/SwiftMarkItDownApp/SwiftMarkItDownApp.swift new file mode 100644 index 0000000..c16808d --- /dev/null +++ b/App/SwiftMarkItDownApp/SwiftMarkItDownApp.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct SwiftMarkItDownDemoApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/README.md b/README.md index 8d25c3d..7a53389 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SwiftMarkItDown -SwiftMarkItDown is the start of a native Swift/iOS document-to-Markdown pipeline inspired by Microsoft MarkItDown. The repository is structured as a Swift Package so the same core can be embedded in an iOS app, a macOS utility, or a server-side Swift service. +SwiftMarkItDown is the start of a native Swift/iOS document-to-Markdown pipeline inspired by Microsoft MarkItDown. The repository is structured around a Swift Package so the same core can be embedded in an iOS app, a macOS utility, or a server-side Swift service. The repo also includes a minimal SwiftUI demo app that exercises the package on iOS. ## Current scope @@ -17,11 +17,16 @@ PDF, DOCX, PPTX, and XLSX are intentionally represented in the format model but ```text Package.swift +SwiftMarkItDownApp.xcodeproj/ Xcode project for the iOS demo app +App/ + SwiftMarkItDownApp/ SwiftUI app target that imports the package Sources/ - SwiftMarkItDown/ Core library and converter protocols - swift-markitdown/ Minimal CLI wrapper around the library + SwiftMarkItDown/ Core library and converter protocols + swift-markitdown/ Minimal CLI wrapper around the library Tests/ - SwiftMarkItDownTests/ Core conversion tests + SwiftMarkItDownTests/ Core conversion tests + Fixtures/ CLI smoke-test inputs + Expected/ CLI smoke-test expected Markdown ``` ## Library usage @@ -43,6 +48,43 @@ print(document.markdown) swift run swift-markitdown path/to/file.html ``` +## iOS demo app + +Open `SwiftMarkItDownApp.xcodeproj` in Xcode, select the `SwiftMarkItDownApp` scheme, and run it on an iOS simulator. The app lets you edit sample text/HTML/CSV/JSON input and convert it to Markdown with the local `SwiftMarkItDown` package. + +You can also build it from Terminal on a Mac with Xcode installed: + +```bash +xcodebuild \ + -project SwiftMarkItDownApp.xcodeproj \ + -scheme SwiftMarkItDownApp \ + -destination 'generic/platform=iOS Simulator' \ + CODE_SIGNING_ALLOWED=NO \ + build +``` + +## Testing + +Run the unit test suite and CLI fixture smoke tests before opening a PR: + +```bash +swift test +Scripts/smoke-test.sh +``` + +On a Mac with Xcode installed, also build the iOS demo app: + +```bash +xcodebuild \ + -project SwiftMarkItDownApp.xcodeproj \ + -scheme SwiftMarkItDownApp \ + -destination 'generic/platform=iOS Simulator' \ + CODE_SIGNING_ALLOWED=NO \ + build +``` + +GitHub Actions runs the same Swift package, CLI smoke-test, and iOS demo app build checks on pushes to `main`, pull requests, and manual workflow dispatches. + ## Roadmap 1. Expand the text/HTML/CSV/JSON converters with richer Markdown normalization and metadata extraction. diff --git a/Scripts/smoke-test.sh b/Scripts/smoke-test.sh new file mode 100755 index 0000000..3ca42e4 --- /dev/null +++ b/Scripts/smoke-test.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +BINARY="${ROOT_DIR}/.build/debug/swift-markitdown" + +swift build --package-path "${ROOT_DIR}" --product swift-markitdown + +run_case() { + local name="$1" + local input="${ROOT_DIR}/Tests/Fixtures/${name}" + local expected="${ROOT_DIR}/Tests/Expected/${name%.*}.md" + local actual + actual="$(mktemp)" + + "${BINARY}" "${input}" > "${actual}" + + if ! diff -u "${expected}" "${actual}"; then + echo "Smoke test failed for ${name}" >&2 + rm -f "${actual}" + return 1 + fi + + rm -f "${actual}" + echo "✓ ${name}" +} + +run_case note.txt +run_case page.html +run_case table.csv +run_case data.json diff --git a/Sources/SwiftMarkItDown/Converters/HTMLConverter.swift b/Sources/SwiftMarkItDown/Converters/HTMLConverter.swift index 9b21554..75bfeab 100644 --- a/Sources/SwiftMarkItDown/Converters/HTMLConverter.swift +++ b/Sources/SwiftMarkItDown/Converters/HTMLConverter.swift @@ -10,6 +10,7 @@ public struct HTMLConverter: DocumentConverter { html = html.replacingOccurrences(of: "\r\n", with: "\n") let rules: [(String, String)] = [ + ("(?is)]*>.*?", ""), ("(?is)]*>.*?", ""), ("(?is)]*>.*?", ""), ("(?is)]*>(.*?)", "\n# $1\n"), @@ -36,6 +37,9 @@ public struct HTMLConverter: DocumentConverter { .smid_decodingHTMLEntities() .replacingOccurrences(of: "[ \t]+\n", with: "\n", options: .regularExpression) .replacingOccurrences(of: "\n{3,}", with: "\n\n", options: .regularExpression) + .split(separator: "\n", omittingEmptySubsequences: false) + .map { $0.trimmingCharacters(in: .whitespaces) } + .joined(separator: "\n") .smid_trimmedBlankLines return MarkdownDocument(markdown: markdown, sourceFormat: .html) diff --git a/SwiftMarkItDownApp.xcodeproj/project.pbxproj b/SwiftMarkItDownApp.xcodeproj/project.pbxproj new file mode 100644 index 0000000..78f0c8d --- /dev/null +++ b/SwiftMarkItDownApp.xcodeproj/project.pbxproj @@ -0,0 +1,352 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 60; + objects = { + +/* Begin PBXBuildFile section */ + 01A95D34F4DA4022BDE286B4 /* SwiftMarkItDownApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66481738239B42EB8C484310 /* SwiftMarkItDownApp.swift */; }; + 23EA68F489C04895BA06323F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 037D23D5D1574ACA94C31BF3 /* ContentView.swift */; }; + EFA99390927544718E050040 /* SwiftMarkItDown in Frameworks */ = {isa = PBXBuildFile; productRef = FFBABEEF11084DE78C50A81D /* SwiftMarkItDown */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 037D23D5D1574ACA94C31BF3 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 5C5BFDA93AF34555BFF7DC79 /* SwiftMarkItDownApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftMarkItDownApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 66481738239B42EB8C484310 /* SwiftMarkItDownApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMarkItDownApp.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 31F046C302AF46C8A0752428 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EFA99390927544718E050040 /* SwiftMarkItDown in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5B1AF9AD93D445758D74221F = { + isa = PBXGroup; + children = ( + 72D75F900530410F84E43735 /* SwiftMarkItDownApp */, + A2101201DE9749578A370783 /* Products */, + ); + sourceTree = ""; + }; + 72D75F900530410F84E43735 /* SwiftMarkItDownApp */ = { + isa = PBXGroup; + children = ( + 66481738239B42EB8C484310 /* SwiftMarkItDownApp.swift */, + 037D23D5D1574ACA94C31BF3 /* ContentView.swift */, + ); + path = App/SwiftMarkItDownApp; + sourceTree = ""; + }; + A2101201DE9749578A370783 /* Products */ = { + isa = PBXGroup; + children = ( + 5C5BFDA93AF34555BFF7DC79 /* SwiftMarkItDownApp.app */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 4E38F4A68E3D44C481A90DAE /* SwiftMarkItDownApp */ = { + isa = PBXNativeTarget; + buildConfigurationList = AAE5DDCC43A44238ABF2C012 /* Build configuration list for PBXNativeTarget "SwiftMarkItDownApp" */; + buildPhases = ( + B303122710924255893B8380 /* Sources */, + 31F046C302AF46C8A0752428 /* Frameworks */, + E8C256034EAE4CEBA9704C5E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SwiftMarkItDownApp; + packageProductDependencies = ( + FFBABEEF11084DE78C50A81D /* SwiftMarkItDown */, + ); + productName = SwiftMarkItDownApp; + productReference = 5C5BFDA93AF34555BFF7DC79 /* SwiftMarkItDownApp.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 26F6896B96234A00BB10F5CF /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1600; + LastUpgradeCheck = 1600; + TargetAttributes = { + 4E38F4A68E3D44C481A90DAE = { + CreatedOnToolsVersion = 16.0; + }; + }; + }; + buildConfigurationList = 22453E69467048B9929FC497 /* Build configuration list for PBXProject "SwiftMarkItDownApp" */; + compatibilityVersion = "Xcode 15.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5B1AF9AD93D445758D74221F; + packageReferences = ( + 3C39D5C2DDC04CEDAC1F52C8 /* XCLocalSwiftPackageReference "." */, + ); + productRefGroup = A2101201DE9749578A370783 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4E38F4A68E3D44C481A90DAE /* SwiftMarkItDownApp */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + E8C256034EAE4CEBA9704C5E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B303122710924255893B8380 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 01A95D34F4DA4022BDE286B4 /* SwiftMarkItDownApp.swift in Sources */, + 23EA68F489C04895BA06323F /* ContentView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 0E2AFE0A298C48F88F93BE03 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = SwiftMarkItDown; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.SwiftMarkItDownApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 2380B44F3C4F4BCFB4DFFA84 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 379F6DF511A3471E9FC78272 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = SwiftMarkItDown; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.SwiftMarkItDownApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 6E9ECFE469D94A67B7AA05C1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 22453E69467048B9929FC497 /* Build configuration list for PBXProject "SwiftMarkItDownApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2380B44F3C4F4BCFB4DFFA84 /* Debug */, + 6E9ECFE469D94A67B7AA05C1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + AAE5DDCC43A44238ABF2C012 /* Build configuration list for PBXNativeTarget "SwiftMarkItDownApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0E2AFE0A298C48F88F93BE03 /* Debug */, + 379F6DF511A3471E9FC78272 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 3C39D5C2DDC04CEDAC1F52C8 /* XCLocalSwiftPackageReference "." */ = { + isa = XCLocalSwiftPackageReference; + relativePath = .; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + FFBABEEF11084DE78C50A81D /* SwiftMarkItDown */ = { + isa = XCSwiftPackageProductDependency; + package = 3C39D5C2DDC04CEDAC1F52C8 /* XCLocalSwiftPackageReference "." */; + productName = SwiftMarkItDown; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 26F6896B96234A00BB10F5CF /* Project object */; +} diff --git a/SwiftMarkItDownApp.xcodeproj/xcshareddata/xcschemes/SwiftMarkItDownApp.xcscheme b/SwiftMarkItDownApp.xcodeproj/xcshareddata/xcschemes/SwiftMarkItDownApp.xcscheme new file mode 100644 index 0000000..6e01b25 --- /dev/null +++ b/SwiftMarkItDownApp.xcodeproj/xcshareddata/xcschemes/SwiftMarkItDownApp.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Expected/data.md b/Tests/Expected/data.md new file mode 100644 index 0000000..15fd210 --- /dev/null +++ b/Tests/Expected/data.md @@ -0,0 +1,4 @@ +- **formats**: + - txt + - html +- **title**: Roadmap diff --git a/Tests/Expected/note.md b/Tests/Expected/note.md new file mode 100644 index 0000000..edf2c98 --- /dev/null +++ b/Tests/Expected/note.md @@ -0,0 +1,2 @@ +Hello SwiftMarkItDown +This is plain text. diff --git a/Tests/Expected/page.md b/Tests/Expected/page.md new file mode 100644 index 0000000..d4c18ff --- /dev/null +++ b/Tests/Expected/page.md @@ -0,0 +1,5 @@ +# Smoke Test + +Hello **native Swift** & Markdown. + +[Example](https://example.com) diff --git a/Tests/Expected/table.md b/Tests/Expected/table.md new file mode 100644 index 0000000..3327c0c --- /dev/null +++ b/Tests/Expected/table.md @@ -0,0 +1,4 @@ +| Name | Note | +| --- | --- | +| Swift | Native | +| Mark, It Down | CSV \| escaped | diff --git a/Tests/Fixtures/data.json b/Tests/Fixtures/data.json new file mode 100644 index 0000000..25c497f --- /dev/null +++ b/Tests/Fixtures/data.json @@ -0,0 +1 @@ +{"title":"Roadmap","formats":["txt","html"]} diff --git a/Tests/Fixtures/note.txt b/Tests/Fixtures/note.txt new file mode 100644 index 0000000..edf2c98 --- /dev/null +++ b/Tests/Fixtures/note.txt @@ -0,0 +1,2 @@ +Hello SwiftMarkItDown +This is plain text. diff --git a/Tests/Fixtures/page.html b/Tests/Fixtures/page.html new file mode 100644 index 0000000..e1986b5 --- /dev/null +++ b/Tests/Fixtures/page.html @@ -0,0 +1,13 @@ + + + + Ignored title + + + + +

Smoke Test

+

Hello native Swift & Markdown.

+

Example

+ + diff --git a/Tests/Fixtures/table.csv b/Tests/Fixtures/table.csv new file mode 100644 index 0000000..e6f07dd --- /dev/null +++ b/Tests/Fixtures/table.csv @@ -0,0 +1,3 @@ +Name,Note +Swift,Native +"Mark, It Down","CSV | escaped" diff --git a/Tests/SwiftMarkItDownTests/SwiftMarkItDownTests.swift b/Tests/SwiftMarkItDownTests/SwiftMarkItDownTests.swift index ca33aa5..fec71d2 100644 --- a/Tests/SwiftMarkItDownTests/SwiftMarkItDownTests.swift +++ b/Tests/SwiftMarkItDownTests/SwiftMarkItDownTests.swift @@ -20,7 +20,7 @@ struct SwiftMarkItDownTests { @Test("converts simple HTML to Markdown") func convertsHTML() throws { - let html = "

Title

Hello Swift & iOS.

Link" + let html = "Ignored

Title

Hello Swift & iOS.

Link" let request = ConversionRequest(data: Data(html.utf8), fileName: "index.html") let document = try MarkItDown().convert(request) #expect(document.markdown == "# Title\nHello **Swift** & iOS.\n\n[Link](https://example.com)")