From 1b307965c9aa664199a8c44234686d5f39c07bf8 Mon Sep 17 00:00:00 2001 From: ANE-Bot Date: Tue, 8 Sep 2026 07:29:38 +0000 Subject: [PATCH 1/2] Swift: parse package-registry dependencies in Package.swift SwiftPM 5.7 lets a Package.swift declare a dependency by registry identifier instead of url: `.package(id: "scope.name", from: "1.0.0")`. The manifest parser only accepted `url:` (or `path:`), so any project using the `id:` form failed Swift analysis with: unexpected "id: "" expecting "name:", "path:", or "url:" Accept `id:` in the same position as `url:`. Registry dependencies take the same version requirements as url dependencies, so they reuse that parser; the registry identifier is used as the dependency name. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_0153hT5c8YQq9dHzzwrGYMCj --- Changelog.md | 1 + src/Strategy/Swift/PackageSwift.hs | 8 +++-- test/Swift/PackageSwiftSpec.hs | 57 ++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index 3efc8532f..85bba0fd0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ ## Unreleased +- Swift: `Package.swift` manifests declaring package-registry dependencies (`.package(id: "scope.name", from: "1.0.0")` and the other `id:` forms introduced in SwiftPM 5.7) no longer fail analysis with `unexpected "id: "" expecting "name:", "path:", or "url:"`; the dependency is reported under its registry identifier. - Dart: `pubspec.yaml` files using valid dependency forms the parser previously rejected no longer fail analysis with `Aeson exception: ... empty` or `failed parsing pub package's source!`: a bare dependency with no value (any version), a `version:`-only entry, the `hosted: ` shorthand introduced in Dart 2.15, a `hosted:` map without a `version`, and a `git:` map without a `ref`. ([#1760](https://github.com/fossas/fossa-cli/pull/1760)) - Workflows: `fossa analyze --x-workflow ` runs a dependency-usage workflow analyzer through the embedded ficus and records its result in the debug bundle. ([#1761](https://github.com/fossas/fossa-cli/pull/1761)) - Workflows: the `--x-workflow` result is uploaded to FOSSA against the analyzed revision once the dependency upload succeeds; `--output` runs still upload nothing. ([#1762](https://github.com/fossas/fossa-cli/pull/1762)) diff --git a/src/Strategy/Swift/PackageSwift.hs b/src/Strategy/Swift/PackageSwift.hs index 0d8b4a5e4..8799eb246 100644 --- a/src/Strategy/Swift/PackageSwift.hs +++ b/src/Strategy/Swift/PackageSwift.hs @@ -232,8 +232,12 @@ parsePackageDep = try parsePathDep <|> parseGitDep _ <- symbol ".package" <* symbol "(" _ <- optionallyTry (parseKeyValue "name" parseQuotedText) - -- Url (Required Field) - url <- parseKeyValue "url" $ parseQuotedText <* maybeComma + -- Url (Required Field), or -- for a package-registry dependency (SwiftPM 5.7+) -- + -- the package's scoped identifier, e.g. `.package(id: "mona.LinkedList", from: "1.0.0")`. + -- https://developer.apple.com/documentation/packagedescription/package/dependency/package(id:from:) + -- Registry dependencies take the same version requirements as url dependencies, + -- so they share this parser; the identifier is used in place of the url. + url <- (parseKeyValue "url" parseQuotedText <|> parseKeyValue "id" parseQuotedText) <* maybeComma versionRequirement <- optional $ diff --git a/test/Swift/PackageSwiftSpec.hs b/test/Swift/PackageSwiftSpec.hs index 1acd34306..e48672665 100644 --- a/test/Swift/PackageSwiftSpec.hs +++ b/test/Swift/PackageSwiftSpec.hs @@ -2,8 +2,11 @@ module Swift.PackageSwiftSpec ( spec, ) where +import Data.Foldable (for_) import Data.Map.Strict qualified as Map +import Data.String.Conversion (toString) import Data.Text (Text) +import Data.Text qualified as Text import Data.Text.IO qualified as TIO import DepTypes (DepType (GitType, SwiftType), Dependency (..), VerConstraint (CEq)) import GraphUtil (expectDeps, expectDirect, expectEdges) @@ -85,6 +88,23 @@ expectedSwiftPackage = expectedSwiftPackageNoDeps :: SwiftPackage expectedSwiftPackageNoDeps = SwiftPackage "6.0" [] +-- | A minimal, valid Package.swift declaring the given package dependencies. +manifestWithDependencies :: [Text] -> Text +manifestWithDependencies deps = + Text.unlines $ + [ "// swift-tools-version:5.7" + , "import PackageDescription" + , "" + , "let package = Package(" + , " name: \"Example\"," + , " dependencies: [" + ] + <> map (\dep -> " " <> dep <> ",") deps + <> [ " ]," + , " targets: [.target(name: \"Example\")]" + , ")" + ] + spec :: Spec spec = do packageDotSwiftFile <- runIO (TIO.readFile "test/Swift/testdata/Package.swift") @@ -109,6 +129,43 @@ spec = do Left failCode -> expectationFailure $ show failCode Right result -> result `shouldBe` expectedSwiftPackageNoDeps + -- Package-registry dependencies (SwiftPM 5.7+) are declared with a scoped + -- identifier instead of a url: `.package(id: "scope.name", ...)`. They used to + -- fail the whole analysis with `unexpected "id: "" expecting "name:", "path:", or "url:"`. + describe "Parses package-registry dependencies" $ do + let registryForms :: [(Text, SwiftPackageGitDep)] + registryForms = + [ (".package(id: \"mona.LinkedList\", from: \"1.0.0\")", gitDepFrom "mona.LinkedList" "1.0.0") + , (".package(id: \"mona.LinkedList\", exact: \"1.2.3\")", gitDepExactly "mona.LinkedList" "1.2.3") + , (".package(id: \"mona.LinkedList\", .upToNextMajor(from: \"1.0.0\"))", gitDepUpToNextMajor "mona.LinkedList" "1.0.0") + , (".package(id: \"mona.LinkedList\", .upToNextMinor(from: \"1.0.0\"))", gitDepUpToNextMinor "mona.LinkedList" "1.0.0") + , (".package(id: \"mona.LinkedList\", \"1.0.0\"..<\"2.0.0\")", gitDepWithRhsHalfOpenInterval "mona.LinkedList" "1.0.0" "2.0.0") + , (".package(id: \"mona.LinkedList\", \"1.0.0\"...\"1.5.0\")", gitDepWithClosedRange "mona.LinkedList" "1.0.0" "1.5.0") + ] + for_ registryForms $ \(form, expected) -> + it ("should parse " <> toString form) $ do + case runParser parsePackageSwiftFile "" (manifestWithDependencies [form]) of + Left failCode -> expectationFailure $ show failCode + Right result -> result `shouldBe` SwiftPackage "5.7" [GitSource expected] + + it "should parse registry dependencies alongside url and path dependencies" $ do + let manifest = + manifestWithDependencies + [ ".package(url: \"https://github.com/apple/swift-argument-parser\", from: \"1.0.0\")" + , ".package(id: \"mona.LinkedList\", from: \"1.0.0\")" + , ".package(path: \"../local\")" + ] + case runParser parsePackageSwiftFile "" manifest of + Left failCode -> expectationFailure $ show failCode + Right result -> + result + `shouldBe` SwiftPackage + "5.7" + [ GitSource $ gitDepFrom "https://github.com/apple/swift-argument-parser" "1.0.0" + , GitSource $ gitDepFrom "mona.LinkedList" "1.0.0" + , PathSource "../local" + ] + describe "buildGraph, when no resolved content is discovered" $ do it "should use git dependency type, when constraint is of branch, revision, or exact type" $ do let expectedDeps = From 56e82237396d7e75f68f4ee19ce1d1fc59d6c430 Mon Sep 17 00:00:00 2001 From: ANE-Bot Date: Tue, 8 Sep 2026 07:31:25 +0000 Subject: [PATCH 2/2] Changelog: link the Swift registry-dependency entry to its PR Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_0153hT5c8YQq9dHzzwrGYMCj --- Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 85bba0fd0..e2c3b427b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,7 +2,7 @@ ## Unreleased -- Swift: `Package.swift` manifests declaring package-registry dependencies (`.package(id: "scope.name", from: "1.0.0")` and the other `id:` forms introduced in SwiftPM 5.7) no longer fail analysis with `unexpected "id: "" expecting "name:", "path:", or "url:"`; the dependency is reported under its registry identifier. +- Swift: `Package.swift` manifests declaring package-registry dependencies (`.package(id: "scope.name", from: "1.0.0")` and the other `id:` forms introduced in SwiftPM 5.7) no longer fail analysis with `unexpected "id: "" expecting "name:", "path:", or "url:"`; the dependency is reported under its registry identifier. ([#1773](https://github.com/fossas/fossa-cli/pull/1773)) - Dart: `pubspec.yaml` files using valid dependency forms the parser previously rejected no longer fail analysis with `Aeson exception: ... empty` or `failed parsing pub package's source!`: a bare dependency with no value (any version), a `version:`-only entry, the `hosted: ` shorthand introduced in Dart 2.15, a `hosted:` map without a `version`, and a `git:` map without a `ref`. ([#1760](https://github.com/fossas/fossa-cli/pull/1760)) - Workflows: `fossa analyze --x-workflow ` runs a dependency-usage workflow analyzer through the embedded ficus and records its result in the debug bundle. ([#1761](https://github.com/fossas/fossa-cli/pull/1761)) - Workflows: the `--x-workflow` result is uploaded to FOSSA against the analyzed revision once the dependency upload succeeds; `--output` runs still upload nothing. ([#1762](https://github.com/fossas/fossa-cli/pull/1762))