* Initial skeleton commit.

* In-Progress Commit

* In progress commit

* Update models for proper serialization. Basic iterative token generation. (#1790)

* Work in progress

* In progress commit

* Removed unused pod stuff

* Remove unused podfile and json edits

* In progress commit

* In progress commit:
	Tokens
	Navigation

* Swift: Refactoring and streamlining (#1791)

* Tweak helper names.

* Refactoring and indentation.

* Add missing properties to TokenFile.swift

* Fix up rebase issues.

* Work in progress

* SwiftAPIView: Load all swift files in a folder, not just a single source file (#1794)

* Load entire folder, not single source file

* Work with either a single file or folder.

* Remove unused file

* Fix bad merge.

* Add line IDs for structs and enums. (#1795)

* More progress

* In progress commit: added function support

* Swift APIView: Added support for variables and functions (#1797)

* Swiftformat and let/var annotations

* Rough support for functions

Co-authored-by: Jair <67484440+jairmyree@users.noreply.github.com>

* Stable APIView for demonstration

* Added navigation functionality

* Swift APIView: Clean up style issues. (#1801)

* Clean up style issues.

* Eliminate double : in type annotations

* Fix default log level.

* Sort navigation. (#1802)

* Swift APIView: Clickable type enhancements (#1805)

* Refactor type info.

* Refactoring

* Clickable inheritance clauses.

* Clickable result types.

* Partially clickable types in function signatures.

* Add Package.swift

* Revert Package.swift changes.

* Fixed the dest URL problem (#1812)

Co-authored-by: Jair Myree <t-jairmyree@microsoft.com>

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Add rudimentary dictionary support.

* Support generation from SwiftInterface files. (#1816)

* Swift APIView: Extract package name from --source (#1817)

* Extract package name from --source.

* Fix temp file deletion bug.

* Clean up unused code.

* Fail if unsupported declaration is needed instead of silent fail.

* Update README.md

Co-authored-by: Jair Myree <t-jairmyree@microsoft.com>
Co-authored-by: Jair <67484440+jairmyree@users.noreply.github.com>
This commit is contained in:
Travis Prescott 2021-07-19 13:53:29 -07:00 коммит произвёл GitHub
Родитель f105dbb3e5
Коммит 75cf2ffd3c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
22 изменённых файлов: 2655 добавлений и 1 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -482,3 +482,4 @@ src/dotnet/APIView/APIViewWeb/wwwroot/js/*.js*
# npm
*-lock.json
src/swift/SwiftAPIView.xcworkspace/xcuserdata

7
src/swift/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,7 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

22
src/swift/Info.plist Normal file
Просмотреть файл

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

34
src/swift/README.md Normal file
Просмотреть файл

@ -0,0 +1,34 @@
# APIView for Swift
SwiftAPIView is a plugin that converts `.swift` source code or `.swiftinterface` files to an APIView-compatible token file.
## Getting started
### Prerequisites
* Swift APIView is written in modern Swift 5. Due to this, Xcode 10.2 or higher is required.
### Build Instructions
1. Clone the `azure-sdk-tools` repository.
2. Open the `SwiftAPIView.xcodeproj` file, which should launch Xcode.
3. In Xcode, build the project file, which will automatically bring in the necessary dependencies.
### Execution Instructions
You may run the tool directly in Xcode or from the command line.
Parameters:
`--source`: May target a folder, which will collect all `*.swift` files, or a single `*.swift` or `*.swiftinterface` file.
`--dest`: (Optional) The path and desired JSON filename. If not provided, it will output as `SwiftAPIView.json` inside your documents directory.
#### Xcode
Edit `SwiftAPIView`'s "Run" scheme. This will allow you to pass `--source` and/or `--dest` as arguments using the "Arguments Passed on Launch" section in the "Arguments" tab.
#### Command Line
Navigate to the build artifacts folder from Xcode and then run:
```
./SwiftAPIView --source=<PATH_TO_SOURCE> --dest=<PATH_TO_DESTINATION_FILE>`
```

Просмотреть файл

@ -0,0 +1,143 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import AST
import Foundation
import Parser
import Source
/// Handles the generation of APIView JSON files.
class APIViewManager {
// MARK: Properties
static var shared = APIViewManager()
let args = CommandLineArguments()
var tokenFile: TokenFile!
// MARK: Methods
func run() throws {
guard let sourcePath = args.source else {
SharedLogger.fail("usage error: SwiftAPIView --source PATH")
}
guard let sourceUrl = URL(string: args.source ?? sourcePath) else {
SharedLogger.fail("usage error: `--source PATH` was invalid.")
}
try buildTokenFile(from: sourceUrl)
let destUrl: URL
if let destPath = args.dest {
destUrl = URL(fileURLWithPath: destPath)
} else {
let destPath = "SwiftAPIView.json"
guard let dest = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent(destPath) else {
SharedLogger.fail("Could not access file system.")
}
destUrl = dest
}
do {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let tokenData = try encoder.encode(tokenFile)
try tokenData.write(to: destUrl)
} catch {
SharedLogger.fail(error.localizedDescription)
}
}
/// Handles automatic processing of swiftinterface file, if supplied
func process(url sourceUrl: URL) throws -> SourceFile {
guard sourceUrl.absoluteString.hasSuffix("swiftinterface") else {
return try SourceReader.read(at: sourceUrl.absoluteString)
}
func check(line: String) -> String {
let needsBodyPatterns = [" init(", " init?(", " func ", " deinit"]
for pattern in needsBodyPatterns {
if line.contains(pattern) {
return "\(line) {}"
}
}
return line
}
var newLines = [String]()
let interfaceContents = try String(contentsOfFile: sourceUrl.absoluteString, encoding: .utf8)
for line in interfaceContents.components(separatedBy: .newlines) {
newLines.append(check(line: line))
}
// write modified swiftinterface file to temp location
let sourceDir = sourceUrl.deletingLastPathComponent()
let filename = sourceUrl.lastPathComponent
let tempFilename = "\(UUID().uuidString)_\(filename)"
let tempUrl = sourceDir.appendingPathComponent(tempFilename)
try newLines.joined(separator: "\n").write(toFile: tempUrl.absoluteString, atomically: true, encoding: .utf8)
defer { try! FileManager.default.removeItem(atPath: tempUrl.absoluteString) }
return try SourceReader.read(at: tempUrl.absoluteString)
}
func extractPackageName(from sourceUrl: URL) -> String {
let sourcePath = sourceUrl.path
let pattern = #"sdk\/[^\/]*\/([^\/]*)"#
let regex = try! NSRegularExpression(pattern: pattern, options: [])
let result = regex.matches(in: sourcePath, range: NSMakeRange(0, sourcePath.utf16.count))
let matchRange = Range(result[0].range(at: 1), in: sourcePath)!
return String(sourcePath[matchRange])
}
func buildTokenFile(from sourceUrl: URL) throws {
SharedLogger.debug("URL: \(sourceUrl.absoluteString)")
var declarations = [TopLevelDeclaration]()
var packageName: String
var isDir: ObjCBool = false
guard FileManager.default.fileExists(atPath: sourceUrl.path, isDirectory: &isDir) else {
SharedLogger.fail("\(sourceUrl.path) does not exist.")
}
// collect all swift files in a directory (and subdirectories)
if isDir.boolValue {
packageName = extractPackageName(from: sourceUrl)
let fileEnumerator = FileManager.default.enumerator(atPath: sourceUrl.path)
while let itemPath = fileEnumerator?.nextObject() as? String {
guard itemPath.hasSuffix(".swift") else { continue }
let itemUrl = sourceUrl.appendingPathComponent(itemPath)
let sourceFile = try SourceReader.read(at: itemUrl.absoluteString)
let topLevelDecl = try Parser(source: sourceFile).parse()
declarations.append(topLevelDecl)
}
} else {
// otherwise load a single file
packageName = sourceUrl.lastPathComponent
let sourceFile = try process(url: sourceUrl)
let topLevelDecl = try Parser(source: sourceFile).parse()
declarations.append(topLevelDecl)
}
tokenFile = TokenFile(name: packageName, packageName: packageName, versionString: version)
tokenFile.process(declarations)
}
}

Просмотреть файл

@ -0,0 +1,89 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import Foundation
class CommandLineArguments: Encodable {
private var rawArgs: [String: String]
/// Keys which are supported by Autorest.Swift
private let supportedKeys: [String] = [
"source",
"dest",
]
// MARK: Computed properties
/// Source path to Swift files
var source: String? {
return rawArgs["source"]
}
/// The desired output path for JSON file
var dest: String? {
return rawArgs["dest"]
}
// MARK: Initializers
init() {
rawArgs = [String: String]()
// Load arguments from direct command line (run standalone)
for item in CommandLine.arguments.dropFirst() {
let key = parseKey(from: item)
if supportedKeys.contains(key) == false {
SharedLogger.warn("SwiftAPIView does not recognize --\(key)")
}
let value = parseValue(from: item)
rawArgs[key] = value
}
}
/// Returns the argument key without the `--` prefix.
private func parseKey(from item: String) -> String {
guard let key = item.split(separator: "=", maxSplits: 1).map({ String($0) }).first else {
SharedLogger.fail("Item \(item) contained no key.")
}
guard key.hasPrefix("--") else {
SharedLogger.fail("Item \(key) expected to start with -- prefix.")
}
return String(key.dropFirst(2))
}
private func parseValue(from item: String) -> String {
let values = Array(item.split(separator: "=", maxSplits: 1).map { String($0) }.dropFirst())
switch values.count {
case 0:
// indicates flag
return "True"
case 1:
return values[0]
default:
SharedLogger.fail("Error in item \(item). Expected at most 1 value. Found \(values.count)")
}
}
}

Просмотреть файл

@ -0,0 +1,66 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import AST
import Foundation
extension DeclarationModifiers {
func verifySupported() {
for modifier in self {
switch modifier {
case .accessLevel, .static, .final:
continue
default:
SharedLogger.fail("Unsupported modifier: \(modifier)")
}
}
}
var accessLevel: AccessLevelModifier? {
for modifier in self {
switch modifier {
case let .accessLevel(value):
return value
default:
continue
}
}
return nil
}
var isStatic: Bool {
for modifier in self {
switch modifier {
case .static:
return true
default:
continue
}
}
return false
}
}

Просмотреть файл

@ -0,0 +1,62 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import Foundation
/// APIView navigation item for the left-hand navigation sidebar
class NavigationItem: Codable {
/// Text to display in the navigation sidebar
var text: String
/// Unique indentifier describing the navigation path
var navigationId: String?
/// Child navigation items
var childItems = [NavigationItem]()
/// Tags which determine the type of icon displayed in the navigation pane of APIView
var tags: NavigationTags
init(text: String, navigationId: String?, typeKind: NavigationTypeKind) {
self.text = text
self.navigationId = navigationId
tags = NavigationTags(typeKind: typeKind)
}
// MARK: Codable
enum CodingKeys: String, CodingKey {
case text = "Text"
case navigationId = "NavigationId"
case childItems = "ChildItems"
case tags = "Tags"
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(text, forKey: .text)
try container.encode(navigationId, forKey: .navigationId)
try container.encode(childItems, forKey: .childItems)
try container.encode(tags, forKey: .tags)
}
}

Просмотреть файл

@ -0,0 +1,54 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import Foundation
/// The kind of object being represented. Determines the icon displayed in APIView.
enum NavigationTypeKind: String, Codable {
case `class`
case interface
case `struct`
case `enum`
case delegate
case unknown
case assembly
}
/// Navigation tag, which determines the icon displayed in APIView
struct NavigationTags: Codable {
var typeKind: NavigationTypeKind?
// MARK: Codable
enum CodingKeys: String, CodingKey {
case typeKind = "TypeKind"
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(typeKind, forKey: .typeKind)
}
}

Просмотреть файл

@ -0,0 +1,857 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import AST
import Foundation
/// The token file that is readable by APIView
class TokenFile: Codable {
/// The name to be used in the APIView review list
var name: String
/// Package name for the review
var packageName: String
/// The version string
var versionString: String
// TODO: Should be switched to Swift once APIView supports
/// Language string.
let language = "Json"
/// List of APIVIew tokens to render
var tokens: [TokenItem]
/// List of APIView navigation items which display in the sidebar
var navigation: [NavigationItem]
/// Indentation level
private var indentLevel = 0
/// Number of spaces per indentation level
private let indentSpaces = 4
/// Access modifier to expose via APIView
private let publicModifiers: [AccessLevelModifier] = [.public, .open]
/// Controls whether a newline is needed
private var needsNewLine = false
/// Tracks assigned definition IDs so they can be linked where key is the name and value is the definition ID (which could be different)
private var definitionIds = [String: String]()
// MARK: Initializers
init(name: String, packageName: String, versionString: String) {
self.name = name
tokens = []
navigation = []
self.packageName = packageName
self.versionString = versionString
}
// MARK: Codable
enum CodingKeys: String, CodingKey {
case name = "Name"
case tokens = "Tokens"
case language = "Language"
case packageName = "PackageName"
case navigation = "Navigation"
case versionString = "VersionString"
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(packageName, forKey: .packageName)
try container.encode(language, forKey: .language)
try container.encode(tokens, forKey: .tokens)
try container.encode(navigation, forKey: .navigation)
try container.encode(versionString, forKey: .versionString)
}
// MARK: Token Emitter Methods
func text(_ text: String) {
let item = TokenItem(definitionId: nil, navigateToId: nil, value: text, kind: .text)
tokens.append(item)
needsNewLine = true
}
func newLine() {
let item = TokenItem(definitionId: nil, navigateToId: nil, value: nil, kind: .newline)
tokens.append(item)
if indentLevel > 0 {
whitespace(spaces: indentLevel)
}
needsNewLine = false
}
func whitespace(spaces: Int = 1) {
let value = String(repeating: " ", count: spaces)
let item = TokenItem(definitionId: nil, navigateToId: nil, value: value, kind: .whitespace)
tokens.append(item)
}
func punctuation(_ value: String) {
let item = TokenItem(definitionId: nil, navigateToId: nil, value: value, kind: .punctuation)
tokens.append(item)
needsNewLine = true
}
func keyword(value: String) {
let item = TokenItem(definitionId: nil, navigateToId: nil, value: value, kind: .keyword)
tokens.append(item)
needsNewLine = true
}
func lineIdMarker(definitionId: String? = nil) {
let item = TokenItem(definitionId: definitionId, navigateToId: nil, value: nil, kind: .lineIdMarker)
tokens.append(item)
}
func type(name: String, definitionId: String? = nil) {
let linkId = definitionIds[name]
let item = TokenItem(definitionId: definitionId, navigateToId: linkId, value: name, kind: .typeName)
tokens.append(item)
needsNewLine = true
}
func member(name: String, definitionId: String? = nil) {
let item = TokenItem(definitionId: definitionId, navigateToId: nil, value: name, kind: .memberName)
tokens.append(item)
needsNewLine = true
}
func stringLiteral(_ text: String) {
let item = TokenItem(definitionId: nil, navigateToId: nil, value: text, kind: .stringLiteral)
tokens.append(item)
needsNewLine = true
}
func indent(_ indentedCode: () -> Void) {
indentLevel += indentSpaces
indentedCode()
indentLevel -= indentSpaces
}
// MARK: Processing Methods
/// This should be the only process method that APIViewManager should be able to call
internal func process(_ declarations: [TopLevelDeclaration]) {
text("package")
whitespace()
text(packageName)
whitespace()
punctuation("{")
indent {
declarations.forEach { topLevelDecl in
process(topLevelDecl)
}
}
if needsNewLine {
newLine()
}
punctuation("}")
newLine()
navigation(from: declarations)
// ensure items appear in sorted order
navigation.sort(by: {$0.text < $1.text })
for item in navigation {
item.childItems.sort(by: { $0.text < $1.text })
}
}
private func process(_ decl: TopLevelDeclaration) {
if needsNewLine {
newLine()
}
for statement in decl.statements {
switch statement {
case let decl as Declaration:
process(decl)
default:
continue
}
}
}
private func process(_ decl: ClassDeclaration) {
// Gather Information
SharedLogger.debug(decl.textDescription)
SharedLogger.debug(decl.attributes.textDescription)
SharedLogger.debug(decl.genericWhereClause?.textDescription ?? "")
guard publicModifiers.contains(decl.accessLevelModifier ?? .internal) else {
return
}
let value = (decl.accessLevelModifier ?? .internal).textDescription
let defId = decl.name.textDescription
definitionIds[defId] = defId
newLine()
if !decl.attributes.isEmpty {
handle(attributes: decl.attributes)
}
lineIdMarker(definitionId: defId)
keyword(value: value)
whitespace()
if decl.isFinal {
keyword(value: "final")
whitespace()
}
keyword(value: "class")
whitespace()
type(name: decl.name.textDescription, definitionId: defId)
if let genericParam = decl.genericParameterClause {
handle(clause: genericParam)
}
if let inheritance = decl.typeInheritanceClause {
handle(clause: inheritance)
}
if let genericWhere = decl.genericWhereClause {
handle(clause: genericWhere)
}
punctuation("{")
indent {
for member in decl.members {
switch member {
case .declaration(let decl):
process(decl)
default:
continue
}
}
}
if needsNewLine {
newLine()
}
punctuation("}")
}
private func process(_ decl: StructDeclaration) {
SharedLogger.debug("Struct Declaration")
SharedLogger.debug(decl.textDescription)
guard publicModifiers.contains(decl.accessLevelModifier ?? .internal) else {
return
}
let value = (decl.accessLevelModifier ?? .internal).textDescription
let defId = decl.name.textDescription
definitionIds[defId] = defId
newLine()
if !decl.attributes.isEmpty {
handle(attributes: decl.attributes)
}
lineIdMarker(definitionId: defId)
keyword(value: value)
whitespace()
keyword(value: "struct")
whitespace()
type(name: decl.name.textDescription, definitionId: defId)
if let genericParam = decl.genericParameterClause {
handle(clause: genericParam)
}
if let inheritance = decl.typeInheritanceClause {
handle(clause: inheritance)
}
if let genericWhere = decl.genericWhereClause {
handle(clause: genericWhere)
}
punctuation("{")
indent {
for member in decl.members {
switch member {
case let .declaration(decl):
process(decl)
default:
continue
}
}
}
if needsNewLine {
newLine()
}
punctuation("}")
}
private func process(_ decl: EnumDeclaration) {
SharedLogger.debug("Enum Declaration")
SharedLogger.debug(decl.textDescription)
guard publicModifiers.contains(decl.accessLevelModifier ?? .internal) else {
return
}
let value = (decl.accessLevelModifier ?? .internal).textDescription
let defId = decl.name.textDescription
definitionIds[defId] = defId
newLine()
if !decl.attributes.isEmpty {
handle(attributes: decl.attributes)
}
if decl.isIndirect {
keyword(value: "indirect")
whitespace()
}
lineIdMarker(definitionId: defId)
keyword(value: value)
whitespace()
keyword(value: "enum")
whitespace()
type(name: decl.name.textDescription, definitionId: defId)
if let genericParam = decl.genericParameterClause {
whitespace()
handle(clause: genericParam)
}
if let inheritance = decl.typeInheritanceClause {
handle(clause: inheritance)
}
if let genericWhere = decl.genericWhereClause {
handle(clause: genericWhere)
}
punctuation("{")
indent {
for member in decl.members {
switch member {
case .declaration(let decl):
process(decl)
case .union(let enumCase):
enumCase.cases.forEach { enumCaseValue in
newLine()
let enumDefId = "\(decl.name.textDescription).\(enumCaseValue.name.textDescription)"
lineIdMarker(definitionId: enumDefId)
keyword(value: "case")
whitespace()
self.member(name: enumCaseValue.name.textDescription, definitionId: enumDefId)
}
case .rawValue(let enumCase):
enumCase.cases.forEach { enumCaseValue in
let enumDefId = "\(decl.name.textDescription).\(enumCaseValue.name.textDescription)"
lineIdMarker(definitionId: enumDefId)
keyword(value: "case")
whitespace()
newLine()
self.member(name: enumCaseValue.name.textDescription, definitionId: enumDefId)
}
default:
continue
}
}
}
if needsNewLine {
newLine()
}
punctuation("}")
}
private func process(_ decl: ProtocolDeclaration) {
SharedLogger.debug("Protocol Declaration")
SharedLogger.debug(decl.textDescription)
guard publicModifiers.contains(decl.accessLevelModifier ?? .internal) else {
return
}
let value = (decl.accessLevelModifier ?? .internal).textDescription
newLine()
if !decl.attributes.isEmpty {
handle(attributes: decl.attributes)
}
let defId = decl.name.textDescription
definitionIds[defId] = defId
keyword(value: value)
whitespace()
keyword(value: "protocol")
whitespace()
type(name: decl.name.textDescription, definitionId: defId)
whitespace()
if let inheritance = decl.typeInheritanceClause {
handle(clause: inheritance)
}
punctuation("{")
indent {
decl.members.forEach { member in
// TODO: Need to complete this
}
}
if needsNewLine {
newLine()
}
punctuation("}")
}
private func process(_ decl : TypealiasDeclaration) {
guard publicModifiers.contains(decl.accessLevelModifier ?? .internal) else {
return
}
let value = (decl.accessLevelModifier ?? .internal).textDescription
let defId = decl.name.textDescription
definitionIds[defId] = defId
newLine()
if !decl.attributes.isEmpty {
handle(attributes: decl.attributes)
}
keyword(value: value)
whitespace()
keyword(value: "typealias")
whitespace()
type(name: decl.name.textDescription, definitionId: defId)
if let genericParam = decl.generic {
handle(clause: genericParam)
}
whitespace()
punctuation("=")
whitespace()
text(decl.assignment.textDescription)
}
private func process(_ decl: VariableDeclaration) {
let accessLevel = decl.modifiers.accessLevel
var name = "NAME"
let isStatic = decl.modifiers.isStatic
var typeModel: TypeModel? = nil
decl.modifiers.verifySupported()
switch decl.body {
case let .initializerList(initializerList):
for item in initializerList {
if case let identPattern as IdentifierPattern = item.pattern {
name = identPattern.identifier.textDescription
typeModel = TypeModel(from: identPattern)
break
}
}
case let .codeBlock(ident, typeAnno, _):
typeModel = TypeModel(from: typeAnno)
name = ident.textDescription
case let .getterSetterKeywordBlock(ident, typeAnno, _):
typeModel = TypeModel(from: typeAnno)
name = ident.textDescription
default:
SharedLogger.fail("Unsupported variable body type: \(decl.body)")
}
guard publicModifiers.contains(accessLevel ?? .internal) else { return }
newLine()
keyword(value: accessLevel!.textDescription)
whitespace()
if isStatic {
keyword(value: "static")
whitespace()
}
keyword(value: "var")
whitespace()
lineIdMarker(definitionId: name)
member(name: name)
punctuation(":")
whitespace()
handle(typeModel: typeModel)
}
private func process(_ decl: ExtensionDeclaration) {
SharedLogger.debug("Extension Declaration")
SharedLogger.debug(decl.textDescription)
guard publicModifiers.contains(decl.accessLevelModifier ?? .internal) else {
return
}
let value = (decl.accessLevelModifier ?? .internal).textDescription
newLine()
if !decl.attributes.isEmpty {
handle(attributes: decl.attributes)
}
keyword(value: value)
whitespace()
keyword(value: "extension")
whitespace()
let defId = decl.type.textDescription
lineIdMarker(definitionId: defId)
type(name: decl.type.textDescription, definitionId: defId)
whitespace()
if let inheritance = decl.typeInheritanceClause {
handle(clause: inheritance)
}
if let genericWhere = decl.genericWhereClause {
handle(clause: genericWhere)
}
punctuation("{")
indent {
decl.members.forEach { member in
switch member {
case .declaration(let decl):
process(decl)
default:
return
}
}
}
if needsNewLine {
newLine()
}
punctuation("}")
}
private func process(_ decl: ConstantDeclaration) {
let accessLevel = decl.modifiers.accessLevel
var name = "NAME"
let isStatic = decl.modifiers.isStatic
var typeModel: TypeModel? = nil
decl.modifiers.verifySupported()
for item in decl.initializerList {
if case let identPattern as IdentifierPattern = item.pattern {
name = identPattern.identifier.textDescription
typeModel = TypeModel(from: identPattern)
}
}
guard publicModifiers.contains(accessLevel ?? .internal) else { return }
newLine()
keyword(value: accessLevel!.textDescription)
whitespace()
if isStatic {
keyword(value: "static")
whitespace()
}
keyword(value: "let")
whitespace()
lineIdMarker(definitionId: name)
member(name: name)
punctuation(":")
whitespace()
handle(typeModel: typeModel)
}
private func process(_ decl : InitializerDeclaration) {
SharedLogger.debug("Initializer Declaration")
guard publicModifiers.contains(decl.modifiers.accessLevel ?? .internal) else {
return
}
newLine()
if !decl.attributes.isEmpty {
handle(attributes: decl.attributes)
}
if !decl.modifiers.isEmpty {
handle(modifiers: decl.modifiers)
}
let defId = decl.textDescription
keyword(value: "init")
lineIdMarker(definitionId: defId)
if let genericParam = decl.genericParameterClause {
handle(clause: genericParam)
}
let initSignature = FunctionSignature(parameterList: decl.parameterList, throwsKind: decl.throwsKind, result: nil)
handle(signature: initSignature)
if let genericWhere = decl.genericWhereClause {
handle(clause: genericWhere)
}
}
private func process(_ decl: FunctionDeclaration) {
SharedLogger.debug("Function Declaration")
SharedLogger.debug(decl.signature.textDescription)
guard publicModifiers.contains(decl.modifiers.accessLevel ?? .internal) else {
return
}
newLine()
if !decl.attributes.isEmpty {
handle(attributes: decl.attributes)
}
handle(modifiers: decl.modifiers)
keyword(value: "func")
lineIdMarker(definitionId: name)
whitespace()
type(name: decl.name.textDescription, definitionId: decl.textDescription)
if let genericParam = decl.genericParameterClause {
whitespace()
handle(clause: genericParam)
}
handle(signature: decl.signature)
}
private func process(_ decl: Declaration) {
switch decl {
case let decl as ClassDeclaration:
return process(decl)
case let decl as ConstantDeclaration:
return process(decl)
case let decl as EnumDeclaration:
return process(decl)
case let decl as ExtensionDeclaration:
return process(decl)
case let decl as FunctionDeclaration:
return process(decl)
case let decl as InitializerDeclaration:
return process(decl)
case let decl as ProtocolDeclaration:
return process(decl)
case let decl as StructDeclaration:
return process(decl)
case let decl as TypealiasDeclaration:
return process(decl)
case let decl as VariableDeclaration:
return process(decl)
case _ as ImportDeclaration:
// Imports are no-op
return
default:
SharedLogger.fail("Unsupported declaration: \(decl)")
}
}
private func handle(modifiers: DeclarationModifiers) {
keyword(value: modifiers.textDescription)
whitespace()
}
private func handle(signature: FunctionSignature) {
func handle(parameter: FunctionSignature.Parameter) {
let externalNameText = parameter.externalName.map({ [$0.textDescription] }) ?? []
let localNameText = parameter.localName.textDescription.isEmpty ? [] : [parameter.localName.textDescription]
let nameText = (externalNameText + localNameText).joined(separator: " ")
let typeModel = TypeModel(from: parameter.typeAnnotation)
let defaultText =
parameter.defaultArgumentClause.map({ " = \($0.textDescription)" }) ?? ""
let varargsText = parameter.isVarargs ? "..." : ""
member(name: nameText)
punctuation(":")
whitespace()
self.handle(typeModel: typeModel)
stringLiteral(defaultText)
text(varargsText)
}
func handle(throws: ThrowsKind) {
switch `throws` {
case .throwing, .rethrowing:
keyword(value: `throws`.textDescription)
whitespace()
default:
return
}
}
func handle(result: FunctionResult?) {
guard let result = result else {
return
}
let typeModel = TypeModel(from: result.type)
punctuation("->")
whitespace()
self.handle(typeModel: typeModel)
}
punctuation("(")
var count = signature.parameterList.count - 1
signature.parameterList.forEach { parameter in
handle(parameter: parameter)
if count > 0 {
punctuation(",")
whitespace()
count -= 1
}
}
punctuation(")")
whitespace()
handle(throws: signature.throwsKind)
handle(result: signature.result)
}
private func handle(clause typeInheritance: TypeInheritanceClause) {
punctuation(":")
whitespace()
for (idx, item) in typeInheritance.typeInheritanceList.enumerated() {
let typeModel = TypeModel(from: item)
handle(typeModel: typeModel)
if idx != typeInheritance.typeInheritanceList.count - 1 {
punctuation(",")
whitespace()
}
}
whitespace()
}
private func handle(clause genericParam: GenericParameterClause) {
// TODO: Remove reliance on textDescription
text(genericParam.textDescription)
whitespace()
}
private func handle(clause genericWhere: GenericWhereClause) {
// TODO: Remove reliance on textDescription
text(genericWhere.textDescription)
whitespace()
}
private func handle(attributes: Attributes) {
// TODO: remove reliance on textDescription
keyword(value: attributes.textDescription)
newLine()
}
private func handle(typeModel: TypeModel?) {
guard let source = typeModel else { return }
if source.isArray { punctuation("[") }
type(name: source.name)
if source.isArray { punctuation("]") }
if source.isOptional {
punctuation("?")
}
}
// MARK: Navigation Emitter Methods
private func navigation(add item: NavigationItem) {
if let topItem = navigation.last {
topItem.childItems.append(item)
} else {
navigation.append(item)
}
}
private func navigation(from declarations: [TopLevelDeclaration]) {
let packageNavItem = NavigationItem(text: packageName, navigationId: nil, typeKind: .assembly)
declarations.forEach { decl in
let item = navigation(from: decl)
packageNavItem.childItems += item
}
navigation = [packageNavItem]
}
private func navigation(from decl: TopLevelDeclaration) -> [NavigationItem] {
var navItems: [NavigationItem] = []
decl.statements.forEach { stmt in
if let item = navigation(from: stmt) {
navItems.append(item)
}
}
return navItems
}
private func navigation(from decl: ClassDeclaration) -> NavigationItem? {
guard publicModifiers.contains(decl.accessLevelModifier ?? .internal) else {
return nil
}
let navItem = NavigationItem(text: decl.name.textDescription, navigationId: decl.name.textDescription, typeKind: .class)
decl.members.forEach { member in
switch member {
case let .declaration(decl):
if let item = navigation(from: decl) {
navItem.childItems.append(item)
}
case .compilerControl:
return
}
}
return navItem
}
private func navigation(from decl: StructDeclaration) -> NavigationItem? {
guard publicModifiers.contains(decl.accessLevelModifier ?? .internal) else {
return nil
}
let navItem = NavigationItem(text: decl.name.textDescription, navigationId: decl.name.textDescription, typeKind: .class)
decl.members.forEach { member in
switch member {
case let .declaration(decl):
if let item = navigation(from: decl) {
navItem.childItems.append(item)
}
case .compilerControl:
return
}
}
return navItem
}
private func navigation(from decl: EnumDeclaration) -> NavigationItem? {
guard publicModifiers.contains(decl.accessLevelModifier ?? .internal) else {
return nil
}
let navItem = NavigationItem(text: decl.name.textDescription, navigationId: decl.name.textDescription, typeKind: .class)
decl.members.forEach { member in
switch member {
case let .declaration(decl):
if let item = navigation(from: decl) {
navItem.childItems.append(item)
}
default:
return
}
}
return navItem
}
private func navigation(from decl: ProtocolDeclaration) -> NavigationItem? {
guard publicModifiers.contains(decl.accessLevelModifier ?? .internal) else {
return nil
}
let navItem = NavigationItem(text: decl.name.textDescription, navigationId: decl.name.textDescription, typeKind: .class)
return navItem
}
private func navigation(from decl: ExtensionDeclaration) -> NavigationItem? {
guard publicModifiers.contains(decl.accessLevelModifier ?? .internal) else {
return nil
}
let navItem = NavigationItem(text: decl.type.textDescription, navigationId: decl.type.textDescription, typeKind: .class)
decl.members.forEach { member in
switch member {
case let .declaration(decl):
if let item = navigation(from: decl) {
navItem.childItems.append(item)
}
default:
return
}
}
return navItem
}
private func navigation(from decl: Statement) -> NavigationItem? {
switch decl {
case let decl as ClassDeclaration:
return navigation(from: decl)
case let decl as EnumDeclaration:
return navigation(from: decl)
case let decl as ExtensionDeclaration:
return navigation(from: decl)
case let decl as ProtocolDeclaration:
return navigation(from: decl)
case let decl as StructDeclaration:
return navigation(from: decl)
default:
return nil
}
}
}

Просмотреть файл

@ -0,0 +1,78 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import Foundation
/// Enum for token kind
enum TokenKind: Int, Codable {
/// Text
case text = 0
/// Newline
case newline = 1
/// Whitespace
case whitespace = 2
/// Punctuation
case punctuation = 3
/// Swift keyword
case keyword = 4
/// used to display comment marker on lines with no visible tokens
case lineIdMarker = 5
/// Swift type name (class, structs, enums, etc.)
case typeName = 6
/// Variable names
case memberName = 7
/// Constants
case stringLiteral = 8
}
/// An individual token item
struct TokenItem: Codable {
// Allows tokens to be navigated to. Should be unique. Used as ID for comment thread.
var definitionId: String?
// If set, clicking on the token would navigate to the other token with this ID.
var navigateToId: String?
// Text value
var value: String?
// Token kind
var kind: TokenKind
// MARK: Codable
enum CodingKeys: String, CodingKey {
case definitionId = "DefinitionId"
case navigateToId = "NavigateToId"
case value = "Value"
case kind = "Kind"
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(definitionId, forKey: .definitionId)
try container.encode(navigateToId, forKey: .navigateToId)
try container.encode(value, forKey: .value)
try container.encode(kind, forKey: .kind)
}
}

Просмотреть файл

@ -0,0 +1,95 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import AST
import Foundation
struct TypeModel {
var name: String
var isOptional = false
var isArray = false
init(from source: IdentifierPattern) {
guard let typeAnnotation = source.typeAnnotation?.type else {
SharedLogger.fail("Missing type annotation.")
}
self.init(from: typeAnnotation)
}
init(from source: TypeAnnotation) {
self.init(from: source.type)
}
init(from source: OptionalType) {
self.init(from: source.wrappedType)
isOptional = true
}
init(from source: ArrayType) {
self.init(from: source.elementType)
isArray = true
}
init(from source: TypeIdentifier) {
let genericArgumentClauses = source.names.compactMap { $0.genericArgumentClause }
guard genericArgumentClauses.count < 2 else {
SharedLogger.fail("Unexpectedly found multiple generic argument clauses.")
}
if genericArgumentClauses.count == 1 {
// TODO: remove reliance on textDescription
name = source.textDescription
} else {
name = source.names.map { $0.name.textDescription }.joined(separator: ".")
}
}
init(from source: FunctionType) {
// TODO: remove reliance on textDescription
name = source.textDescription
}
init(from source: DictionaryType) {
// TODO: remove reliance on textDescription
name = source.textDescription
}
init(from source: Type) {
switch source {
case let src as OptionalType:
self.init(from: src)
case let src as TypeIdentifier:
self.init(from: src)
case let src as ArrayType:
self.init(from: src)
case let src as FunctionType:
self.init(from: src)
case let src as DictionaryType:
self.init(from: src)
default:
SharedLogger.fail("Unsupported identifier: \(source)")
}
}
}

Просмотреть файл

@ -0,0 +1,65 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import Foundation
@available(macOS 10.12, *)
public class SwiftClass<T> where T : Codable {
let text : String = "Yea boi"
public func test(name: String) throws -> Bool {
return true
}
}
public protocol TestProtocol {
}
public final class ThirdClass : TestProtocol {
}
@available(macOS 10.12, *)
public struct SwiftAPIViewResources: Codable {
static var text = "Hello, World!"
public let a = "yessir"
}
@available(macOS 10.12, *)
public class TestGeneric<T> {}
@available(macOS 10.12, *)
public indirect enum VariableNode<T> {
case endpoint(value: T)
case node(value: T, next: VariableNode)
}
public extension SwiftAPIViewResources {
func transition() throws {
print("I've transitioned")
}
}

Просмотреть файл

@ -0,0 +1,205 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import Foundation
import Foundation
enum LogLevel: Int {
case error, warning, info, debug
var label: String {
switch self {
case .error:
return "ERROR"
case .warning:
return "WARN"
case .info:
return "INFO"
case .debug:
return "DEBUG"
}
}
}
protocol Logger {
var level: LogLevel { get set }
func log(_ message: @autoclosure @escaping () -> String?, category: String?, level: LogLevel)
func fail(_ message: @autoclosure @escaping () -> String?, category: String?) -> Never
}
extension Logger {
func shouldLog(forLevel level: LogLevel) -> Bool {
return level.rawValue <= self.level.rawValue
}
}
// MARK: - Implementation
struct SharedLogger {
private static var logger: Logger!
static var level: LogLevel {
set {
logger.level = newValue
}
get {
logger.level
}
}
fileprivate static let `default` = "default"
static func set(logger: Logger, withLevel level: LogLevel = .info) {
SharedLogger.logger = logger
SharedLogger.level = level
}
static func error(
_ message: @autoclosure @escaping () -> String?,
category: String? = nil
) {
log(message(), category: category, level: .error)
}
static func warn(
_ message: @autoclosure @escaping () -> String?,
category: String? = nil
) {
log(message(), category: category, level: .warning)
}
static func info(
_ message: @autoclosure @escaping () -> String?,
category: String? = nil
) {
log(message(), category: category, level: .info)
}
static func debug(
_ message: @autoclosure @escaping () -> String?,
category: String? = nil
) {
log(message(), category: category, level: .debug)
}
private static func log(
_ message: @autoclosure @escaping () -> String?,
category: String? = nil,
level: LogLevel
) {
guard logger.shouldLog(forLevel: level) else { return }
SharedLogger.logger.log(message(), category: category ?? SharedLogger.default, level: level)
}
static func fail(
_ message: @autoclosure @escaping () -> String?,
category: String = SharedLogger.default
) -> Never {
SharedLogger.logger.fail(message(), category: category)
}
}
/// Do-nothing logger
class NullLogger: Logger {
var level: LogLevel = .info
func log(_: @autoclosure @escaping () -> String?, category _: String? = nil, level _: LogLevel = .info) {}
func fail(_: @autoclosure @escaping () -> String?, category _: String? = nil) -> Never {
fatalError()
}
}
/// Stdiout logger
class StdoutLogger: Logger {
// MARK: Properties
var level: LogLevel = .info
// MARK: Methods
func log(_ message: @autoclosure @escaping () -> String?, category: String? = nil, level: LogLevel) {
guard let msg = message() else {
fatalError("Unable to create log message.")
}
guard shouldLog(forLevel: level) else { return }
let cat = category ?? SharedLogger.default
print("SwiftAPIView.\(cat) (\(level.label)) \(msg)")
}
func fail(_ message: @autoclosure @escaping () -> String?, category: String? = nil) -> Never {
guard let msg = message() else {
fatalError("Unable to create log message.")
}
log(msg, category: category, level: .error)
fatalError(msg)
}
}
/// Logs to a file.
class FileLogger: Logger {
var level: LogLevel = .info
func log(_ message: @autoclosure @escaping () -> String?, category: String? = nil, level: LogLevel) {
guard var msg = message() else {
fatalError("Unable to create log message.")
}
guard shouldLog(forLevel: level) else { return }
if let cat = category {
msg = "SwiftAPIView.\(cat) (\(level.label)) \(msg)"
} else {
msg = "SwiftAPIView (\(level.label)) \(msg)"
}
try? url.append(line: msg)
}
func fail(_ message: @autoclosure @escaping () -> String?, category: String? = nil) -> Never {
guard let msg = message() else {
fatalError("Unable to create log message.")
}
log(msg, category: category, level: .error)
fatalError(msg)
}
// MARK: Properties
let url: URL
// MARK: Initializers
internal init(withFileName name: String, deleteIfExists: Bool = true) {
guard let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
fatalError("Unable to locate Documents directory.")
}
url = documentsUrl.appendingPathComponent(name)
if deleteIfExists {
try? FileManager.default.removeItem(atPath: url.path)
}
}
}

Просмотреть файл

@ -0,0 +1,54 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import Foundation
extension URL {
func ensureExists() throws {
let fileManager = FileManager.default
if let existing = try? resourceValues(forKeys: [.isDirectoryKey]) {
if !existing.isDirectory! {
let err = "Path exists but is not a folder!"
fatalError(err)
}
} else {
// Path does not exist so let us create it
try fileManager.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
}
}
func append(line: String) throws {
guard let lineData = "\(line)\n".data(using: .utf8) else { return }
if let handle = FileHandle(forWritingAtPath: path) {
defer { handle.closeFile() }
handle.seekToEndOfFile()
handle.write(lineData)
} else {
try lineData.write(to: self, options: .atomic)
}
}
}

Просмотреть файл

@ -0,0 +1,38 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------
import Foundation
let version = "1.0.0"
// Should be set to `.warning` normally
let logLevel = LogLevel.warning
SharedLogger.set(logger: StdoutLogger(), withLevel: logLevel)
do {
try APIViewManager.shared.run()
} catch {
SharedLogger.error("\(error)")
}

Просмотреть файл

@ -0,0 +1,518 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objects = {
/* Begin PBXBuildFile section */
0A6A5434268B82D0001006AF /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6A5433268B82D0001006AF /* main.swift */; };
0A6A5441268B886D001006AF /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6A5440268B886D001006AF /* Logger.swift */; };
0A6A5443268B88AE001006AF /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6A5442268B88AE001006AF /* URL+Extensions.swift */; };
0A6A5445268B89DE001006AF /* APIViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6A5444268B89DE001006AF /* APIViewManager.swift */; };
0A6A5447268B8B4F001006AF /* CommandLineArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6A5446268B8B4E001006AF /* CommandLineArguments.swift */; };
0A6A544A268B8EF9001006AF /* TokenFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6A5449268B8EF9001006AF /* TokenFile.swift */; };
0A6A544C268B8F67001006AF /* TokenItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6A544B268B8F67001006AF /* TokenItem.swift */; };
0A6A544E268B8F75001006AF /* NavigationItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6A544D268B8F75001006AF /* NavigationItem.swift */; };
0A6A5450268B91FC001006AF /* NavigationTags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6A544F268B91FC001006AF /* NavigationTags.swift */; };
0A6A545B269CAD5A001006AF /* TypeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6A545A269CAD59001006AF /* TypeModel.swift */; };
0A6A545E269CE223001006AF /* DeclarationModifier+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6A545D269CE223001006AF /* DeclarationModifier+Extensions.swift */; };
0A6A546C269E2AE8001006AF /* SwiftAPIViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6A546B269E2AE8001006AF /* SwiftAPIViewTests.swift */; };
0A6A5474269E2B83001006AF /* SwiftAST in Frameworks */ = {isa = PBXBuildFile; productRef = 0A6A5473269E2B83001006AF /* SwiftAST */; };
0A6A5476269E2B83001006AF /* SwiftAST+Tooling in Frameworks */ = {isa = PBXBuildFile; productRef = 0A6A5475269E2B83001006AF /* SwiftAST+Tooling */; };
31A6751B2697437400F92505 /* SourceCodeExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A6751A2697437400F92505 /* SourceCodeExample.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
0A6A542E268B82D0001006AF /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0A6A5430268B82D0001006AF /* SwiftAPIView */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = SwiftAPIView; sourceTree = BUILT_PRODUCTS_DIR; };
0A6A5433268B82D0001006AF /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
0A6A543B268B845A001006AF /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0A6A5440268B886D001006AF /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
0A6A5442268B88AE001006AF /* URL+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Extensions.swift"; sourceTree = "<group>"; };
0A6A5444268B89DE001006AF /* APIViewManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIViewManager.swift; sourceTree = "<group>"; };
0A6A5446268B8B4E001006AF /* CommandLineArguments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandLineArguments.swift; sourceTree = "<group>"; };
0A6A5449268B8EF9001006AF /* TokenFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenFile.swift; sourceTree = "<group>"; };
0A6A544B268B8F67001006AF /* TokenItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenItem.swift; sourceTree = "<group>"; };
0A6A544D268B8F75001006AF /* NavigationItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItem.swift; sourceTree = "<group>"; };
0A6A544F268B91FC001006AF /* NavigationTags.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationTags.swift; sourceTree = "<group>"; };
0A6A545A269CAD59001006AF /* TypeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypeModel.swift; sourceTree = "<group>"; };
0A6A545D269CE223001006AF /* DeclarationModifier+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DeclarationModifier+Extensions.swift"; sourceTree = "<group>"; };
0A6A545F269E2589001006AF /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
0A6A5469269E2AE8001006AF /* SwiftAPIViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftAPIViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
0A6A546B269E2AE8001006AF /* SwiftAPIViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftAPIViewTests.swift; sourceTree = "<group>"; };
0A6A546D269E2AE8001006AF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
31A6751A2697437400F92505 /* SourceCodeExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceCodeExample.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
0A6A542D268B82D0001006AF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0A6A5476269E2B83001006AF /* SwiftAST+Tooling in Frameworks */,
0A6A5474269E2B83001006AF /* SwiftAST in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0A6A5466269E2AE8001006AF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0A6A5427268B82D0001006AF = {
isa = PBXGroup;
children = (
0A6A545F269E2589001006AF /* README.md */,
0A6A543B268B845A001006AF /* Info.plist */,
0A6A5432268B82D0001006AF /* Sources */,
0A6A546A269E2AE8001006AF /* Tests */,
0A6A5431268B82D0001006AF /* Products */,
6F4C0E2E04E03C6B3145C4A1 /* Frameworks */,
);
sourceTree = "<group>";
};
0A6A5431268B82D0001006AF /* Products */ = {
isa = PBXGroup;
children = (
0A6A5430268B82D0001006AF /* SwiftAPIView */,
0A6A5469269E2AE8001006AF /* SwiftAPIViewTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
0A6A5432268B82D0001006AF /* Sources */ = {
isa = PBXGroup;
children = (
0A6A545C269CE213001006AF /* Extensions */,
0A6A5448268B8EED001006AF /* Models */,
0A6A543F268B8862001006AF /* Util */,
0A6A5433268B82D0001006AF /* main.swift */,
0A6A5444268B89DE001006AF /* APIViewManager.swift */,
0A6A5446268B8B4E001006AF /* CommandLineArguments.swift */,
31A6751A2697437400F92505 /* SourceCodeExample.swift */,
);
path = Sources;
sourceTree = "<group>";
};
0A6A543F268B8862001006AF /* Util */ = {
isa = PBXGroup;
children = (
0A6A5440268B886D001006AF /* Logger.swift */,
0A6A5442268B88AE001006AF /* URL+Extensions.swift */,
);
path = Util;
sourceTree = "<group>";
};
0A6A5448268B8EED001006AF /* Models */ = {
isa = PBXGroup;
children = (
0A6A544D268B8F75001006AF /* NavigationItem.swift */,
0A6A544F268B91FC001006AF /* NavigationTags.swift */,
0A6A5449268B8EF9001006AF /* TokenFile.swift */,
0A6A544B268B8F67001006AF /* TokenItem.swift */,
0A6A545A269CAD59001006AF /* TypeModel.swift */,
);
path = Models;
sourceTree = "<group>";
};
0A6A545C269CE213001006AF /* Extensions */ = {
isa = PBXGroup;
children = (
0A6A545D269CE223001006AF /* DeclarationModifier+Extensions.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
0A6A546A269E2AE8001006AF /* Tests */ = {
isa = PBXGroup;
children = (
0A6A546B269E2AE8001006AF /* SwiftAPIViewTests.swift */,
0A6A546D269E2AE8001006AF /* Info.plist */,
);
path = Tests;
sourceTree = "<group>";
};
6F4C0E2E04E03C6B3145C4A1 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
0A6A542F268B82D0001006AF /* SwiftAPIView */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0A6A5437268B82D0001006AF /* Build configuration list for PBXNativeTarget "SwiftAPIView" */;
buildPhases = (
0A6A542C268B82D0001006AF /* Sources */,
0A6A542D268B82D0001006AF /* Frameworks */,
0A6A542E268B82D0001006AF /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = SwiftAPIView;
packageProductDependencies = (
0A6A5473269E2B83001006AF /* SwiftAST */,
0A6A5475269E2B83001006AF /* SwiftAST+Tooling */,
);
productName = SwiftAPIView;
productReference = 0A6A5430268B82D0001006AF /* SwiftAPIView */;
productType = "com.apple.product-type.tool";
};
0A6A5468269E2AE8001006AF /* SwiftAPIViewTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0A6A546E269E2AE8001006AF /* Build configuration list for PBXNativeTarget "SwiftAPIViewTests" */;
buildPhases = (
0A6A5465269E2AE8001006AF /* Sources */,
0A6A5466269E2AE8001006AF /* Frameworks */,
0A6A5467269E2AE8001006AF /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = SwiftAPIViewTests;
productName = SwiftAPIViewTests;
productReference = 0A6A5469269E2AE8001006AF /* SwiftAPIViewTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
0A6A5428268B82D0001006AF /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1250;
LastUpgradeCheck = 1250;
TargetAttributes = {
0A6A542F268B82D0001006AF = {
CreatedOnToolsVersion = 12.5.1;
};
0A6A5468269E2AE8001006AF = {
CreatedOnToolsVersion = 12.5.1;
};
};
};
buildConfigurationList = 0A6A542B268B82D0001006AF /* Build configuration list for PBXProject "SwiftAPIView" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 0A6A5427268B82D0001006AF;
packageReferences = (
0A6A5472269E2B83001006AF /* XCRemoteSwiftPackageReference "swift-ast" */,
);
productRefGroup = 0A6A5431268B82D0001006AF /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
0A6A542F268B82D0001006AF /* SwiftAPIView */,
0A6A5468269E2AE8001006AF /* SwiftAPIViewTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
0A6A5467269E2AE8001006AF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
0A6A542C268B82D0001006AF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0A6A545B269CAD5A001006AF /* TypeModel.swift in Sources */,
0A6A5450268B91FC001006AF /* NavigationTags.swift in Sources */,
0A6A5447268B8B4F001006AF /* CommandLineArguments.swift in Sources */,
0A6A544A268B8EF9001006AF /* TokenFile.swift in Sources */,
0A6A544C268B8F67001006AF /* TokenItem.swift in Sources */,
31A6751B2697437400F92505 /* SourceCodeExample.swift in Sources */,
0A6A5434268B82D0001006AF /* main.swift in Sources */,
0A6A545E269CE223001006AF /* DeclarationModifier+Extensions.swift in Sources */,
0A6A5443268B88AE001006AF /* URL+Extensions.swift in Sources */,
0A6A5445268B89DE001006AF /* APIViewManager.swift in Sources */,
0A6A544E268B8F75001006AF /* NavigationItem.swift in Sources */,
0A6A5441268B886D001006AF /* Logger.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0A6A5465269E2AE8001006AF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0A6A546C269E2AE8001006AF /* SwiftAPIViewTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
0A6A5435268B82D0001006AF /* 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++14";
CLANG_CXX_LIBRARY = "libc++";
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;
GCC_C_LANGUAGE_STANDARD = gnu11;
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;
MACOSX_DEPLOYMENT_TARGET = 11.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
0A6A5436268B82D0001006AF /* 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++14";
CLANG_CXX_LIBRARY = "libc++";
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;
GCC_C_LANGUAGE_STANDARD = gnu11;
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;
MACOSX_DEPLOYMENT_TARGET = 11.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
0A6A5438268B82D0001006AF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = ZQB5E94758;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.SwiftAPIView;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
0A6A5439268B82D0001006AF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = ZQB5E94758;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.SwiftAPIView;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Release;
};
0A6A546F269E2AE8001006AF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = UBF8T346G9;
INFOPLIST_FILE = SwiftAPIViewTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.azure.SwiftAPIViewTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
0A6A5470269E2AE8001006AF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = UBF8T346G9;
INFOPLIST_FILE = SwiftAPIViewTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.azure.SwiftAPIViewTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
0A6A542B268B82D0001006AF /* Build configuration list for PBXProject "SwiftAPIView" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0A6A5435268B82D0001006AF /* Debug */,
0A6A5436268B82D0001006AF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0A6A5437268B82D0001006AF /* Build configuration list for PBXNativeTarget "SwiftAPIView" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0A6A5438268B82D0001006AF /* Debug */,
0A6A5439268B82D0001006AF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0A6A546E269E2AE8001006AF /* Build configuration list for PBXNativeTarget "SwiftAPIViewTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0A6A546F269E2AE8001006AF /* Debug */,
0A6A5470269E2AE8001006AF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
0A6A5472269E2B83001006AF /* XCRemoteSwiftPackageReference "swift-ast" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/yanagiba/swift-ast";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.19.9;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
0A6A5473269E2B83001006AF /* SwiftAST */ = {
isa = XCSwiftPackageProductDependency;
package = 0A6A5472269E2B83001006AF /* XCRemoteSwiftPackageReference "swift-ast" */;
productName = SwiftAST;
};
0A6A5475269E2B83001006AF /* SwiftAST+Tooling */ = {
isa = XCSwiftPackageProductDependency;
package = 0A6A5472269E2B83001006AF /* XCRemoteSwiftPackageReference "swift-ast" */;
productName = "SwiftAST+Tooling";
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 0A6A5428268B82D0001006AF /* Project object */;
}

Просмотреть файл

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0A6A542F268B82D0001006AF"
BuildableName = "SwiftAPIView"
BlueprintName = "SwiftAPIView"
ReferencedContainer = "container:SwiftAPIView.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<PathRunnable
runnableDebuggingMode = "0"
BundleIdentifier = "com.apple.Terminal"
FilePath = "/System/Applications/Utilities/Terminal.app">
</PathRunnable>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0A6A542F268B82D0001006AF"
BuildableName = "SwiftAPIView"
BlueprintName = "SwiftAPIView"
ReferencedContainer = "container:SwiftAPIView.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
<CommandLineArgument
argument = "$(BUILT_PRODUCTS_DIR)/$(FULL_PRODUCT_NAME)"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0A6A542F268B82D0001006AF"
BuildableName = "SwiftAPIView"
BlueprintName = "SwiftAPIView"
ReferencedContainer = "container:SwiftAPIView.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

Просмотреть файл

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0A6A542F268B82D0001006AF"
BuildableName = "SwiftAPIView"
BlueprintName = "SwiftAPIView"
ReferencedContainer = "container:SwiftAPIView.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0A6A542F268B82D0001006AF"
BuildableName = "SwiftAPIView"
BlueprintName = "SwiftAPIView"
ReferencedContainer = "container:SwiftAPIView.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "--source=/Users/jairmyree/Desktop/azure-sdk-for-ios/sdk/communication/AzureCommunicationChat/Source"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--source=/Users/travisprescott/repos/azure-sdk-for-ios/sdk/communication/AzureCommunicationChat/Source"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
<LocationScenarioReference
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
referenceType = "1">
</LocationScenarioReference>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0A6A542F268B82D0001006AF"
BuildableName = "SwiftAPIView"
BlueprintName = "SwiftAPIView"
ReferencedContainer = "container:SwiftAPIView.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

Просмотреть файл

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>SwiftAPIView on Terminal.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>SwiftAPIView.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
<key>SwiftAPIViewTests.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>0A6A542F268B82D0001006AF</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

Просмотреть файл

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

Просмотреть файл

@ -0,0 +1,32 @@
//
// SwiftAPIViewTests.swift
// SwiftAPIViewTests
//
// Created by Travis Prescott on 7/13/21.
//
import XCTest
class SwiftAPIViewTests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() throws {
// This is an example of a performance test case.
measure {
// Put the code you want to measure the time of here.
}
}
}