├── .github └── workflows │ └── swift.yml ├── .gitignore ├── Codable ├── Codable.entitlements ├── Command.swift ├── Info.plist ├── OptionalExtension.swift ├── Regex.swift ├── SourceEditorCommand.swift ├── SourceEditorExtension.swift └── StringExtension.swift ├── LICENSE ├── README.md ├── TrickerX.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ └── TrickerX.xcscheme └── xcuserdata │ └── ray.xcuserdatad │ └── xcschemes │ └── Codable.xcscheme ├── TrickerX ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── Main.storyboard ├── Info.plist ├── TrickerX.entitlements └── ViewController.swift ├── TrickerXTests ├── CodableRegexTests.swift ├── Info.plist └── TrickerXTests.swift ├── app └── TrickerX.dmg ├── codable.gif └── fastlane ├── Appfile ├── Fastfile ├── README.md └── make_dmg /.github/workflows/swift.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Swift project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift 3 | 4 | name: Swift 5 | 6 | on: 7 | push: 8 | branches: [ "master" ] 9 | pull_request: 10 | branches: [ "master" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: macos-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Build 20 | run: swift build -v 21 | - name: Run tests 22 | run: swift test -v 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | xcuserdata 20 | *.DS_Store 21 | *.xcworkspace 22 | 23 | ## Other 24 | *.moved-aside 25 | *.xccheckout 26 | *.xcscmblueprint 27 | 28 | ## Obj-C/Swift specific 29 | *.hmap 30 | *.ipa 31 | *.dSYM.zip 32 | *.dSYM 33 | 34 | ## Playgrounds 35 | timeline.xctimeline 36 | playground.xcworkspace 37 | 38 | # Swift Package Manager 39 | # 40 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 41 | # Packages/ 42 | # Package.pins 43 | # Package.resolved 44 | .build/ 45 | 46 | # CocoaPods 47 | # 48 | # We recommend against adding the Pods directory to your .gitignore. However 49 | # you should judge for yourself, the pros and cons are mentioned at: 50 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 51 | # 52 | # Pods/ 53 | 54 | # Carthage 55 | # 56 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 57 | # Carthage/Checkouts 58 | 59 | Carthage/Build 60 | 61 | # fastlane 62 | # 63 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 64 | # screenshots whenever they are needed. 65 | # For more information about the recommended setup visit: 66 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 67 | 68 | fastlane/report.xml 69 | fastlane/Preview.html 70 | fastlane/screenshots 71 | fastlane/test_output 72 | -------------------------------------------------------------------------------- /Codable/Codable.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Codable/Command.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Command.swift 3 | // Codable 4 | // 5 | // Created by Lei Wang on 2017/12/6. 6 | // Copyright © 2017年 Lei Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | enum Command: RawRepresentable { 13 | 14 | var rawValue: String { 15 | switch self { 16 | case .makeCodingKeys(let isSorting): 17 | if isSorting { 18 | return "makeCodingKeysWithSorting" 19 | }else { 20 | return "makeCodingKeys" 21 | } 22 | case .readme: 23 | return "readme" 24 | } 25 | } 26 | 27 | init?(rawValue: String) { 28 | switch rawValue { 29 | case "makeCodingKeys": 30 | self = .makeCodingKeys(sorting: false) 31 | case "makeCodingKeysWithSorting": 32 | self = .makeCodingKeys(sorting: true) 33 | case "readme": 34 | self = .readme 35 | default: 36 | return nil 37 | } 38 | } 39 | case makeCodingKeys(sorting: Bool) 40 | case readme 41 | 42 | var displayName: String { 43 | switch self { 44 | case .makeCodingKeys(let isSorting): 45 | if isSorting { 46 | return "Make Coding Key With Sorting" 47 | }else { 48 | return "Make Coding Key" 49 | } 50 | case .readme: 51 | return "README" 52 | } 53 | } 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /Codable/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Codable 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSExtension 26 | 27 | NSExtensionAttributes 28 | 29 | XCSourceEditorExtensionPrincipalClass 30 | $(PRODUCT_MODULE_NAME).SourceEditorExtension 31 | 32 | NSExtensionPointIdentifier 33 | com.apple.dt.Xcode.extension.source-editor 34 | 35 | NSHumanReadableCopyright 36 | Copyright © 2017年 Lei Wang. All rights reserved. 37 | 38 | 39 | -------------------------------------------------------------------------------- /Codable/OptionalExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OptionalExtension.swift 3 | // Codable 4 | // 5 | // Created by Lei Wang on 2017/12/6. 6 | // Copyright © 2017年 Lei Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | extension Optional where Wrapped == String { 13 | var unwrappedOrEmpty: String { 14 | switch self { 15 | case let .some(wrapped): 16 | return wrapped 17 | default: 18 | return "" 19 | } 20 | } 21 | } 22 | extension Optional where Wrapped: Collection { 23 | var isNilOrEmpty: Bool { 24 | switch self { 25 | case let .some(wrapped): 26 | return wrapped.isEmpty 27 | default: 28 | return true 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Codable/Regex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Regex.swift 3 | // TrickerX 4 | // 5 | // Created by Lei Wang on 2017/12/7. 6 | // Copyright © 2017年 Lei Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum Regex: String { 12 | case codableModelStartLine = ".+\\s*:\\s*.*(Codable|Decodable|Encodable).*\\{" 13 | case openBracket = "\\{" 14 | case closeBracket = "\\}" 15 | case closureOrTuple = "\\(.*\\)" 16 | case spaceOrTabIndent = "^(\\s|\\t)*" 17 | case toggleComments = "^\\s*\\/\\/" 18 | 19 | case codablePropertyLine = ".*(let|var)\\s+\\w+\\s*(:|=).+" 20 | case codablePropertyName = "\\w+(?=\\s*:)" 21 | case customKey = "\\/\\/\\s*\\w+" 22 | } 23 | -------------------------------------------------------------------------------- /Codable/SourceEditorCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SourceEditorCommand.swift 3 | // Codable 4 | // 5 | // Created by Lei Wang on 2017/11/24. 6 | // Copyright © 2017年 Lei Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XcodeKit 11 | import AppKit 12 | 13 | class SourceEditorCommand: NSObject, XCSourceEditorCommand { 14 | 15 | func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void { 16 | let command = Command.init(rawValue: invocation.commandIdentifier) 17 | command?.perform(with: invocation, completionHandler: completionHandler) 18 | 19 | } 20 | 21 | } 22 | 23 | 24 | private let Github = "https://github.com/wleii/TrickerX" 25 | 26 | enum TrickerXError: CustomDebugStringConvertible, CustomStringConvertible { 27 | case noSelectionFound 28 | case notFoundCodableModel 29 | case codablePropertyEmpty 30 | 31 | var localizedDescription: String { 32 | return description 33 | } 34 | 35 | var description: String { 36 | switch self { 37 | case .noSelectionFound: 38 | return "Not found selection line where to make CodingKeys" 39 | case .notFoundCodableModel: 40 | return "Not found codable model. Please add codable protocol where your model want to inherit" 41 | case .codablePropertyEmpty: 42 | return "Not found available codable properties. If you have a doubt about this, please check the documents: \(Github)" 43 | } } 44 | var debugDescription: String { 45 | return description 46 | } 47 | 48 | private var errorCode: Int { 49 | return 404 50 | } 51 | 52 | var asNSError: NSError { 53 | let domain = "com.rayternet.codable.error" 54 | let userInfo = [NSLocalizedDescriptionKey: description] 55 | return NSError(domain: domain, code: errorCode, userInfo: userInfo) 56 | } 57 | } 58 | 59 | 60 | private extension Command { 61 | 62 | func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void { 63 | switch self { 64 | case .makeCodingKeys(let isSortingKey): 65 | guard let textRange = invocation.buffer.selections.firstObject as? XCSourceTextRange else { 66 | completionHandler(TrickerXError.noSelectionFound.asNSError) 67 | return 68 | } 69 | var startLine = textRange.start.line 70 | 71 | var bracketCount: Int = 0 72 | var isMatchCodableModelStartLine: Bool = false 73 | var enumCase: [(key: String, value: String)] = [] 74 | 75 | while startLine >= 0 { 76 | guard let lineText = invocation.buffer.lines[startLine] as? String else { startLine -= 1; continue } 77 | 78 | 79 | // toggle comments 80 | if !lineText.match(regex: .toggleComments).isNilOrEmpty { 81 | startLine -= 1 82 | continue 83 | } 84 | 85 | // find { or } 86 | let closeBracket: [String] = lineText.match(regex: Regex.closeBracket.rawValue) 87 | let openBracket: [String] = lineText.match(regex: Regex.openBracket.rawValue) 88 | 89 | bracketCount += closeBracket.count 90 | 91 | if bracketCount > 0 { 92 | // not full {} continue ⬆️ parse 93 | bracketCount -= openBracket.count 94 | startLine -= 1 95 | continue 96 | } 97 | if !lineText.match(regex: .codableModelStartLine).isNilOrEmpty { 98 | // the end, then break 99 | isMatchCodableModelStartLine = true 100 | break 101 | } 102 | 103 | // 104 | if !lineText.match(regex: .closureOrTuple).isNilOrEmpty { 105 | startLine -= 1 106 | continue 107 | } 108 | 109 | // 110 | let codablePropertyLine = lineText.match(regex: .codablePropertyLine).unwrappedOrEmpty 111 | if codablePropertyLine.isEmpty { 112 | startLine -= 1 113 | continue 114 | } 115 | 116 | // parse property name 117 | let propertyName = codablePropertyLine.match(regex: .codablePropertyName).unwrappedOrEmpty 118 | 119 | let rawValue: String 120 | // check: is exist custom key? 121 | if let customRawValue = codablePropertyLine.match(regex: .customKey)?.match(regex: "\\w+"), !customRawValue.isEmpty { 122 | rawValue = customRawValue 123 | let splitStrings = codablePropertyLine.split(separator: "/") 124 | invocation.buffer.lines[startLine] = splitStrings.first! 125 | }else { 126 | let propertyRawValue = propertyName.snakeCased().unwrappedOrEmpty 127 | rawValue = propertyRawValue 128 | } 129 | enumCase.append((key: propertyName, value: rawValue)) 130 | 131 | // coontinue 132 | startLine -= 1 133 | 134 | } 135 | 136 | guard isMatchCodableModelStartLine else { 137 | // not match codable model start line 138 | completionHandler(TrickerXError.notFoundCodableModel.asNSError) 139 | return 140 | } 141 | 142 | guard !enumCase.isEmpty else { 143 | // codable keys empty 144 | completionHandler(TrickerXError.codablePropertyEmpty.asNSError) 145 | return 146 | } 147 | 148 | 149 | let startSelection = textRange.start.line 150 | let updateSelectionIndexs: [Int] = Array(startLine...startLine+(enumCase.count + 2)) 151 | 152 | let indentSpaces = (invocation.buffer.lines[textRange.start.line] as! String).match(regex: .spaceOrTabIndent).unwrappedOrEmpty.replacingOccurrences(of: "\n", with: "") 153 | let caseIndentSpaces = repeatElement(" ", count: invocation.buffer.indentationWidth).joined() 154 | if isSortingKey { 155 | enumCase = enumCase.sorted(by: {$0.0 < $1.1}) 156 | }else { 157 | enumCase = enumCase.reversed() 158 | } 159 | var lines = enumCase.reduce("\(indentSpaces)enum CodingKeys: String, CodingKey {\n") { (result, dict) -> String in 160 | if dict.key != dict.value { 161 | return result.appending("\(indentSpaces)\(caseIndentSpaces)case \(dict.key) = \"\(dict.value)\"\n") 162 | }else { 163 | return result.appending("\(indentSpaces)\(caseIndentSpaces)case \(dict.key)\n") 164 | } 165 | } 166 | lines += "\(indentSpaces)}" 167 | invocation.buffer.lines.insert(lines, at: startSelection) 168 | 169 | let textRanges = updateSelectionIndexs.map { (index) -> XCSourceTextRange in 170 | let sourceTextRange = XCSourceTextRange() 171 | sourceTextRange.start = XCSourceTextPosition(line: index, column: 0) 172 | sourceTextRange.end = XCSourceTextPosition(line: index, column: 0) 173 | return sourceTextRange 174 | } 175 | invocation.buffer.selections.setArray(textRanges) 176 | 177 | completionHandler(nil) 178 | case .readme: 179 | NSWorkspace.shared.open(URL.init(string: Github)!) 180 | completionHandler(nil) 181 | } 182 | } 183 | } 184 | 185 | 186 | -------------------------------------------------------------------------------- /Codable/SourceEditorExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SourceEditorExtension.swift 3 | // Codable 4 | // 5 | // Created by Lei Wang on 2017/11/24. 6 | // Copyright © 2017年 Lei Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XcodeKit 11 | 12 | class SourceEditorExtension: NSObject, XCSourceEditorExtension { 13 | 14 | /* 15 | func extensionDidFinishLaunching() { 16 | // If your extension needs to do any work at launch, implement this optional method. 17 | } 18 | */ 19 | 20 | var commandDefinitions: [[XCSourceEditorCommandDefinitionKey: Any]] { 21 | // If your extension needs to return a collection of command definitions that differs from those in its Info.plist, implement this optional property getter. 22 | let className = SourceEditorCommand.className() 23 | let commaneds: [Command] = [.makeCodingKeys(sorting: false), 24 | .makeCodingKeys(sorting: true), 25 | .readme] 26 | 27 | return commaneds.map({ (command) -> [XCSourceEditorCommandDefinitionKey: Any] in 28 | return [ 29 | .nameKey: command.displayName, 30 | .classNameKey: className, 31 | .identifierKey: command.rawValue, 32 | ] 33 | }) 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Codable/StringExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringExtension.swift 3 | // Codable 4 | // 5 | // Created by Lei Wang on 2017/12/6. 6 | // Copyright © 2017年 Lei Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | 13 | func match(regex: Regex) -> String? { 14 | return self.match(regex: regex.rawValue) 15 | } 16 | 17 | func match(regex: String) -> String? { 18 | let matchList: [String] = match(regex: regex) 19 | return matchList.first 20 | } 21 | 22 | func match(regex: String) -> [String] { 23 | if isEmpty { 24 | return [] 25 | } 26 | do { 27 | let regex = try NSRegularExpression(pattern: regex, options: []) 28 | let results = regex.matches(in: self, options: [], range: NSRange.init(startIndex..., in: self)) 29 | return results.map({ (result) -> String in 30 | let range = Range.init(result.range, in: self) 31 | return String(self[range!]) 32 | }) 33 | } 34 | catch { 35 | return [] 36 | } 37 | } 38 | 39 | func snakeCased() -> String? { 40 | let pattern = "([a-z0-9])([A-Z])" 41 | 42 | let regex = try? NSRegularExpression(pattern: pattern, options: []) 43 | let range = NSRange(location: 0, length: count) 44 | return regex?.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: "$1_$2").lowercased() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Lei Wang 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TrickerX 2 | An Xcode9+ Extension which make [CodingKeys](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types) automatically. 3 | 4 | ![Make CodingKeys](codable.gif) 5 | 6 | ## How to use 7 | 1. Download the installation [package](https://github.com/wleii/TrickerX/tree/master/app) I provide, or you can download project and build it yourself. 8 | 2. Open the App you have installed 9 | 3. Launch Xcode -> Open `Make CodingKey` File -> Editor -> Codable -> Make CodingKeys (PS: If you need, you can bind the shortcut key for this :] 10 | 11 | ## More specific methods of use 12 | TrickerX also support the following way to define keys, e.g. 13 | ```swift 14 | struct CustomKey: Codable { 15 | // TrickerX will parsing the syntax //my_custom_key 16 | private let key: String //my_custom_key 17 | } 18 | ``` 19 | result 20 | ```swift 21 | struct CustomKey: Codable { 22 | // TrickerX will parsing the syntax //my_custom_key 23 | private let key: String 24 | 25 | enum CodingKeys: String, Codable { 26 | case key = "my_custom_key" 27 | } 28 | } 29 | ``` 30 | ## Contributes 31 | 32 | Welcome :] 33 | 34 | ## License 35 | MIT 36 | -------------------------------------------------------------------------------- /TrickerX.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 719DB98D1FD817920080CD22 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = 719DB98C1FD817920080CD22 /* Command.swift */; }; 11 | 719DB98F1FD818730080CD22 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 719DB98E1FD818730080CD22 /* StringExtension.swift */; }; 12 | 719DB9911FD8187D0080CD22 /* OptionalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 719DB9901FD8187D0080CD22 /* OptionalExtension.swift */; }; 13 | 71B852911FC834F80084F597 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B852901FC834F80084F597 /* AppDelegate.swift */; }; 14 | 71B852931FC834F80084F597 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B852921FC834F80084F597 /* ViewController.swift */; }; 15 | 71B852951FC834F80084F597 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 71B852941FC834F80084F597 /* Assets.xcassets */; }; 16 | 71B852981FC834F80084F597 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71B852961FC834F80084F597 /* Main.storyboard */; }; 17 | 71B852CE1FC83A970084F597 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71B852A61FC835610084F597 /* Cocoa.framework */; }; 18 | 71B852D11FC83A970084F597 /* SourceEditorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B852D01FC83A970084F597 /* SourceEditorExtension.swift */; }; 19 | 71B852D31FC83A970084F597 /* SourceEditorCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B852D21FC83A970084F597 /* SourceEditorCommand.swift */; }; 20 | 71B852D81FC83A970084F597 /* Codable.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 71B852CD1FC83A970084F597 /* Codable.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 21 | 71C885841FD8F2800045737E /* TrickerXTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71C885831FD8F2800045737E /* TrickerXTests.swift */; }; 22 | 71C885901FD8F2F70045737E /* CodableRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71C8858E1FD8F2F70045737E /* CodableRegexTests.swift */; }; 23 | 71C885911FD8F33B0045737E /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 719DB98E1FD818730080CD22 /* StringExtension.swift */; }; 24 | 71C885931FD8F34D0045737E /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71C885921FD8F34D0045737E /* Regex.swift */; }; 25 | 71C885941FD8F34D0045737E /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71C885921FD8F34D0045737E /* Regex.swift */; }; 26 | 71C885951FD912C40045737E /* OptionalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 719DB9901FD8187D0080CD22 /* OptionalExtension.swift */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 71B852D61FC83A970084F597 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 71B852851FC834F80084F597 /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 71B852CC1FC83A970084F597; 35 | remoteInfo = Codable; 36 | }; 37 | 71C885861FD8F2800045737E /* PBXContainerItemProxy */ = { 38 | isa = PBXContainerItemProxy; 39 | containerPortal = 71B852851FC834F80084F597 /* Project object */; 40 | proxyType = 1; 41 | remoteGlobalIDString = 71B8528C1FC834F80084F597; 42 | remoteInfo = TrickerX; 43 | }; 44 | /* End PBXContainerItemProxy section */ 45 | 46 | /* Begin PBXCopyFilesBuildPhase section */ 47 | 71B852B51FC835610084F597 /* Embed App Extensions */ = { 48 | isa = PBXCopyFilesBuildPhase; 49 | buildActionMask = 2147483647; 50 | dstPath = ""; 51 | dstSubfolderSpec = 13; 52 | files = ( 53 | 71B852D81FC83A970084F597 /* Codable.appex in Embed App Extensions */, 54 | ); 55 | name = "Embed App Extensions"; 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | /* End PBXCopyFilesBuildPhase section */ 59 | 60 | /* Begin PBXFileReference section */ 61 | 719DB98C1FD817920080CD22 /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = ""; }; 62 | 719DB98E1FD818730080CD22 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = ""; }; 63 | 719DB9901FD8187D0080CD22 /* OptionalExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalExtension.swift; sourceTree = ""; }; 64 | 71B8528D1FC834F80084F597 /* TrickerX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TrickerX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | 71B852901FC834F80084F597 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 66 | 71B852921FC834F80084F597 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 67 | 71B852941FC834F80084F597 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 68 | 71B852971FC834F80084F597 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 69 | 71B852991FC834F90084F597 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 70 | 71B8529A1FC834F90084F597 /* TrickerX.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TrickerX.entitlements; sourceTree = ""; }; 71 | 71B852A61FC835610084F597 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 72 | 71B852CD1FC83A970084F597 /* Codable.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Codable.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 73 | 71B852D01FC83A970084F597 /* SourceEditorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceEditorExtension.swift; sourceTree = ""; }; 74 | 71B852D21FC83A970084F597 /* SourceEditorCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceEditorCommand.swift; sourceTree = ""; }; 75 | 71B852D41FC83A970084F597 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 76 | 71B852D51FC83A970084F597 /* Codable.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Codable.entitlements; sourceTree = ""; }; 77 | 71C885811FD8F2800045737E /* TrickerXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TrickerXTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 78 | 71C885831FD8F2800045737E /* TrickerXTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrickerXTests.swift; sourceTree = ""; }; 79 | 71C885851FD8F2800045737E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 80 | 71C8858E1FD8F2F70045737E /* CodableRegexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableRegexTests.swift; sourceTree = ""; }; 81 | 71C885921FD8F34D0045737E /* Regex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Regex.swift; sourceTree = ""; }; 82 | /* End PBXFileReference section */ 83 | 84 | /* Begin PBXFrameworksBuildPhase section */ 85 | 71B8528A1FC834F80084F597 /* Frameworks */ = { 86 | isa = PBXFrameworksBuildPhase; 87 | buildActionMask = 2147483647; 88 | files = ( 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | 71B852CA1FC83A970084F597 /* Frameworks */ = { 93 | isa = PBXFrameworksBuildPhase; 94 | buildActionMask = 2147483647; 95 | files = ( 96 | 71B852CE1FC83A970084F597 /* Cocoa.framework in Frameworks */, 97 | ); 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | 71C8857E1FD8F2800045737E /* Frameworks */ = { 101 | isa = PBXFrameworksBuildPhase; 102 | buildActionMask = 2147483647; 103 | files = ( 104 | ); 105 | runOnlyForDeploymentPostprocessing = 0; 106 | }; 107 | /* End PBXFrameworksBuildPhase section */ 108 | 109 | /* Begin PBXGroup section */ 110 | 71B852841FC834F80084F597 = { 111 | isa = PBXGroup; 112 | children = ( 113 | 71B8528F1FC834F80084F597 /* TrickerX */, 114 | 71B852CF1FC83A970084F597 /* Codable */, 115 | 71C885821FD8F2800045737E /* TrickerXTests */, 116 | 71B852A51FC835610084F597 /* Frameworks */, 117 | 71B8528E1FC834F80084F597 /* Products */, 118 | ); 119 | sourceTree = ""; 120 | }; 121 | 71B8528E1FC834F80084F597 /* Products */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 71B8528D1FC834F80084F597 /* TrickerX.app */, 125 | 71B852CD1FC83A970084F597 /* Codable.appex */, 126 | 71C885811FD8F2800045737E /* TrickerXTests.xctest */, 127 | ); 128 | name = Products; 129 | sourceTree = ""; 130 | }; 131 | 71B8528F1FC834F80084F597 /* TrickerX */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 71B852901FC834F80084F597 /* AppDelegate.swift */, 135 | 71B852921FC834F80084F597 /* ViewController.swift */, 136 | 71B852941FC834F80084F597 /* Assets.xcassets */, 137 | 71B852961FC834F80084F597 /* Main.storyboard */, 138 | 71B852991FC834F90084F597 /* Info.plist */, 139 | 71B8529A1FC834F90084F597 /* TrickerX.entitlements */, 140 | ); 141 | path = TrickerX; 142 | sourceTree = ""; 143 | }; 144 | 71B852A51FC835610084F597 /* Frameworks */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 71B852A61FC835610084F597 /* Cocoa.framework */, 148 | ); 149 | name = Frameworks; 150 | sourceTree = ""; 151 | }; 152 | 71B852CF1FC83A970084F597 /* Codable */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 71B852D01FC83A970084F597 /* SourceEditorExtension.swift */, 156 | 71B852D21FC83A970084F597 /* SourceEditorCommand.swift */, 157 | 719DB98C1FD817920080CD22 /* Command.swift */, 158 | 719DB98E1FD818730080CD22 /* StringExtension.swift */, 159 | 719DB9901FD8187D0080CD22 /* OptionalExtension.swift */, 160 | 71C885921FD8F34D0045737E /* Regex.swift */, 161 | 71B852D41FC83A970084F597 /* Info.plist */, 162 | 71B852D51FC83A970084F597 /* Codable.entitlements */, 163 | ); 164 | path = Codable; 165 | sourceTree = ""; 166 | }; 167 | 71C885821FD8F2800045737E /* TrickerXTests */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | 71C885831FD8F2800045737E /* TrickerXTests.swift */, 171 | 71C8858E1FD8F2F70045737E /* CodableRegexTests.swift */, 172 | 71C885851FD8F2800045737E /* Info.plist */, 173 | ); 174 | path = TrickerXTests; 175 | sourceTree = ""; 176 | }; 177 | /* End PBXGroup section */ 178 | 179 | /* Begin PBXNativeTarget section */ 180 | 71B8528C1FC834F80084F597 /* TrickerX */ = { 181 | isa = PBXNativeTarget; 182 | buildConfigurationList = 71B8529D1FC834F90084F597 /* Build configuration list for PBXNativeTarget "TrickerX" */; 183 | buildPhases = ( 184 | 71B852891FC834F80084F597 /* Sources */, 185 | 71B8528A1FC834F80084F597 /* Frameworks */, 186 | 71B8528B1FC834F80084F597 /* Resources */, 187 | 71B852B51FC835610084F597 /* Embed App Extensions */, 188 | ); 189 | buildRules = ( 190 | ); 191 | dependencies = ( 192 | 71B852D71FC83A970084F597 /* PBXTargetDependency */, 193 | ); 194 | name = TrickerX; 195 | productName = TrickerX; 196 | productReference = 71B8528D1FC834F80084F597 /* TrickerX.app */; 197 | productType = "com.apple.product-type.application"; 198 | }; 199 | 71B852CC1FC83A970084F597 /* Codable */ = { 200 | isa = PBXNativeTarget; 201 | buildConfigurationList = 71B852D91FC83A970084F597 /* Build configuration list for PBXNativeTarget "Codable" */; 202 | buildPhases = ( 203 | 71B852C91FC83A970084F597 /* Sources */, 204 | 71B852CA1FC83A970084F597 /* Frameworks */, 205 | 71B852CB1FC83A970084F597 /* Resources */, 206 | ); 207 | buildRules = ( 208 | ); 209 | dependencies = ( 210 | ); 211 | name = Codable; 212 | productName = Codable; 213 | productReference = 71B852CD1FC83A970084F597 /* Codable.appex */; 214 | productType = "com.apple.product-type.xcode-extension"; 215 | }; 216 | 71C885801FD8F2800045737E /* TrickerXTests */ = { 217 | isa = PBXNativeTarget; 218 | buildConfigurationList = 71C885881FD8F2800045737E /* Build configuration list for PBXNativeTarget "TrickerXTests" */; 219 | buildPhases = ( 220 | 71C8857D1FD8F2800045737E /* Sources */, 221 | 71C8857E1FD8F2800045737E /* Frameworks */, 222 | 71C8857F1FD8F2800045737E /* Resources */, 223 | ); 224 | buildRules = ( 225 | ); 226 | dependencies = ( 227 | 71C885871FD8F2800045737E /* PBXTargetDependency */, 228 | ); 229 | name = TrickerXTests; 230 | productName = TrickerXTests; 231 | productReference = 71C885811FD8F2800045737E /* TrickerXTests.xctest */; 232 | productType = "com.apple.product-type.bundle.unit-test"; 233 | }; 234 | /* End PBXNativeTarget section */ 235 | 236 | /* Begin PBXProject section */ 237 | 71B852851FC834F80084F597 /* Project object */ = { 238 | isa = PBXProject; 239 | attributes = { 240 | LastSwiftUpdateCheck = 0910; 241 | LastUpgradeCheck = 0930; 242 | ORGANIZATIONNAME = "Lei Wang"; 243 | TargetAttributes = { 244 | 71B8528C1FC834F80084F597 = { 245 | CreatedOnToolsVersion = 9.1; 246 | ProvisioningStyle = Automatic; 247 | }; 248 | 71B852CC1FC83A970084F597 = { 249 | CreatedOnToolsVersion = 9.1; 250 | ProvisioningStyle = Automatic; 251 | }; 252 | 71C885801FD8F2800045737E = { 253 | CreatedOnToolsVersion = 9.1; 254 | ProvisioningStyle = Automatic; 255 | TestTargetID = 71B8528C1FC834F80084F597; 256 | }; 257 | }; 258 | }; 259 | buildConfigurationList = 71B852881FC834F80084F597 /* Build configuration list for PBXProject "TrickerX" */; 260 | compatibilityVersion = "Xcode 8.0"; 261 | developmentRegion = en; 262 | hasScannedForEncodings = 0; 263 | knownRegions = ( 264 | en, 265 | Base, 266 | ); 267 | mainGroup = 71B852841FC834F80084F597; 268 | productRefGroup = 71B8528E1FC834F80084F597 /* Products */; 269 | projectDirPath = ""; 270 | projectRoot = ""; 271 | targets = ( 272 | 71B8528C1FC834F80084F597 /* TrickerX */, 273 | 71B852CC1FC83A970084F597 /* Codable */, 274 | 71C885801FD8F2800045737E /* TrickerXTests */, 275 | ); 276 | }; 277 | /* End PBXProject section */ 278 | 279 | /* Begin PBXResourcesBuildPhase section */ 280 | 71B8528B1FC834F80084F597 /* Resources */ = { 281 | isa = PBXResourcesBuildPhase; 282 | buildActionMask = 2147483647; 283 | files = ( 284 | 71B852951FC834F80084F597 /* Assets.xcassets in Resources */, 285 | 71B852981FC834F80084F597 /* Main.storyboard in Resources */, 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | }; 289 | 71B852CB1FC83A970084F597 /* Resources */ = { 290 | isa = PBXResourcesBuildPhase; 291 | buildActionMask = 2147483647; 292 | files = ( 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | 71C8857F1FD8F2800045737E /* Resources */ = { 297 | isa = PBXResourcesBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | ); 301 | runOnlyForDeploymentPostprocessing = 0; 302 | }; 303 | /* End PBXResourcesBuildPhase section */ 304 | 305 | /* Begin PBXSourcesBuildPhase section */ 306 | 71B852891FC834F80084F597 /* Sources */ = { 307 | isa = PBXSourcesBuildPhase; 308 | buildActionMask = 2147483647; 309 | files = ( 310 | 71B852931FC834F80084F597 /* ViewController.swift in Sources */, 311 | 71B852911FC834F80084F597 /* AppDelegate.swift in Sources */, 312 | ); 313 | runOnlyForDeploymentPostprocessing = 0; 314 | }; 315 | 71B852C91FC83A970084F597 /* Sources */ = { 316 | isa = PBXSourcesBuildPhase; 317 | buildActionMask = 2147483647; 318 | files = ( 319 | 719DB9911FD8187D0080CD22 /* OptionalExtension.swift in Sources */, 320 | 719DB98F1FD818730080CD22 /* StringExtension.swift in Sources */, 321 | 71B852D11FC83A970084F597 /* SourceEditorExtension.swift in Sources */, 322 | 71C885931FD8F34D0045737E /* Regex.swift in Sources */, 323 | 71B852D31FC83A970084F597 /* SourceEditorCommand.swift in Sources */, 324 | 719DB98D1FD817920080CD22 /* Command.swift in Sources */, 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | }; 328 | 71C8857D1FD8F2800045737E /* Sources */ = { 329 | isa = PBXSourcesBuildPhase; 330 | buildActionMask = 2147483647; 331 | files = ( 332 | 71C885951FD912C40045737E /* OptionalExtension.swift in Sources */, 333 | 71C885901FD8F2F70045737E /* CodableRegexTests.swift in Sources */, 334 | 71C885941FD8F34D0045737E /* Regex.swift in Sources */, 335 | 71C885841FD8F2800045737E /* TrickerXTests.swift in Sources */, 336 | 71C885911FD8F33B0045737E /* StringExtension.swift in Sources */, 337 | ); 338 | runOnlyForDeploymentPostprocessing = 0; 339 | }; 340 | /* End PBXSourcesBuildPhase section */ 341 | 342 | /* Begin PBXTargetDependency section */ 343 | 71B852D71FC83A970084F597 /* PBXTargetDependency */ = { 344 | isa = PBXTargetDependency; 345 | target = 71B852CC1FC83A970084F597 /* Codable */; 346 | targetProxy = 71B852D61FC83A970084F597 /* PBXContainerItemProxy */; 347 | }; 348 | 71C885871FD8F2800045737E /* PBXTargetDependency */ = { 349 | isa = PBXTargetDependency; 350 | target = 71B8528C1FC834F80084F597 /* TrickerX */; 351 | targetProxy = 71C885861FD8F2800045737E /* PBXContainerItemProxy */; 352 | }; 353 | /* End PBXTargetDependency section */ 354 | 355 | /* Begin PBXVariantGroup section */ 356 | 71B852961FC834F80084F597 /* Main.storyboard */ = { 357 | isa = PBXVariantGroup; 358 | children = ( 359 | 71B852971FC834F80084F597 /* Base */, 360 | ); 361 | name = Main.storyboard; 362 | sourceTree = ""; 363 | }; 364 | /* End PBXVariantGroup section */ 365 | 366 | /* Begin XCBuildConfiguration section */ 367 | 71B8529B1FC834F90084F597 /* Debug */ = { 368 | isa = XCBuildConfiguration; 369 | buildSettings = { 370 | ALWAYS_SEARCH_USER_PATHS = NO; 371 | CLANG_ANALYZER_NONNULL = YES; 372 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 373 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 374 | CLANG_CXX_LIBRARY = "libc++"; 375 | CLANG_ENABLE_MODULES = YES; 376 | CLANG_ENABLE_OBJC_ARC = YES; 377 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 378 | CLANG_WARN_BOOL_CONVERSION = YES; 379 | CLANG_WARN_COMMA = YES; 380 | CLANG_WARN_CONSTANT_CONVERSION = YES; 381 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 382 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 383 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 384 | CLANG_WARN_EMPTY_BODY = YES; 385 | CLANG_WARN_ENUM_CONVERSION = YES; 386 | CLANG_WARN_INFINITE_RECURSION = YES; 387 | CLANG_WARN_INT_CONVERSION = YES; 388 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 389 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 390 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 391 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 392 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 393 | CLANG_WARN_STRICT_PROTOTYPES = YES; 394 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 395 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 396 | CLANG_WARN_UNREACHABLE_CODE = YES; 397 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 398 | CODE_SIGN_IDENTITY = "Mac Developer"; 399 | COPY_PHASE_STRIP = NO; 400 | DEBUG_INFORMATION_FORMAT = dwarf; 401 | ENABLE_STRICT_OBJC_MSGSEND = YES; 402 | ENABLE_TESTABILITY = YES; 403 | GCC_C_LANGUAGE_STANDARD = gnu11; 404 | GCC_DYNAMIC_NO_PIC = NO; 405 | GCC_NO_COMMON_BLOCKS = YES; 406 | GCC_OPTIMIZATION_LEVEL = 0; 407 | GCC_PREPROCESSOR_DEFINITIONS = ( 408 | "DEBUG=1", 409 | "$(inherited)", 410 | ); 411 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 412 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 413 | GCC_WARN_UNDECLARED_SELECTOR = YES; 414 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 415 | GCC_WARN_UNUSED_FUNCTION = YES; 416 | GCC_WARN_UNUSED_VARIABLE = YES; 417 | MACOSX_DEPLOYMENT_TARGET = 10.12; 418 | MTL_ENABLE_DEBUG_INFO = YES; 419 | ONLY_ACTIVE_ARCH = YES; 420 | SDKROOT = macosx; 421 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 422 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 423 | }; 424 | name = Debug; 425 | }; 426 | 71B8529C1FC834F90084F597 /* Release */ = { 427 | isa = XCBuildConfiguration; 428 | buildSettings = { 429 | ALWAYS_SEARCH_USER_PATHS = NO; 430 | CLANG_ANALYZER_NONNULL = YES; 431 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 432 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 433 | CLANG_CXX_LIBRARY = "libc++"; 434 | CLANG_ENABLE_MODULES = YES; 435 | CLANG_ENABLE_OBJC_ARC = YES; 436 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 437 | CLANG_WARN_BOOL_CONVERSION = YES; 438 | CLANG_WARN_COMMA = YES; 439 | CLANG_WARN_CONSTANT_CONVERSION = YES; 440 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 441 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 442 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 443 | CLANG_WARN_EMPTY_BODY = YES; 444 | CLANG_WARN_ENUM_CONVERSION = YES; 445 | CLANG_WARN_INFINITE_RECURSION = YES; 446 | CLANG_WARN_INT_CONVERSION = YES; 447 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 448 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 449 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 450 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 451 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 452 | CLANG_WARN_STRICT_PROTOTYPES = YES; 453 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 454 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 455 | CLANG_WARN_UNREACHABLE_CODE = YES; 456 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 457 | CODE_SIGN_IDENTITY = "Mac Developer"; 458 | COPY_PHASE_STRIP = NO; 459 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 460 | ENABLE_NS_ASSERTIONS = NO; 461 | ENABLE_STRICT_OBJC_MSGSEND = YES; 462 | GCC_C_LANGUAGE_STANDARD = gnu11; 463 | GCC_NO_COMMON_BLOCKS = YES; 464 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 465 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 466 | GCC_WARN_UNDECLARED_SELECTOR = YES; 467 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 468 | GCC_WARN_UNUSED_FUNCTION = YES; 469 | GCC_WARN_UNUSED_VARIABLE = YES; 470 | MACOSX_DEPLOYMENT_TARGET = 10.12; 471 | MTL_ENABLE_DEBUG_INFO = NO; 472 | SDKROOT = macosx; 473 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 474 | }; 475 | name = Release; 476 | }; 477 | 71B8529E1FC834F90084F597 /* Debug */ = { 478 | isa = XCBuildConfiguration; 479 | buildSettings = { 480 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 481 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 482 | CODE_SIGN_ENTITLEMENTS = TrickerX/TrickerX.entitlements; 483 | CODE_SIGN_STYLE = Automatic; 484 | COMBINE_HIDPI_IMAGES = YES; 485 | DEVELOPMENT_TEAM = ZRW9N2A955; 486 | INFOPLIST_FILE = TrickerX/Info.plist; 487 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 488 | MACOSX_DEPLOYMENT_TARGET = 10.12; 489 | PRODUCT_BUNDLE_IDENTIFIER = com.rayternet.TrickerX; 490 | PRODUCT_NAME = "$(TARGET_NAME)"; 491 | SWIFT_VERSION = 4.0; 492 | }; 493 | name = Debug; 494 | }; 495 | 71B8529F1FC834F90084F597 /* Release */ = { 496 | isa = XCBuildConfiguration; 497 | buildSettings = { 498 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 499 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 500 | CODE_SIGN_ENTITLEMENTS = TrickerX/TrickerX.entitlements; 501 | CODE_SIGN_STYLE = Automatic; 502 | COMBINE_HIDPI_IMAGES = YES; 503 | DEVELOPMENT_TEAM = ZRW9N2A955; 504 | INFOPLIST_FILE = TrickerX/Info.plist; 505 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 506 | MACOSX_DEPLOYMENT_TARGET = 10.12; 507 | PRODUCT_BUNDLE_IDENTIFIER = com.rayternet.TrickerX; 508 | PRODUCT_NAME = "$(TARGET_NAME)"; 509 | SWIFT_VERSION = 4.0; 510 | }; 511 | name = Release; 512 | }; 513 | 71B852DA1FC83A970084F597 /* Debug */ = { 514 | isa = XCBuildConfiguration; 515 | buildSettings = { 516 | CODE_SIGN_ENTITLEMENTS = Codable/Codable.entitlements; 517 | CODE_SIGN_STYLE = Automatic; 518 | COMBINE_HIDPI_IMAGES = YES; 519 | DEVELOPMENT_TEAM = ZRW9N2A955; 520 | INFOPLIST_FILE = Codable/Info.plist; 521 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks"; 522 | PRODUCT_BUNDLE_IDENTIFIER = com.rayternet.TrickerX.Codable; 523 | PRODUCT_NAME = "$(TARGET_NAME)"; 524 | SKIP_INSTALL = YES; 525 | SWIFT_VERSION = 4.0; 526 | }; 527 | name = Debug; 528 | }; 529 | 71B852DB1FC83A970084F597 /* Release */ = { 530 | isa = XCBuildConfiguration; 531 | buildSettings = { 532 | CODE_SIGN_ENTITLEMENTS = Codable/Codable.entitlements; 533 | CODE_SIGN_STYLE = Automatic; 534 | COMBINE_HIDPI_IMAGES = YES; 535 | DEVELOPMENT_TEAM = ZRW9N2A955; 536 | INFOPLIST_FILE = Codable/Info.plist; 537 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks"; 538 | PRODUCT_BUNDLE_IDENTIFIER = com.rayternet.TrickerX.Codable; 539 | PRODUCT_NAME = "$(TARGET_NAME)"; 540 | SKIP_INSTALL = YES; 541 | SWIFT_VERSION = 4.0; 542 | }; 543 | name = Release; 544 | }; 545 | 71C885891FD8F2800045737E /* Debug */ = { 546 | isa = XCBuildConfiguration; 547 | buildSettings = { 548 | BUNDLE_LOADER = "$(TEST_HOST)"; 549 | CODE_SIGN_STYLE = Automatic; 550 | COMBINE_HIDPI_IMAGES = YES; 551 | DEVELOPMENT_TEAM = ZRW9N2A955; 552 | INFOPLIST_FILE = TrickerXTests/Info.plist; 553 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 554 | PRODUCT_BUNDLE_IDENTIFIER = com.rayternet.TrickerXTests; 555 | PRODUCT_NAME = "$(TARGET_NAME)"; 556 | SWIFT_VERSION = 4.0; 557 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TrickerX.app/Contents/MacOS/TrickerX"; 558 | }; 559 | name = Debug; 560 | }; 561 | 71C8858A1FD8F2800045737E /* Release */ = { 562 | isa = XCBuildConfiguration; 563 | buildSettings = { 564 | BUNDLE_LOADER = "$(TEST_HOST)"; 565 | CODE_SIGN_STYLE = Automatic; 566 | COMBINE_HIDPI_IMAGES = YES; 567 | DEVELOPMENT_TEAM = ZRW9N2A955; 568 | INFOPLIST_FILE = TrickerXTests/Info.plist; 569 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 570 | PRODUCT_BUNDLE_IDENTIFIER = com.rayternet.TrickerXTests; 571 | PRODUCT_NAME = "$(TARGET_NAME)"; 572 | SWIFT_VERSION = 4.0; 573 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TrickerX.app/Contents/MacOS/TrickerX"; 574 | }; 575 | name = Release; 576 | }; 577 | /* End XCBuildConfiguration section */ 578 | 579 | /* Begin XCConfigurationList section */ 580 | 71B852881FC834F80084F597 /* Build configuration list for PBXProject "TrickerX" */ = { 581 | isa = XCConfigurationList; 582 | buildConfigurations = ( 583 | 71B8529B1FC834F90084F597 /* Debug */, 584 | 71B8529C1FC834F90084F597 /* Release */, 585 | ); 586 | defaultConfigurationIsVisible = 0; 587 | defaultConfigurationName = Release; 588 | }; 589 | 71B8529D1FC834F90084F597 /* Build configuration list for PBXNativeTarget "TrickerX" */ = { 590 | isa = XCConfigurationList; 591 | buildConfigurations = ( 592 | 71B8529E1FC834F90084F597 /* Debug */, 593 | 71B8529F1FC834F90084F597 /* Release */, 594 | ); 595 | defaultConfigurationIsVisible = 0; 596 | defaultConfigurationName = Release; 597 | }; 598 | 71B852D91FC83A970084F597 /* Build configuration list for PBXNativeTarget "Codable" */ = { 599 | isa = XCConfigurationList; 600 | buildConfigurations = ( 601 | 71B852DA1FC83A970084F597 /* Debug */, 602 | 71B852DB1FC83A970084F597 /* Release */, 603 | ); 604 | defaultConfigurationIsVisible = 0; 605 | defaultConfigurationName = Release; 606 | }; 607 | 71C885881FD8F2800045737E /* Build configuration list for PBXNativeTarget "TrickerXTests" */ = { 608 | isa = XCConfigurationList; 609 | buildConfigurations = ( 610 | 71C885891FD8F2800045737E /* Debug */, 611 | 71C8858A1FD8F2800045737E /* Release */, 612 | ); 613 | defaultConfigurationIsVisible = 0; 614 | defaultConfigurationName = Release; 615 | }; 616 | /* End XCConfigurationList section */ 617 | }; 618 | rootObject = 71B852851FC834F80084F597 /* Project object */; 619 | } 620 | -------------------------------------------------------------------------------- /TrickerX.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TrickerX.xcodeproj/xcshareddata/xcschemes/TrickerX.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /TrickerX.xcodeproj/xcuserdata/ray.xcuserdatad/xcschemes/Codable.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 6 | 9 | 10 | 16 | 22 | 23 | 24 | 30 | 36 | 37 | 38 | 39 | 40 | 46 | 47 | 48 | 49 | 55 | 56 | 57 | 58 | 59 | 60 | 72 | 75 | 76 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 95 | 97 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /TrickerX/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // TrickerX 4 | // 5 | // Created by Lei Wang on 2017/11/24. 6 | // Copyright © 2017年 Lei Wang. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | 15 | 16 | func applicationDidFinishLaunching(_ aNotification: Notification) { 17 | // Insert code here to initialize your application 18 | 19 | NSApp.setActivationPolicy(NSApplication.ActivationPolicy.prohibited) 20 | } 21 | 22 | func applicationWillTerminate(_ aNotification: Notification) { 23 | // Insert code here to tear down your application 24 | } 25 | 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /TrickerX/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /TrickerX/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | Default 531 | 532 | 533 | 534 | 535 | 536 | 537 | Left to Right 538 | 539 | 540 | 541 | 542 | 543 | 544 | Right to Left 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | Default 556 | 557 | 558 | 559 | 560 | 561 | 562 | Left to Right 563 | 564 | 565 | 566 | 567 | 568 | 569 | Right to Left 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | -------------------------------------------------------------------------------- /TrickerX/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSApplicationCategoryType 24 | public.app-category.developer-tools 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2017年 Lei Wang. All rights reserved. 29 | NSMainStoryboardFile 30 | Main 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /TrickerX/TrickerX.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /TrickerX/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TrickerX 4 | // 5 | // Created by Lei Wang on 2017/11/24. 6 | // Copyright © 2017年 Lei Wang. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class ViewController: NSViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | // Do any additional setup after loading the view. 17 | } 18 | 19 | override var representedObject: Any? { 20 | didSet { 21 | // Update the view, if already loaded. 22 | } 23 | } 24 | 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /TrickerXTests/CodableRegexTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodableRegexTests.swift 3 | // TrickerX 4 | // 5 | // Created by Lei Wang on 2017/12/7. 6 | // Copyright © 2017年 Lei Wang. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class CodableRegexTests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | super.tearDown() 21 | } 22 | 23 | func testExample() { 24 | // This is an example of a functional test case. 25 | // Use XCTAssert and related functions to verify your tests produce the correct results. 26 | var toggleComments = "// toggle commentes test" 27 | XCTAssertNotNil(toggleComments.match(regex: .toggleComments)) 28 | toggleComments = " // toggle commentes test " 29 | XCTAssertNotNil(toggleComments.match(regex: .toggleComments)) 30 | toggleComments = "test // toggle commentes test " 31 | XCTAssertNil(toggleComments.match(regex: .toggleComments)) 32 | 33 | 34 | var customKeys = "private let customKey: String //my_custom_key" 35 | XCTAssertNotNil(customKeys.match(regex: .customKey)) 36 | XCTAssertEqual(customKeys.match(regex: .customKey)?.match(regex: "\\w+").unwrappedOrEmpty, "my_custom_key") 37 | 38 | XCTAssertNotNil(customKeys.match(regex: .codablePropertyLine)) 39 | XCTAssertEqual(customKeys.match(regex: .codablePropertyLine)?.match(regex: .codablePropertyName), "customKey") 40 | let splitStrings = customKeys.split(separator: "/") 41 | XCTAssertEqual(splitStrings.first, "private let customKey: String ") 42 | 43 | customKeys = "private let customKey: String //" 44 | XCTAssertNil(customKeys.match(regex: .customKey)) 45 | 46 | 47 | } 48 | 49 | func testPerformanceExample() { 50 | // This is an example of a performance test case. 51 | self.measure { 52 | // Put the code you want to measure the time of here. 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /TrickerXTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /TrickerXTests/TrickerXTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TrickerXTests.swift 3 | // TrickerXTests 4 | // 5 | // Created by Lei Wang on 2017/12/7. 6 | // Copyright © 2017年 Lei Wang. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class TrickerXTests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | super.tearDown() 21 | } 22 | 23 | func testExample() { 24 | // This is an example of a functional test case. 25 | // Use XCTAssert and related functions to verify your tests produce the correct results. 26 | } 27 | 28 | func testPerformanceExample() { 29 | // This is an example of a performance test case. 30 | self.measure { 31 | // Put the code you want to measure the time of here. 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/TrickerX.dmg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wleii/TrickerX/7ecee50d8e393a0ccea758fc1688a4db2c1a3c28/app/TrickerX.dmg -------------------------------------------------------------------------------- /codable.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wleii/TrickerX/7ecee50d8e393a0ccea758fc1688a4db2c1a3c28/codable.gif -------------------------------------------------------------------------------- /fastlane/Appfile: -------------------------------------------------------------------------------- 1 | app_identifier "com.rayternet.TrickerX" # The bundle identifier of your app 2 | apple_id "w_leii@sina.cn" # Your Apple email address 3 | 4 | team_id "[[DEV_PORTAL_TEAM_ID]]" # Developer Portal Team ID 5 | 6 | # you can even provide different app identifiers, Apple IDs and team names per lane: 7 | # More information: https://docs.fastlane.tools/advanced/#appfile 8 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | # Customize this file, documentation can be found here: 2 | # https://docs.fastlane.tools/actions/ 3 | # All available actions: https://docs.fastlane.tools/actions 4 | # can also be listed using the `fastlane actions` command 5 | 6 | # Change the syntax highlighting to Ruby 7 | # All lines starting with a # are ignored when running `fastlane` 8 | 9 | # If you want to automatically update fastlane if a new version is available: 10 | # update_fastlane 11 | 12 | # This is the minimum version number required. 13 | # Update this, if you use features of a newer version 14 | fastlane_version "2.68.0" 15 | 16 | default_platform :ios 17 | 18 | platform :ios do 19 | before_all do 20 | # ENV["SLACK_URL"] = "https://hooks.slack.com/services/..." 21 | # cocoapods 22 | # carthage 23 | end 24 | 25 | desc "Runs all the tests" 26 | lane :test do 27 | run_tests 28 | end 29 | 30 | desc "release new dmg" 31 | lane :dmg do 32 | build_app( 33 | scheme: "TrickerX", 34 | clean: true, 35 | output_directory: "./app", 36 | output_name: "TrickerX", 37 | export_method: "developer-id", 38 | archive_path: "./app/TrickerX" 39 | ) 40 | 41 | sh("./make_dmg") 42 | end 43 | 44 | # You can define as many lanes as you want 45 | 46 | after_all do |lane| 47 | # This block is called, only if the executed lane was successful 48 | 49 | # slack( 50 | # message: "Successfully deployed new App Update." 51 | # ) 52 | end 53 | 54 | error do |lane, exception| 55 | # slack( 56 | # message: exception.message, 57 | # success: false 58 | # ) 59 | end 60 | end 61 | 62 | 63 | # More information about multiple platforms in fastlane: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform 64 | # All available actions: https://docs.fastlane.tools/actions 65 | 66 | # fastlane reports which actions are used. No personal data is recorded. 67 | # Learn more at https://docs.fastlane.tools/#metrics 68 | -------------------------------------------------------------------------------- /fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ================ 3 | # Installation 4 | 5 | Make sure you have the latest version of the Xcode command line tools installed: 6 | 7 | ``` 8 | xcode-select --install 9 | ``` 10 | 11 | Install _fastlane_ using 12 | ``` 13 | [sudo] gem install fastlane -NV 14 | ``` 15 | or alternatively using `brew cask install fastlane` 16 | 17 | # Available Actions 18 | ## iOS 19 | ### ios test 20 | ``` 21 | fastlane ios test 22 | ``` 23 | Runs all the tests 24 | ### ios dmg 25 | ``` 26 | fastlane ios dmg 27 | ``` 28 | release new dmg 29 | 30 | ---- 31 | 32 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. 33 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). 34 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). 35 | -------------------------------------------------------------------------------- /fastlane/make_dmg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd .. 4 | 5 | projectPath=$(pwd) 6 | appFilePath=${projectPath}/app/TrickerX.app 7 | 8 | if [ -d "$appFilePath" ] 9 | then 10 | echo "success find $appFilePath" 11 | else 12 | echo "$appFilePath not found." 13 | exit 1 14 | fi 15 | 16 | # clean 17 | rm -rf $projectPath/app/TrickerX.dmg 18 | rm -rf $projectPath/app/Applications 19 | rm -rf $projectPath/app/*.xcarchive 20 | rm -rf $projectPath/app/*.zip 21 | 22 | cd $projectPath/app 23 | ln -s /Applications Applications 24 | cd .. 25 | echo "Link Applications success" 26 | 27 | hdiutil create $projectPath/app/TrickerX.dmg -volname "TrickerX" -srcfolder $projectPath/app 28 | 29 | # clean 30 | rm -rf $projectPath/app/TrickerX.app 31 | rm -rf $projectPath/app/Applications 32 | --------------------------------------------------------------------------------