{"id":13872226,"url":"https://github.com/SwiftDocOrg/SwiftSemantics","last_synced_at":"2025-07-16T02:30:29.181Z","repository":{"id":50314072,"uuid":"235567484","full_name":"SwiftDocOrg/SwiftSemantics","owner":"SwiftDocOrg","description":"Uses SwiftSyntax to parse Swift code into its constituent declarations","archived":true,"fork":false,"pushed_at":"2021-07-20T16:20:54.000Z","size":192,"stargazers_count":224,"open_issues_count":0,"forks_count":29,"subscribers_count":11,"default_branch":"main","last_synced_at":"2024-11-14T09:21:24.814Z","etag":null,"topics":["swift","swiftsyntax"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SwiftDocOrg.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-01-22T12:20:17.000Z","updated_at":"2024-07-17T09:15:50.000Z","dependencies_parsed_at":"2022-09-13T02:32:06.144Z","dependency_job_id":null,"html_url":"https://github.com/SwiftDocOrg/SwiftSemantics","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftDocOrg%2FSwiftSemantics","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftDocOrg%2FSwiftSemantics/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftDocOrg%2FSwiftSemantics/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftDocOrg%2FSwiftSemantics/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SwiftDocOrg","download_url":"https://codeload.github.com/SwiftDocOrg/SwiftSemantics/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226095618,"owners_count":17572963,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["swift","swiftsyntax"],"created_at":"2024-08-05T23:00:37.359Z","updated_at":"2024-11-23T20:30:46.664Z","avatar_url":"https://github.com/SwiftDocOrg.png","language":"Swift","funding_links":[],"categories":["Swift"],"sub_categories":[],"readme":"# SwiftSemantics\n\n![CI][ci badge]\n[![Documentation][documentation badge]][documentation]\n\nSwiftSemantics is a package that lets you\nparse Swift code into its constituent declarations.\n\nUse [SwiftSyntax][swiftsyntax] to construct\nan abstract syntax tree from Swift source code,\nthen walk the AST with the provided `DeclarationCollector`\n(or with your own `SyntaxVisitor`-conforming type)\nand construct a `Declaration` value for each visited `DeclSyntax` node:\n\n```swift\nimport SwiftSyntax\nimport SwiftSemantics\n\nlet source = #\"\"\"\nimport UIKit\n\nclass ViewController: UIViewController, UITableViewDelegate {\n    enum Section: Int {\n        case summary, people, places\n    }\n\n    var people: [People], places: [Place]\n\n    @IBOutlet private(set) var tableView: UITableView!\n}\n\"\"\"#\n\nvar collector = DeclarationCollector()\nlet tree = try SyntaxParser.parse(source: source)\ncollector.walk(tree)\n\n// Import declarations\ncollector.imports.first?.pathComponents // [\"UIKit\"]\n\n// Class declarations\ncollector.classes.first?.name // \"ViewController\"\ncollector.classes.first?.inheritance // [\"UIViewController\", \"UITableViewDelegate\"]\n\n// Enumeration declarations\ncollector.enumerations.first?.name // \"Section\"\n\n// Enumeration case declarations\ncollector.enumerationCases.count // 3\ncollector.enumerationCases.map { $0.name } // [\"summary\", \"people\", \"places\"])\n\n// Variable (property) declarations\ncollector.variables.count // 3\ncollector.variables[0].name // \"people\"\ncollector.variables[1].typeAnnotation // \"[Place]\"\ncollector.variables[2].name // \"tableView\"\ncollector.variables[2].typeAnnotation // \"UITableView!\"\ncollector.variables[2].attributes.first?.name // \"IBOutlet\"\ncollector.variables[2].modifiers.first?.name // \"private\"\ncollector.variables[2].modifiers.first?.detail // \"set\"\n```\n\n\u003e **Note**:\n\u003e For more information about SwiftSyntax,\n\u003e see [this article from NSHipster][nshipster swiftsyntax].\n\nThis package is used by [swift-doc][swift-doc]\nin coordination with [SwiftMarkup][swiftmarkup]\nto generate documentation for Swift projects\n_([including this one][swiftsemantics documentation])_.\n\n## Requirements\n\n- Swift 5.2, 5.3, 5.4, or 5.5\n\n## Installation\n\n### Swift Package Manager\n\nAdd the SwiftSemantics package to your target dependencies in `Package.swift`:\n\n```swift\n// swift-tools-version:5.3\n\nimport PackageDescription\n\nlet package = Package(\n  name: \"YourProject\",\n  dependencies: [\n    .package(\n        name: \"SwiftSemantics\",\n        url: \"https://github.com/SwiftDocOrg/SwiftSemantics\",\n        .exact(\"0.3.2\")\n    )\n  ]\n)\n```\n\nIf your project has a direct dependency `SwiftSyntax`,\nuse the declaration below that corresponds to your Swift language version:\n\n```swift\n// Swift 5.2\n.package(url: \"https://github.com/apple/swift-syntax.git\",\n         .exact(\"0.50200.0\")),\n\n// Swift 5.3\n.package(name: \"SwiftSyntax\",\n         url: \"https://github.com/apple/swift-syntax.git\",\n         .exact(\"0.50300.0\")),\n\n// Swift 5.4\n.package(name: \"SwiftSyntax\",\n         url: \"https://github.com/apple/swift-syntax.git\",\n         .revision(\"release/5.4\")),\n\n// Swift 5.5\n.package(name: \"SwiftSyntax\",\n         url: \"https://github.com/apple/swift-syntax.git\",\n         .revision(\"release/5.5\")),\n```\n\n## Detailed Design\n\nSwift defines 17 different kinds of declarations,\neach of which is represented by a corresponding type in SwiftSemantics\nthat conforms to the\n[`Declaration` protocol](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Declaration):\n\n- [`AssociatedType`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/AssociatedType)\n- [`Class`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Class)\n- [`ConditionalCompilationBlock`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/ConditionalCompilationBlock)\n- [`Deinitializer`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Deinitializer)\n- [`Enumeration`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Enumeration)\n- [`Enumeration.Case`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Enumeration_Case)\n- [`Extension`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Extension)\n- [`Function`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Function)\n- [`Import`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Import)\n- [`Initializer`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Initializer)\n- [`Operator`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Operator)\n- [`PrecedenceGroup`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/PrecedenceGroup)\n- [`Protocol`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Protocol)\n- [`Structure`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Structure)\n- [`Subscript`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Subscript)\n- [`Typealias`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Typealias)\n- [`Variable`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Variable)\n\n\u003e **Note**:\n\u003e Examples of each declaration are provided in the documentation\n\u003e as well as [unit tests](https://github.com/SwiftDocOrg/SwiftSemantics/tree/master/Tests/SwiftSemanticsTests).\n\nThe `Declaration` protocol itself has no requirements.\nHowever,\nadopting types share many of the same properties,\nsuch as\n[`attributes`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Class#attributes),\n[`modifiers`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Class#modifiers),\nand\n[`keyword`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Class#keyword).\n\nSwiftSemantics declaration types are designed to\nmaximize the information provided by SwiftSyntax,\nclosely following the structure and naming conventions of syntax nodes.\nIn some cases,\nthe library takes additional measures to refine results\ninto more conventional interfaces.\nFor example,\nthe `PrecedenceGroup` type defines nested\n[`Associativity`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/PrecedenceGroup_Associativity)\nand\n[`Relation`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/PrecedenceGroup_Relation)\nenumerations for greater convenience and type safety.\nHowever, in other cases,\nresults may be provided in their original, raw `String` values;\nthis decision is typically motivated either by\nconcern for possible future changes to the language\nor simply out of practicality.\n\nFor the most part,\nthese design decisions allow developers with even a basic understanding of Swift\nto work productively with parsed declarations.\nThere are, however, some details that warrant further discussion:\n\n### Type Members Aren't Provided as Properties\n\nIn Swift,\na class, enumeration, or structure may contain\none or more initializers, properties, subscripts, and methods,\nknown as _members_.\nA type can itself be a member of another type,\nsuch as with `CodingKeys` enumerations nested within `Codable`-conforming types.\nLikewise, a type may also have one or more associated type or type alias members.\n\nSwiftSemantics doesn't provide built-in support for\naccessing type members directly from declaration values.\nThis is probably the most surprising\n(and perhaps contentious)\ndesign decision made in the library so far,\nbut we believe it to be the most reasonable option available.\n\nOne motivation comes down to delegation of responsibility:\n`DeclarationCollector` and other types conforming to `SyntaxVisitor`\nwalk the abstract syntax tree,\nrespond to nodes as they're visited,\nand decide whether to visit or skip a node's children.\nIf a `Declaration` were to initialize its own members,\nit would have the effect of overriding\nthe tree walker's decision to visit or skip any children.\nWe believe that an approach involving direct member initialization is inflexible\nand more likely to produce unexpected results.\nFor instance,\nif you wanted to walk the AST to collect only Swift class declarations,\nthere wouldn't be a clear way to avoid needlessly initializing\nthe members of each top-level class\nwithout potentially missing class declarations nested in other types.\n\nBut really,\nthe controlling motivation has to do with extensions ---\nespecially when used across multiple files in a module.\nConsider the following two Swift files in the same module:\n\n```swift\n// First.swift\nenum A { enum B { } }\n\n// Second.swift\nextension A.B { static func f(){} }\n```\n\nThe first file declares two enumerations:\n`A` and `B`, which is nested in `A`.\nThe second file declares an extension on the type `A.B`\nthat provides a static function `f()`.\nDepending on the order in which these files are processed,\nthe extension on `A.B` may precede any knowledge of `A` or `B`.\nThe capacity to reconcile these declarations exceeds\nthat of any individual declaration (or even a syntax walker),\nand any intermediate results would necessarily be incomplete\nand therefore misleading.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cem\u003eAnd if that weren't enough to dissuade you...\u003c/em\u003e\u003c/summary\u003e\n\nConsider what happens when we throw generically-constrained extensions\nand conditional compilation into the mix...\n\n```swift\n// Third.swift\n#if platform(linux)\nenum C {}\n#else\nprotocol P {}\nextension A.B where T: P { static func g(){} }\n#end\n```\n\n\u003c/details\u003e\n\nInstead,\nour approach delegates the responsibility for\nreconciling declaration contexts to API consumers.\n\nThis is the approach we settled on for [swift-doc][swift-doc],\nand it's worked reasonably well so far.\nThat said,\nwe're certainly open to hearing any alternative approaches\nand invite you to share any feedback about project architecture\nby [opening a new Issue](https://github.com/SwiftDocOrg/SwiftSemantics/issues/new).\n\n### Not All Language Features Are Encoded\n\nSwift is a complex language with many different rules and concepts,\nand not all of them are represented directly in SwiftSemantics.\n\nDeclaration membership,\ndiscussed in the previous section,\nis one such example.\nAnother is how\ndeclaration access modifiers like `public` and `private(set)`\naren't given any special treatment;\nthey're [`Modifier`](https://github.com/SwiftDocOrg/SwiftSemantics/wiki/Modifier) values\nlike any other.\n\nThis design strategy keeps the library narrowly focused\nand more adaptable to language evolution over time.\n\nYou can extend SwiftSemantics in your own code\nto encode any missing language concepts that are relevant to your problem.\nFor example,\nSwiftSemantics doesn't encode the concept of\n[property wrappers](https://nshipster.com/propertywrapper/),\nbut you could use it as the foundation of your own representation:\n\n```swift\nprotocol PropertyWrapperType {\n    var attributes: [Attribute] { get }\n}\n\nextension Class: PropertyWrapperType {}\nextension Enumeration: PropertyWrapperType {}\nextension Structure: PropertyWrapperType {}\n\nextension PropertyWrapperType {\n    var isPropertyWrapper: Bool {\n        return attributes.contains { $0.name == \"propertyWrapper\" }\n    }\n}\n```\n\n### Declarations Don't Include Header Documentation or Source Location\n\nDocumentation comments,\nlike regular comments and whitespace,\nare deemed by SwiftSyntax to be \"trivia\" for syntax nodes.\nTo keep this library narrowly focused,\nwe don't provide a built-in functionality for symbol documentation\n(source location is omitted from declarations for similar reasons).\n\nIf you wanted to do this yourself,\nyou could subclass `DeclarationCollector`\nand override the `visit` delegate methods\nto retrieve, parse, and associate documentation comments\nwith their corresponding declaration.\nAlternatively,\nyou can use [SwiftDoc][swift-doc],\nwhich — in conjunction with [SwiftMarkup][swiftmarkup] —\n_does_ offer this functionality.\n\n## Known Issues\n\n- Xcode cannot run unit tests (\u003ckbd\u003e⌘\u003c/kbd\u003e\u003ckbd\u003eU\u003c/kbd\u003e)\n  when opening the SwiftSemantics package directly,\n  as opposed first to generating an Xcode project file with\n  `swift package generate-xcodeproj`.\n  (The reported error is:\n  `Library not loaded: @rpath/lib_InternalSwiftSyntaxParser.dylib`).\n  As a workaround,\n  you can [install the latest toolchain](https://swift.org/download/)\n  and enable it in \"Xcode \u003e Preferences \u003e Components \u003e Toolchains\".\n  Alternatively,\n  you can run unit tests from the command line\n  with `swift test`.\n\n## License\n\nMIT\n\n## Contact\n\nMattt ([@mattt](https://twitter.com/mattt))\n\n[swiftsyntax]: https://github.com/apple/swift-syntax\n[nshipster swiftsyntax]: https://nshipster.com/swiftsyntax/\n[swift-doc]: https://github.com/SwiftDocOrg/swift-doc\n[swiftmarkup]: https://github.com/SwiftDocOrg/SwiftMarkup\n[swiftsemantics documentation]: https://github.com/SwiftDocOrg/SwiftSemantics/wiki\n\n[ci badge]: https://github.com/SwiftDocOrg/SwiftSemantics/workflows/CI/badge.svg\n[documentation badge]: https://github.com/SwiftDocOrg/SwiftSemantics/workflows/Documentation/badge.svg\n[documentation]: https://github.com/SwiftDocOrg/SwiftSemantics/wiki\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSwiftDocOrg%2FSwiftSemantics","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSwiftDocOrg%2FSwiftSemantics","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSwiftDocOrg%2FSwiftSemantics/lists"}