diff --git a/.github/workflows/SyntaxKit.yml b/.github/workflows/SyntaxKit.yml index 5ca13c2..9df2099 100644 --- a/.github/workflows/SyntaxKit.yml +++ b/.github/workflows/SyntaxKit.yml @@ -3,134 +3,243 @@ on: push: branches-ignore: - '*WIP' + paths-ignore: + - '**.md' + - 'Docs/**' + - 'LICENSE' + - '.github/ISSUE_TEMPLATE/**' + pull_request: + branches: + - main + - 'v[0-9]*.[0-9]*.[0-9]*' + paths-ignore: + - '**.md' + - 'Docs/**' + - 'LICENSE' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }} + cancel-in-progress: true + env: - PACKAGE_NAME: SyntaxKit + PACKAGE_NAME: SyntaxKit jobs: + configure: + name: Configure Build Matrix + runs-on: ubuntu-latest + if: ${{ github.event_name == 'pull_request' || !contains(github.event.head_commit.message, 'ci skip') }} + outputs: + full-matrix: ${{ steps.set-matrix.outputs.full-matrix }} + ubuntu-os: ${{ steps.set-matrix.outputs.ubuntu-os }} + ubuntu-swift: ${{ steps.set-matrix.outputs.ubuntu-swift }} + ubuntu-type: ${{ steps.set-matrix.outputs.ubuntu-type }} + steps: + - name: Determine build matrix + id: set-matrix + run: | + if [[ "${{ github.ref }}" == "refs/heads/main" || "${{ github.event_name }}" == "pull_request" ]]; then + echo "full-matrix=true" >> "$GITHUB_OUTPUT" + echo 'ubuntu-os=["noble","jammy"]' >> "$GITHUB_OUTPUT" + echo 'ubuntu-swift=[{"version":"6.0"},{"version":"6.1"},{"version":"6.2"},{"version":"6.3"}]' >> "$GITHUB_OUTPUT" + echo 'ubuntu-type=["","wasm","wasm-embedded"]' >> "$GITHUB_OUTPUT" + else + echo "full-matrix=false" >> "$GITHUB_OUTPUT" + echo 'ubuntu-os=["noble"]' >> "$GITHUB_OUTPUT" + echo 'ubuntu-swift=[{"version":"6.3"}]' >> "$GITHUB_OUTPUT" + echo 'ubuntu-type=[""]' >> "$GITHUB_OUTPUT" + fi + build-ubuntu: name: Build on Ubuntu + needs: [configure] runs-on: ubuntu-latest container: ${{ matrix.swift.nightly && format('swiftlang/swift:nightly-{0}-{1}', matrix.swift.version, matrix.os) || format('swift:{0}-{1}', matrix.swift.version, matrix.os) }} - if: ${{ !contains(github.event.head_commit.message, 'ci skip') }} strategy: matrix: - os: [noble, jammy] - swift: - - version: "6.0" - - version: "6.1" - - version: "6.1" - nightly: true - - version: "6.2" - nightly: true + os: ${{ fromJSON(needs.configure.outputs.ubuntu-os) }} + swift: ${{ fromJSON(needs.configure.outputs.ubuntu-swift) }} + type: ${{ fromJSON(needs.configure.outputs.ubuntu-type) }} + exclude: + - swift: {version: "6.0"} + type: wasm + - swift: {version: "6.0"} + type: wasm-embedded + - swift: {version: "6.1"} + type: wasm + - swift: {version: "6.1"} + type: wasm-embedded + - swift: {version: "6.2"} + type: wasm + - swift: {version: "6.2"} + type: wasm-embedded steps: - - uses: actions/checkout@v4 - - uses: brightdigit/swift-build@v1.3.1 - - uses: sersoft-gmbh/swift-coverage-action@v4 + - uses: actions/checkout@v6 + - uses: brightdigit/swift-build@v1.5.3 + id: build + with: + type: ${{ matrix.type }} + wasmtime-version: 41.0.3 + - name: Install curl + if: steps.build.outputs.contains-code-coverage == 'true' + run: | + apt-get update -q + apt-get install -y curl + - uses: sersoft-gmbh/swift-coverage-action@v5 id: coverage-files - with: + if: steps.build.outputs.contains-code-coverage == 'true' + with: fail-on-empty-output: true - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + if: steps.build.outputs.contains-code-coverage == 'true' + uses: codecov/codecov-action@v6 with: fail_ci_if_error: true - flags: swift-${{ matrix.swift-version }},ubuntu - verbose: true - token: ${{ secrets.CODECOV_TOKEN }} - files: ${{ join(fromJSON(steps.coverage-files.outputs.files), ',') }} + flags: swift-${{ matrix.swift.version }},ubuntu + verbose: true + token: ${{ secrets.CODECOV_TOKEN }} + files: ${{ join(fromJSON(steps.coverage-files.outputs.files), ',') }} + build-windows: name: Build on Windows + needs: [configure] + if: needs.configure.outputs.full-matrix == 'true' runs-on: ${{ matrix.runs-on }} strategy: fail-fast: false matrix: runs-on: [windows-2022, windows-2025] - include: - - swift-version: swift-6.2-branch - swift-build: 6.2-DEVELOPMENT-SNAPSHOT-2025-09-06-a - - swift-version: swift-6.1-release - swift-build: 6.1-RELEASE + swift: + - version: swift-6.3-release + build: 6.3-RELEASE + - version: swift-6.2-release + build: 6.2-RELEASE + - version: swift-6.1-release + build: 6.1-RELEASE steps: - - uses: actions/checkout@v4 - - uses: brightdigit/swift-build@v1.3.1 + - uses: actions/checkout@v6 + - name: Enable git symlinks + shell: pwsh + run: git config --global core.symlinks true + - uses: brightdigit/swift-build@v1.5.3 + id: build with: - windows-swift-version: ${{ matrix.swift-version }} - windows-swift-build: ${{ matrix.swift-build }} + windows-swift-version: ${{ matrix.swift.version }} + windows-swift-build: ${{ matrix.swift.build }} - name: Upload coverage to Codecov - uses: codecov/codecov-action@v5 + if: steps.build.outputs.contains-code-coverage == 'true' + uses: codecov/codecov-action@v6 with: fail_ci_if_error: true - flags: swift-${{ matrix.swift-version }},windows - verbose: true + flags: swift-${{ matrix.swift.version }},windows + verbose: true token: ${{ secrets.CODECOV_TOKEN }} os: windows swift_project: SyntaxKit - # files: ${{ join(fromJSON(steps.coverage-files.outputs.files), ',') }} + build-macos: name: Build on macOS + needs: [configure] env: PACKAGE_NAME: SyntaxKit runs-on: ${{ matrix.runs-on }} - if: "!contains(github.event.head_commit.message, 'ci skip')" + if: ${{ !cancelled() && needs.configure.result == 'success' }} strategy: fail-fast: false matrix: include: - # SPM Build Matrix - - runs-on: macos-15 - xcode: "/Applications/Xcode_26.0.app" + # SPM Build — no platform type; matrix.type evaluates to '' by design + - runs-on: macos-26 + xcode: "/Applications/Xcode_26.4.app" + steps: + - uses: actions/checkout@v6 + + - name: Build and Test + id: build + uses: brightdigit/swift-build@v1.5.3 + with: + scheme: ${{ env.PACKAGE_NAME }}-Package + type: ${{ matrix.type }} + xcode: ${{ matrix.xcode }} + deviceName: ${{ matrix.deviceName }} + osVersion: ${{ matrix.osVersion }} + download-platform: ${{ matrix.download-platform }} + + # Common Coverage Steps + - name: Process Coverage + if: steps.build.outputs.contains-code-coverage == 'true' + uses: sersoft-gmbh/swift-coverage-action@v5 + + - name: Upload Coverage + if: steps.build.outputs.contains-code-coverage == 'true' + uses: codecov/codecov-action@v6 + with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: ${{ matrix.type && format('{0}{1}', matrix.type, matrix.osVersion) || 'spm' }} + + build-macos-full: + name: Build on macOS (Full) + needs: [configure] + if: ${{ !cancelled() && needs.configure.result == 'success' && needs.configure.outputs.full-matrix == 'true' }} + env: + PACKAGE_NAME: SyntaxKit + runs-on: ${{ matrix.runs-on }} + strategy: + fail-fast: false + matrix: + include: + # SPM Build (older Xcode) - runs-on: macos-15 xcode: "/Applications/Xcode_16.4.app" - # macOS Build Matrix - - type: macos - runs-on: macos-15 - xcode: "/Applications/Xcode_26.0.app" - + # macOS Build (older Xcode) - type: macos runs-on: macos-15 xcode: "/Applications/Xcode_16.4.app" + # macOS Build - type: macos - runs-on: macos-15 - xcode: "/Applications/Xcode_26.0.app" - + runs-on: macos-26 + xcode: "/Applications/Xcode_26.4.app" + # iOS Build Matrix - type: ios - runs-on: macos-15 - xcode: "/Applications/Xcode_26.0.app" + runs-on: macos-26 + xcode: "/Applications/Xcode_26.4.app" deviceName: "iPhone 17 Pro" - osVersion: "26.0" + osVersion: "26.4" download-platform: true - + # watchOS Build Matrix - type: watchos - runs-on: macos-15 - xcode: "/Applications/Xcode_26.0.app" + runs-on: macos-26 + xcode: "/Applications/Xcode_26.4.app" deviceName: "Apple Watch Ultra 3 (49mm)" - osVersion: "26.0" + osVersion: "26.4" download-platform: true # tvOS Build Matrix - type: tvos - runs-on: macos-15 - xcode: "/Applications/Xcode_26.0.app" + runs-on: macos-26 + xcode: "/Applications/Xcode_26.4.app" deviceName: "Apple TV" - osVersion: "26.0" + osVersion: "26.4" download-platform: true - # visionOS Build Matrix + # visionOS Build Matrix - type: visionos - runs-on: macos-15 - xcode: "/Applications/Xcode_26.0.app" + runs-on: macos-26 + xcode: "/Applications/Xcode_26.4.app" deviceName: "Apple Vision Pro" - osVersion: "26.0" + osVersion: "26.4" download-platform: true - + steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Build and Test - uses: brightdigit/swift-build@v1.3.1 + id: build + uses: brightdigit/swift-build@v1.5.3 with: scheme: ${{ env.PACKAGE_NAME }}-Package type: ${{ matrix.type }} @@ -138,39 +247,84 @@ jobs: deviceName: ${{ matrix.deviceName }} osVersion: ${{ matrix.osVersion }} download-platform: ${{ matrix.download-platform }} - + # Common Coverage Steps - name: Process Coverage - uses: sersoft-gmbh/swift-coverage-action@v4 - + if: steps.build.outputs.contains-code-coverage == 'true' + uses: sersoft-gmbh/swift-coverage-action@v5 + - name: Upload Coverage - uses: codecov/codecov-action@v4 + if: steps.build.outputs.contains-code-coverage == 'true' + uses: codecov/codecov-action@v6 with: token: ${{ secrets.CODECOV_TOKEN }} flags: ${{ matrix.type && format('{0}{1}', matrix.type, matrix.osVersion) || 'spm' }} + build-android: + name: Build for Android + needs: [configure] + if: needs.configure.outputs.full-matrix == 'true' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + swift: + - version: "6.2" + - version: "6.3" + android-api-level: [33, 34, 35, 36] + steps: + - uses: actions/checkout@v6 + - name: Free disk space + uses: jlumbroso/free-disk-space@v1.3.1 + with: + tool-cache: false + android: false + dotnet: true + haskell: true + large-packages: true + docker-images: true + swap-storage: true + - uses: brightdigit/swift-build@v1.5.3 + id: build + with: + type: android + android-swift-version: ${{ matrix.swift.version }} + android-api-level: ${{ matrix.android-api-level }} + android-run-tests: true + android-copy-files: Sources/SyntaxKit/Documentation.docc + - name: Upload coverage to Codecov + if: steps.build.outputs.contains-code-coverage == 'true' + uses: codecov/codecov-action@v6 + with: + fail_ci_if_error: true + flags: android-api${{ matrix.android-api-level }}-swift${{ matrix.swift.version }} + verbose: true + token: ${{ secrets.CODECOV_TOKEN }} + lint: name: Linting - if: "!contains(github.event.head_commit.message, 'ci skip')" + # build-windows, build-macos-full, and build-android are skipped on feature branches; + # !failure() allows this job to proceed past skipped (not failed) dependencies. + if: ${{ !cancelled() && !failure() && (github.event_name == 'pull_request' || !contains(github.event.head_commit.message, 'ci skip')) }} runs-on: ubuntu-latest - needs: [build-ubuntu, build-macos, build-windows] + needs: [build-ubuntu, build-macos, build-windows, build-macos-full, build-android] env: MINT_PATH: .mint/lib MINT_LINK_PATH: .mint/bin steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Cache mint id: cache-mint - uses: actions/cache@v4 + uses: actions/cache@v5 env: cache-name: cache with: path: | .mint - Mint + Mint key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }} restore-keys: | - ${{ runner.os }}-mint- + ${{ runner.os }}-mint- - name: Install mint if: steps.cache-mint.outputs.cache-hit == '' run: | @@ -182,10 +336,11 @@ jobs: docs: name: Documentation Validation - if: "!contains(github.event.head_commit.message, 'ci skip')" - needs: [build-ubuntu, build-macos, build-windows] + # Same rationale as lint: !failure() lets this proceed when platform-specific jobs are skipped. + if: ${{ !cancelled() && !failure() && (github.event_name == 'pull_request' || !contains(github.event.head_commit.message, 'ci skip')) }} + needs: [build-ubuntu, build-macos, build-windows, build-macos-full, build-android] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Validate Documentation run: ./Scripts/validate-docs.sh diff --git a/.github/workflows/cleanup-caches.yml b/.github/workflows/cleanup-caches.yml new file mode 100644 index 0000000..69c3b56 --- /dev/null +++ b/.github/workflows/cleanup-caches.yml @@ -0,0 +1,42 @@ +name: Cleanup Branch Caches +on: + delete: + +jobs: + cleanup: + name: Cleanup Caches for Deleted Branch + runs-on: ubuntu-latest + permissions: + actions: write + steps: + - name: Delete branch caches + uses: actions/github-script@v8 + with: + script: | + if (context.payload.ref_type !== 'branch') { + console.log('Not a branch deletion, skipping.'); + return; + } + + const ref = `refs/heads/${context.payload.ref}`; + console.log(`Cleaning up caches for branch: ${ref}`); + + const caches = await github.paginate( + github.rest.actions.getActionsCacheList, + { + owner: context.repo.owner, + repo: context.repo.repo, + ref: ref, + } + ); + + for (const cache of caches) { + console.log(`Deleting cache: ${cache.key} (${cache.id})`); + await github.rest.actions.deleteActionsCacheById({ + owner: context.repo.owner, + repo: context.repo.repo, + cache_id: cache.id, + }); + } + + console.log(`Deleted ${caches.length} cache(s) for ${ref}`); diff --git a/.github/workflows/cleanup-pr-caches.yml b/.github/workflows/cleanup-pr-caches.yml new file mode 100644 index 0000000..e928075 --- /dev/null +++ b/.github/workflows/cleanup-pr-caches.yml @@ -0,0 +1,38 @@ +name: Cleanup PR Caches +on: + pull_request: + types: [closed] + +jobs: + cleanup: + name: Cleanup Caches for PR + runs-on: ubuntu-latest + permissions: + actions: write + steps: + - name: Delete PR branch caches + uses: actions/github-script@v8 + with: + script: | + const ref = `refs/pull/${context.payload.pull_request.number}/merge`; + console.log(`Cleaning up caches for PR: ${ref}`); + + const caches = await github.paginate( + github.rest.actions.getActionsCacheList, + { + owner: context.repo.owner, + repo: context.repo.repo, + ref: ref, + } + ); + + for (const cache of caches) { + console.log(`Deleting cache: ${cache.key} (${cache.id})`); + await github.rest.actions.deleteActionsCacheById({ + owner: context.repo.owner, + repo: context.repo.repo, + cache_id: cache.id, + }); + } + + console.log(`Deleted ${caches.length} cache(s) for ${ref}`); diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..5e7f78b --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,91 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches-ignore: + - '*WIP' + paths-ignore: + - '**.md' + - 'Docs/**' + - 'LICENSE' + - '.github/ISSUE_TEMPLATE/**' + pull_request: + # The branches below must be a subset of the branches above + branches: [ "main" ] + paths-ignore: + - '**.md' + - 'Docs/**' + - 'LICENSE' + - '.github/ISSUE_TEMPLATE/**' + schedule: + - cron: '20 11 * * 3' + +jobs: + analyze: + name: Analyze + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners + # Consider using larger runners for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-26') || 'ubuntu-latest' }} + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'swift' ] + # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ] + # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup Xcode + run: sudo xcode-select -s /Applications/Xcode_26.4.app/Contents/Developer + + - name: Verify Swift Version + run: | + swift --version + swift package --version + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Build + run: swift build + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{matrix.language}}" diff --git a/Package.resolved b/Package.resolved index e355d45..24cfefa 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,13 +1,13 @@ { - "originHash" : "3a9631966aed0489b1d0415c39c345f4083602bf6a2ddfdc7954cd286093542f", + "originHash" : "482d43aff5bb5c075d237e0ea17c12ee2c043b2642e459260752aa1848a20593", "pins" : [ { "identity" : "swift-docc-plugin", "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-docc-plugin", "state" : { - "revision" : "3e4f133a77e644a5812911a0513aeb7288b07d06", - "version" : "1.4.5" + "revision" : "e977f65879f82b375a044c8837597f690c067da6", + "version" : "1.4.6" } }, { diff --git a/Tests/SyntaxDocTests/DocumentationExampleTests.swift b/Tests/SyntaxDocTests/DocumentationExampleTests.swift index 602462d..d2222f7 100644 --- a/Tests/SyntaxDocTests/DocumentationExampleTests.swift +++ b/Tests/SyntaxDocTests/DocumentationExampleTests.swift @@ -42,7 +42,7 @@ internal struct DocumentationExampleTests { @Test("Quick Start Guide examples work correctly") internal func validateQuickStartGuideExamples() throws { let quickStartFile = try Settings.resolveFilePath( - "Sources/SyntaxKit/Documentation.docc/Tutorials/Quick-Start-Guide.md" + "Documentation.docc/Tutorials/Quick-Start-Guide.md" ) let results = try testHarness.validateFile(at: quickStartFile) @@ -57,7 +57,7 @@ internal struct DocumentationExampleTests { @Test("Creating Macros tutorial examples work correctly") internal func validateMacroTutorialExamples() throws { let macroTutorialFile = try Settings.resolveFilePath( - "Sources/SyntaxKit/Documentation.docc/Tutorials/Creating-Macros-with-SyntaxKit.md" + "Documentation.docc/Tutorials/Creating-Macros-with-SyntaxKit.md" ) let results = try testHarness.validateFile(at: macroTutorialFile) diff --git a/Tests/SyntaxDocTests/Settings.swift b/Tests/SyntaxDocTests/Settings.swift index ab5bda9..f85ebaf 100644 --- a/Tests/SyntaxDocTests/Settings.swift +++ b/Tests/SyntaxDocTests/Settings.swift @@ -8,22 +8,72 @@ import Foundation internal enum Settings { - /// Project root directory calculated from the current file location + /// Project root directory calculated with a 3-strategy fallback for cross-platform support internal static let projectRoot: URL = { - let currentFileURL = URL(fileURLWithPath: #filePath) - return - currentFileURL + let workingDir = URL(fileURLWithPath: FileManager.default.currentDirectoryPath) + + // Strategy 1a: Sources/ in working directory (SPM/WASM/Linux) + if FileManager.default.fileExists(atPath: workingDir.appendingPathComponent("Sources").path) { + return workingDir + } + + // Strategy 1b: Documentation.docc present in working directory. + // The swift-build action's android-copy-files parameter copies Documentation.docc/ as + // a flat sibling of the test binary. Strategy 1a always runs first, so a macOS project + // root containing Sources/ will never reach this check. + if FileManager.default.fileExists( + atPath: workingDir.appendingPathComponent("Documentation.docc").path) + { + return workingDir + } + + // Strategy 2: Source-relative via #filePath (macOS/Linux CI) + let sourceRelative = URL(fileURLWithPath: #filePath) .deletingLastPathComponent() // Tests/SyntaxDocTests .deletingLastPathComponent() // Tests .deletingLastPathComponent() // Project root + if FileManager.default.fileExists( + atPath: sourceRelative.appendingPathComponent("Sources").path) + { + return sourceRelative + } + + // Strategy 3: Walk up from working directory (nested execution contexts) + var search = workingDir + for _ in 0..<4 { + if FileManager.default.fileExists(atPath: search.appendingPathComponent("Sources").path) { + return search + } + search = search.deletingLastPathComponent() + } + + // Fallback — will produce a clear error if Sources/ is still not found + return sourceRelative }() /// Document paths to search for documentation files - internal static let docPaths = [ - "Sources/SyntaxKit/Documentation.docc", - "README.md", - "Examples", - ] + /// On WASM, limited to lightweight tutorial files only (no images, no Examples) + /// due to WASM memory constraints (~144KB practical limit) + internal static let docPaths: [String] = { + #if os(Android) + // android-copy-files copies Documentation.docc/ as last component to working dir + return [ + "Documentation.docc/Tutorials/Quick-Start-Guide.md", + "Documentation.docc/Tutorials/Creating-Macros-with-SyntaxKit.md", + ] + #elseif os(WASI) + return [ + "Sources/SyntaxKit/Documentation.docc/Tutorials/Quick-Start-Guide.md", + "Sources/SyntaxKit/Documentation.docc/Tutorials/Creating-Macros-with-SyntaxKit.md", + ] + #else + return [ + "Sources/SyntaxKit/Documentation.docc", + "README.md", + "Examples", + ] + #endif + }() /// Resolves a relative file path to absolute path internal static func resolveFilePath(_ filePath: String) throws -> URL { @@ -34,7 +84,12 @@ internal enum Settings { return .init(fileURLWithPath: filePath) } } else { - return Self.projectRoot.appendingPathComponent(filePath) + #if os(Android) // os(Android) is a valid Swift platform condition since Swift 5.9 + let resolvedPath = filePath + #else + let resolvedPath = "Sources/SyntaxKit/" + filePath + #endif + return Self.projectRoot.appendingPathComponent(resolvedPath) } } }