Swift API View (#1783)
* 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:
Родитель
f105dbb3e5
Коммит
75cf2ffd3c
|
@ -482,3 +482,4 @@ src/dotnet/APIView/APIViewWeb/wwwroot/js/*.js*
|
|||
|
||||
# npm
|
||||
*-lock.json
|
||||
src/swift/SwiftAPIView.xcworkspace/xcuserdata
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
|
@ -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,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.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Загрузка…
Ссылка в новой задаче