├── README.md ├── Sources ├── YApiRAW.gif ├── YApiRAWData.js ├── YApiRAWData.png ├── config.png ├── example.gif ├── example_hight.gif ├── jsTest.js ├── keybinding.png ├── mutilToken.png ├── result.png ├── showfinder.png ├── yapiHostId.png └── yapiToken.png ├── SwiftJSONModeler For Xcode.app.zip ├── SwiftJSONModeler For Xcode.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved ├── xcshareddata │ └── xcschemes │ │ ├── SwiftJSONModeler For Xcode.xcscheme │ │ └── SwiftJSONModeler.xcscheme └── xcuserdata │ └── yibin.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── SwiftJSONModeler For Xcode ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon_128x128.png │ │ ├── Icon_128x128@2x.png │ │ ├── Icon_16x16.png │ │ ├── Icon_16x16@2x.png │ │ ├── Icon_256x256.png │ │ ├── Icon_256x256@2x.png │ │ ├── Icon_32x32.png │ │ ├── Icon_32x32@2x.png │ │ ├── Icon_512x512.png │ │ └── Icon_512x512@2x.png │ └── Contents.json ├── Base.lproj │ └── Main.storyboard ├── Config │ ├── ConfigCenter.swift │ └── Model │ │ └── ConfigModel.swift ├── Constants │ └── Constants.swift ├── Controller │ ├── ConfigViewController.swift │ └── TokenViewController.swift ├── Document.swift ├── ErrorCenter.swift ├── Info.plist ├── NormalJSON │ ├── JSONHelper.swift │ └── OrderJSON+NormalJSON.swift ├── SwiftJSONModeler For Xcode.entitlements ├── Utils │ └── OpenSavePanel.swift ├── View │ ├── TokenView.swift │ └── TokenView.xib ├── ViewController.swift └── YApi │ ├── OrderJSON+YApi │ └── OrderJSON+Yapi.swift │ ├── YApiCreator.swift │ ├── YApiHelper.swift │ ├── YApiObject.swift │ └── YApiRequest.swift ├── SwiftJSONModeler For XcodeTests ├── Info.plist ├── SwiftJSONModelerTest │ ├── JSONHelperTest.swift │ ├── OrderJSON+YApiTest.swift │ └── YApiObjectTest.swift └── SwiftJSONModeler_For_XcodeTests.swift ├── SwiftJSONModeler ├── Info.plist ├── SourceEditorCommand.swift ├── SourceEditorExtension.swift └── SwiftJSONModeler.entitlements └── SwiftJSONModelerDemo ├── SwiftJSONModelerDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── yibin.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist └── SwiftJSONModelerDemo ├── AppDelegate.swift ├── Assets.xcassets ├── AppIcon.appiconset │ └── Contents.json └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── Config.plist ├── Info.plist ├── SceneDelegate.swift ├── TestJSONModel.swift ├── TestYapiRAWModel.swift └── ViewController.swift /README.md: -------------------------------------------------------------------------------- 1 | SwiftJSONModeler是一个Xcode插件,一键转换json字符串为Swfit模型,一键转化 YApi 平台接口为模型,并且自动引入注释。 2 | * 支持struct, class 3 | * 支持单json转模, 多层嵌套 json 4 | * 模型字段顺序与 json 一致 5 | * 支持YApi RAW或接口id解析转模,并且自动引入 YApi 平台注释和兼容数据类型 6 | * 支持自定义遵循 和 import 7 | * 支持自定义模型前缀和后缀 8 | * 可设置隐式和显示可选类型,默认显示可选`?`(不使用则为隐式可选`!`) 9 | * YApi 支持按照自定义路径解析模型,自动解析子类型 10 | * 导入导出配置plist配置,以便团队共享。 11 | 12 | 13 | ## json 转Swfit模型 14 | 15 | 复制json字符串, 一步转为Swift模型,支持多层嵌套自动识别。 16 | 17 | ![运行效果](./Sources/example.gif) 18 | 19 | 如果无法预览查看[传输门](https://github.com/yumengqing/SwiftJSONModeler/blob/master/Sources/example.gif)或者[Sources/example.gif](./Sources/example_hight.gif) 20 | 21 | 示例 json 数据: 22 | ```javaScript 23 | { 24 | "stringValue": "字符串", 25 | "intValue": 20, 26 | "doubleValue": 12.8, 27 | "boolValue": false, 28 | "objectValue": { 29 | "objectKey1": "value1", 30 | "objectKey2": 2, 31 | "objectKey3": { 32 | "key": "value" 33 | } 34 | }, 35 | "arrayValue1": [1, 2, 3], 36 | "arrayValue2": [{ 37 | "name": "小明", 38 | "age": 18 39 | }], 40 | "emptyArray": [], 41 | "emptyObject": {}, 42 | "nullValue": null 43 | } 44 | ``` 45 | Swift模型 46 | ```swift 47 | struct Model: HandyJSON { 48 | 49 | var stringValue: String = "" 50 | 51 | var intValue: Int? 52 | 53 | var doubleValue: Double? 54 | 55 | var boolValue: Int? 56 | /// 57 | var objectValue: ObjectValueModel? 58 | 59 | var arrayValue1: [Int] = [] 60 | 61 | var arrayValue2: [ArrayValue2Model] = [] 62 | 63 | var emptyArray: [<#Undefined#>] = [] // 空数组 需要手动指定类型 64 | /// 65 | var emptyObject: EmptyObjectModel? 66 | 67 | var nullValue: <#NSNull#>? // null值,需要手动指定类型 68 | } 69 | 70 | struct ObjectValueModel: HandyJSON { 71 | 72 | var objectKey1: String = "" 73 | 74 | var objectKey2: Int? 75 | /// 76 | var objectKey3: ObjectKey3Model? 77 | } 78 | 79 | struct ArrayValue2Model: HandyJSON { 80 | 81 | var name: String = "" 82 | 83 | var age: Int? 84 | } 85 | 86 | struct EmptyObjectModel: HandyJSON { 87 | } 88 | 89 | struct ObjectKey3Model: HandyJSON { 90 | 91 | var key: String = "" 92 | } 93 | 94 | ``` 95 | 支持多层嵌套 josn, 高亮提示 json 中 `null`类型, 类型自动判断。 96 | 97 | ## YApi 接口平台转模支持 98 | 99 | 什么是 YApi,YApi 是一个可本地部署的、打通前后端及QA的、可视化的接口管理平台,[github 地址](https://github.com/YMFE/yapi) 100 | 101 | 复制YApi接口RAW数据,一步解析带有注释的模型。 102 | 解析效果如下(): 103 | 104 | ![解析YApi](./Sources/YApiRAW.gif) 105 | 106 | 如果无法预览查看[Source/YApiRAW.gif](./Sources/YApiRAW.gif) 107 | 108 | 如果你使用YApi接口平台,我们支持两种方式,通过接口 Id和 Raw 数据转模。一键转为模型,并且自动根据YApi为模型引入注释。 109 | 110 | ### 通过Id转模 111 | 112 | 在配置了项目token和host基础下,简单复制Id即可实现转模和添加注释. 113 | 114 | **如何查看YApi接口中的id?**在YApi对应的接口中,查看浏览器网址,最后的数字就是Id。如下图: 115 | 116 | ![接口Id](./Sources/yapiHostId.png) 117 | 118 | 具体配置参考下面设置部分。 119 | 120 | ### RAW数据 121 | 122 | **RAW数据**:即YApi接口平台提供的带有接口字段及注释的json数据,查看方式:选择接口 -> 编辑 -> 返回数据设置 -> RAW 如下图 123 | 124 | ![Alt](./Sources/YApiRAWData.png) 125 | 126 | 示例RAW数据: 127 | 128 | ```javascript 129 | {"type":"object","title":"empty object","properties":{"message":{"type":"string"},"code":{"type":"string"},"response":{"type":"object","properties":{"teachers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","mock":{"mock":"Mrs Yang"},"description":"名字"},"subject":{"type":"string","mock":{"mock":"语文"},"description":"科目"},"phone":{"type":"string","mock":{"mock":"13459923098"},"description":"联系电话"}},"required":["name","subject","phone"]},"description":"老师"},"name":{"type":"string","description":"姓名"},"age":{"type":"integer","mock":{"mock":"18"},"description":"年龄"},"score":{"type":"number","mock":{"mock":"89.8"},"description":"综合成绩"},"likes":{"type":"array","items":{"type":"string","mock":{"mock":"英雄联盟"}},"description":"爱好"},"emergercyContact":{"type":"object","properties":{"name":{"type":"string"},"phone":{"type":"string","description":"联系电话"},"address":{"type":"string","description":"联系地址","mock":{"mock":"xx街道xx栋xx单元"}}},"description":"紧急联系人","required":["name","phone","address"]},"isBoy":{"type":"boolean","description":"是否为男孩"}},"required":["teachers","name","age","score","likes","emergercyContact","isBoy"]}},"required":["message","code","response"]} 130 | ``` 131 | 132 | > 完整示例可下载打开SwiftJSONModelerDemo查看 133 | 134 | ### 解析指定路径模型 135 | 136 | 如果你数据有多层json, 可以在设置中指定解析路线path来获取指定模型。比如我的目标数据在response字段下,则可以配置path为`response`.则直接解析response下的json模型。多路径使用 `.` 137 | 138 | 139 | ## 安装 140 | 1.你可以选择[Release](https://github.com/yumengqing/SwiftJSONModeler/releases) 直接下载应用安装 141 | 142 | 2.你也可以选择下载源代码编译为应用 143 | 下载项目工程,修改为自己的bundleId 144 | 145 | 运行主项目SwiftJSONModeler For Xcode 146 | 147 | 再运行SwiftJSONModeler 148 | 149 | 确保没有报错的情况下,选择Products下的运行主项目SwiftJSONModeler For Xcode.app点击右键, 选择show in finder如下图 150 | 151 | ![](./Sources/showfinder.png) 152 | 153 | 再将应用移动到应用程序, 重启Xcode即可使用。 154 | 155 | ### 注意事项 156 | 157 | 1. 安装弹出安全提示,选择系统设置 -> 安全性与隐私 -> 通用 点击允许打开该软件即可。 158 | 2. 如果重启Xcode之后在Editor中还没看见插件选项,请选择系统设置-> 扩展->Xcode Source Editor中对应插件是否勾选 159 | 160 | ## 设置 161 | SwiftJSONModeler提供多种自定义可选设置,可通过插件的Config选项进行设置。 162 | 163 | 设置选项如下图: 164 | 165 | ![可选设置](./Sources/config.png) 166 | 167 | **YApi模型路径指定**:当对象含有多层json,或者有基本json包裹时,可以指定path解析模型。 168 | 169 | **YApi项目token**: 每个YApi项目都有唯一一个token,在YApi项目接口的设置中可以查看对应的token,如下图: 170 | 171 | ![token](./Sources/yapiToken.png) 172 | 173 | **YApi项目host**:host就是部署YApi的地址 174 | 175 | ![host](./Sources/yapiHostId.png) 176 | 177 | **多 token配置** 178 | 179 | 在开发中可能团队同时开发多个项目,就会存在多个token,可以通过配置,转模时切换 token 180 | 181 | ![](./Sources/mutilToken.png) 182 | 183 | > 多 token 接口无法转模问题 184 | > 185 | > 通过 id 转模,配置多个 token 项目,可能会存在某个项目无法通过 id 砖模型,原因 YApi 平台的 token 无法获取到相应的json数据. 186 | > 187 | > 解决办法: 使用其他项目 token 尝试 188 | 189 | 设置通过 plist 文件保存,可以导入导出。 190 | 191 | > Tips: plist 文件还有其他未展示的设置, 比如默认设置 String 类型为空字符串等 192 | 193 | ## 设置快捷键 194 | 195 | 可以给插件设置快捷键,快速转换模型 196 | 197 | 在Xcode -> Preference -> Key Bindings -> Editor Menu For Source Code【或者搜索】就可以找到,如下图 198 | 199 | ![](./Sources/keybinding.png) 200 | 201 | 记得双击key下面那个区域才可以编辑,这里我使用的是alt + s 和alt + c 避免与系统的冲突 202 | 203 | -------------------------------------------------------------------------------- /Sources/YApiRAW.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/Sources/YApiRAW.gif -------------------------------------------------------------------------------- /Sources/YApiRAWData.js: -------------------------------------------------------------------------------- 1 | {"type":"object","title":"empty object","properties":{"person":{"type":"object","properties":{"name":{"type":"string","description":"姓名","mock":{"mock":"小明"}},"age":{"type":"integer","description":"年龄","mock":{"mock":"12"}},"school":{"type":"object","properties":{"address":{"type":"string","mock":{"mock":"xx街道xx号"},"description":"学校地址"},"schoolName":{"type":"string","description":"学校名字"}},"required":["address","schoolName"],"description":"学校"},"likes":{"type":"array","items":{"type":"string"},"description":"好友"},"teachers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"老师名字"},"subject":{"type":"string","description":"科目","mock":{"mock":"语文"}},"isMale":{"type":"boolean","description":"是否为男"}},"required":["name","subject","isMale"]}}},"required":["name","age","school","likes","teachers"],"description":"个人信息详情"}},"required":["person"]} 2 | -------------------------------------------------------------------------------- /Sources/YApiRAWData.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/Sources/YApiRAWData.png -------------------------------------------------------------------------------- /Sources/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/Sources/config.png -------------------------------------------------------------------------------- /Sources/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/Sources/example.gif -------------------------------------------------------------------------------- /Sources/example_hight.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/Sources/example_hight.gif -------------------------------------------------------------------------------- /Sources/jsTest.js: -------------------------------------------------------------------------------- 1 | { 2 | "orderName": "擦护理洗车", 3 | "decription": "退还到原支付账户", 4 | "refund": 58, 5 | "total": 18.2, 6 | "name": null, 7 | "detail": { 8 | "id": 1387329, 9 | "date": "2018-08-08" 10 | }, 11 | "tag": [ 12 | "美容洗车", 13 | "活动", 14 | "护理" 15 | ] 16 | } -------------------------------------------------------------------------------- /Sources/keybinding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/Sources/keybinding.png -------------------------------------------------------------------------------- /Sources/mutilToken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/Sources/mutilToken.png -------------------------------------------------------------------------------- /Sources/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/Sources/result.png -------------------------------------------------------------------------------- /Sources/showfinder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/Sources/showfinder.png -------------------------------------------------------------------------------- /Sources/yapiHostId.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/Sources/yapiHostId.png -------------------------------------------------------------------------------- /Sources/yapiToken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/Sources/yapiToken.png -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode.app.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/SwiftJSONModeler For Xcode.app.zip -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C90EFE0C257E172E0008632B /* XcodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C90EFE0B257E172E0008632B /* XcodeKit.framework */; }; 11 | C90EFE0D257E172E0008632B /* XcodeKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C90EFE0B257E172E0008632B /* XcodeKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 12 | C92A970A24E512BD00C87CCD /* YApiObjectTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C92A970524E50D5900C87CCD /* YApiObjectTest.swift */; }; 13 | C92A971424E513EA00C87CCD /* YApiHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94AFC00241F4AE600389AF3 /* YApiHelper.swift */; }; 14 | C92A971524E513EA00C87CCD /* YApiObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94AFC03241F4E8A00389AF3 /* YApiObject.swift */; }; 15 | C92A971624E513EA00C87CCD /* YApiCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CEE26C242B382900A04EA9 /* YApiCreator.swift */; }; 16 | C92A971724E513EA00C87CCD /* YApiRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D04F20242EF99F00843DC4 /* YApiRequest.swift */; }; 17 | C92A971824E513F900C87CCD /* ErrorCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CB247F241F559C00F4D5CE /* ErrorCenter.swift */; }; 18 | C92A971D24E514FB00C87CCD /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C92A971C24E514FB00C87CCD /* Constants.swift */; }; 19 | C92A971E24E5150600C87CCD /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C92A971C24E514FB00C87CCD /* Constants.swift */; }; 20 | C935B49C24EA24BE00E48231 /* JSONHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C935B49B24EA24BE00E48231 /* JSONHelper.swift */; }; 21 | C935B49E24EA56EF00E48231 /* JSONHelperTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C935B49D24EA56EF00E48231 /* JSONHelperTest.swift */; }; 22 | C935B49F24EA664A00E48231 /* JSONHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C935B49B24EA24BE00E48231 /* JSONHelper.swift */; }; 23 | C94AFC01241F4AE600389AF3 /* YApiHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94AFC00241F4AE600389AF3 /* YApiHelper.swift */; }; 24 | C94AFC04241F4E8A00389AF3 /* YApiObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94AFC03241F4E8A00389AF3 /* YApiObject.swift */; }; 25 | C961C1DE23D82A8D008D0DE6 /* ConfigViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C961C1DD23D82A8D008D0DE6 /* ConfigViewController.swift */; }; 26 | C9AB1D312637B211008256ED /* OrderJSON+Yapi.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9AB1D302637B211008256ED /* OrderJSON+Yapi.swift */; }; 27 | C9AB1D322637B211008256ED /* OrderJSON+Yapi.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9AB1D302637B211008256ED /* OrderJSON+Yapi.swift */; }; 28 | C9AB1D362637C34B008256ED /* OrderJSON+YApiTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9AB1D352637C34B008256ED /* OrderJSON+YApiTest.swift */; }; 29 | C9AB1D6826395F82008256ED /* OrderJSON in Frameworks */ = {isa = PBXBuildFile; productRef = C9AB1D6726395F82008256ED /* OrderJSON */; }; 30 | C9AB1D6C26395F8E008256ED /* OrderJSON in Frameworks */ = {isa = PBXBuildFile; productRef = C9AB1D6B26395F8E008256ED /* OrderJSON */; }; 31 | C9CB2480241F559C00F4D5CE /* ErrorCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CB247F241F559C00F4D5CE /* ErrorCenter.swift */; }; 32 | C9CEE26D242B382900A04EA9 /* YApiCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CEE26C242B382900A04EA9 /* YApiCreator.swift */; }; 33 | C9D04F2B242F218200843DC4 /* SwiftJSONModeler_For_XcodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D04F2A242F218200843DC4 /* SwiftJSONModeler_For_XcodeTests.swift */; }; 34 | C9D9905825E776A900258865 /* ConfigCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D9905725E776A900258865 /* ConfigCenter.swift */; }; 35 | C9D9905C25E776EF00258865 /* ConfigModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E9C09125CFD94E00CD767D /* ConfigModel.swift */; }; 36 | C9D9906725E7807300258865 /* CleanJSON in Frameworks */ = {isa = PBXBuildFile; productRef = C9D9906625E7807300258865 /* CleanJSON */; }; 37 | C9D9906D25E7815F00258865 /* CleanJSON in Frameworks */ = {isa = PBXBuildFile; productRef = C9D9906C25E7815F00258865 /* CleanJSON */; }; 38 | C9D9906E25E7816600258865 /* ConfigCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D9905725E776A900258865 /* ConfigCenter.swift */; }; 39 | C9DD88322431C630004E420F /* YApiRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D04F20242EF99F00843DC4 /* YApiRequest.swift */; }; 40 | C9E393E424EE248500D80B28 /* TokenView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C9E393E324EE248500D80B28 /* TokenView.xib */; }; 41 | C9E393E824EE255900D80B28 /* TokenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E393E724EE255900D80B28 /* TokenView.swift */; }; 42 | C9E393EA24EE47D300D80B28 /* TokenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E393E924EE47D300D80B28 /* TokenViewController.swift */; }; 43 | C9E9C08925CF907A00CD767D /* OpenSavePanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E9C08825CF907A00CD767D /* OpenSavePanel.swift */; }; 44 | C9E9C09225CFD94E00CD767D /* ConfigModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E9C09125CFD94E00CD767D /* ConfigModel.swift */; }; 45 | C9ED9CC623D7F9B3004567A1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9ED9CC523D7F9B3004567A1 /* AppDelegate.swift */; }; 46 | C9ED9CCA23D7F9B3004567A1 /* Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9ED9CC923D7F9B3004567A1 /* Document.swift */; }; 47 | C9ED9CCC23D7F9B4004567A1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C9ED9CCB23D7F9B4004567A1 /* Assets.xcassets */; }; 48 | C9ED9CCF23D7F9B4004567A1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C9ED9CCD23D7F9B4004567A1 /* Main.storyboard */; }; 49 | C9ED9CDE23D7F9D0004567A1 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9ED9CDD23D7F9D0004567A1 /* Cocoa.framework */; }; 50 | C9ED9CE123D7F9D0004567A1 /* SourceEditorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9ED9CE023D7F9D0004567A1 /* SourceEditorExtension.swift */; }; 51 | C9ED9CE323D7F9D0004567A1 /* SourceEditorCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9ED9CE223D7F9D0004567A1 /* SourceEditorCommand.swift */; }; 52 | C9ED9CE823D7F9D0004567A1 /* SwiftJSONModeler.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = C9ED9CDB23D7F9D0004567A1 /* SwiftJSONModeler.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 53 | /* End PBXBuildFile section */ 54 | 55 | /* Begin PBXContainerItemProxy section */ 56 | C9D04F2D242F218200843DC4 /* PBXContainerItemProxy */ = { 57 | isa = PBXContainerItemProxy; 58 | containerPortal = C9ED9CBA23D7F9B3004567A1 /* Project object */; 59 | proxyType = 1; 60 | remoteGlobalIDString = C9ED9CC123D7F9B3004567A1; 61 | remoteInfo = "SwiftJSONModeler For Xcode"; 62 | }; 63 | C9ED9CE623D7F9D0004567A1 /* PBXContainerItemProxy */ = { 64 | isa = PBXContainerItemProxy; 65 | containerPortal = C9ED9CBA23D7F9B3004567A1 /* Project object */; 66 | proxyType = 1; 67 | remoteGlobalIDString = C9ED9CDA23D7F9D0004567A1; 68 | remoteInfo = JSONSwiftModel; 69 | }; 70 | /* End PBXContainerItemProxy section */ 71 | 72 | /* Begin PBXCopyFilesBuildPhase section */ 73 | C90EFE0E257E172E0008632B /* Embed Frameworks */ = { 74 | isa = PBXCopyFilesBuildPhase; 75 | buildActionMask = 2147483647; 76 | dstPath = ""; 77 | dstSubfolderSpec = 10; 78 | files = ( 79 | C90EFE0D257E172E0008632B /* XcodeKit.framework in Embed Frameworks */, 80 | ); 81 | name = "Embed Frameworks"; 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | C9ED9CEC23D7F9D0004567A1 /* Embed App Extensions */ = { 85 | isa = PBXCopyFilesBuildPhase; 86 | buildActionMask = 2147483647; 87 | dstPath = ""; 88 | dstSubfolderSpec = 13; 89 | files = ( 90 | C9ED9CE823D7F9D0004567A1 /* SwiftJSONModeler.appex in Embed App Extensions */, 91 | ); 92 | name = "Embed App Extensions"; 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | /* End PBXCopyFilesBuildPhase section */ 96 | 97 | /* Begin PBXFileReference section */ 98 | C90EFE0B257E172E0008632B /* XcodeKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XcodeKit.framework; path = Library/Frameworks/XcodeKit.framework; sourceTree = DEVELOPER_DIR; }; 99 | C92A970524E50D5900C87CCD /* YApiObjectTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YApiObjectTest.swift; sourceTree = ""; }; 100 | C92A971C24E514FB00C87CCD /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 101 | C935B49B24EA24BE00E48231 /* JSONHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONHelper.swift; sourceTree = ""; }; 102 | C935B49D24EA56EF00E48231 /* JSONHelperTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONHelperTest.swift; sourceTree = ""; }; 103 | C94AFC00241F4AE600389AF3 /* YApiHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YApiHelper.swift; sourceTree = ""; }; 104 | C94AFC03241F4E8A00389AF3 /* YApiObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YApiObject.swift; sourceTree = ""; }; 105 | C961C1DD23D82A8D008D0DE6 /* ConfigViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigViewController.swift; sourceTree = ""; }; 106 | C9AB1D302637B211008256ED /* OrderJSON+Yapi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OrderJSON+Yapi.swift"; sourceTree = ""; }; 107 | C9AB1D352637C34B008256ED /* OrderJSON+YApiTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OrderJSON+YApiTest.swift"; sourceTree = ""; }; 108 | C9CB247F241F559C00F4D5CE /* ErrorCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorCenter.swift; sourceTree = ""; }; 109 | C9CEE26C242B382900A04EA9 /* YApiCreator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YApiCreator.swift; sourceTree = ""; }; 110 | C9D04F20242EF99F00843DC4 /* YApiRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YApiRequest.swift; sourceTree = ""; }; 111 | C9D04F28242F218200843DC4 /* SwiftJSONModeler For XcodeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftJSONModeler For XcodeTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 112 | C9D04F2A242F218200843DC4 /* SwiftJSONModeler_For_XcodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftJSONModeler_For_XcodeTests.swift; sourceTree = ""; }; 113 | C9D04F2C242F218200843DC4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 114 | C9D9905725E776A900258865 /* ConfigCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigCenter.swift; sourceTree = ""; }; 115 | C9E393E324EE248500D80B28 /* TokenView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TokenView.xib; sourceTree = ""; }; 116 | C9E393E724EE255900D80B28 /* TokenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenView.swift; sourceTree = ""; }; 117 | C9E393E924EE47D300D80B28 /* TokenViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenViewController.swift; sourceTree = ""; }; 118 | C9E9C08825CF907A00CD767D /* OpenSavePanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenSavePanel.swift; sourceTree = ""; }; 119 | C9E9C09125CFD94E00CD767D /* ConfigModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigModel.swift; sourceTree = ""; }; 120 | C9ED9CC223D7F9B3004567A1 /* SwiftJSONModeler For Xcode.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SwiftJSONModeler For Xcode.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 121 | C9ED9CC523D7F9B3004567A1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 122 | C9ED9CC923D7F9B3004567A1 /* Document.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Document.swift; sourceTree = ""; }; 123 | C9ED9CCB23D7F9B4004567A1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 124 | C9ED9CCE23D7F9B4004567A1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 125 | C9ED9CD023D7F9B4004567A1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 126 | C9ED9CD123D7F9B4004567A1 /* SwiftJSONModeler For Xcode.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SwiftJSONModeler For Xcode.entitlements"; sourceTree = ""; }; 127 | C9ED9CDB23D7F9D0004567A1 /* SwiftJSONModeler.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SwiftJSONModeler.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 128 | C9ED9CDD23D7F9D0004567A1 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 129 | C9ED9CE023D7F9D0004567A1 /* SourceEditorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceEditorExtension.swift; sourceTree = ""; }; 130 | C9ED9CE223D7F9D0004567A1 /* SourceEditorCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceEditorCommand.swift; sourceTree = ""; }; 131 | C9ED9CE423D7F9D0004567A1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 132 | C9ED9CE523D7F9D0004567A1 /* SwiftJSONModeler.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SwiftJSONModeler.entitlements; sourceTree = ""; }; 133 | /* End PBXFileReference section */ 134 | 135 | /* Begin PBXFrameworksBuildPhase section */ 136 | C9D04F25242F218200843DC4 /* Frameworks */ = { 137 | isa = PBXFrameworksBuildPhase; 138 | buildActionMask = 2147483647; 139 | files = ( 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | C9ED9CBF23D7F9B3004567A1 /* Frameworks */ = { 144 | isa = PBXFrameworksBuildPhase; 145 | buildActionMask = 2147483647; 146 | files = ( 147 | C9D9906725E7807300258865 /* CleanJSON in Frameworks */, 148 | C9AB1D6826395F82008256ED /* OrderJSON in Frameworks */, 149 | ); 150 | runOnlyForDeploymentPostprocessing = 0; 151 | }; 152 | C9ED9CD823D7F9D0004567A1 /* Frameworks */ = { 153 | isa = PBXFrameworksBuildPhase; 154 | buildActionMask = 2147483647; 155 | files = ( 156 | C9ED9CDE23D7F9D0004567A1 /* Cocoa.framework in Frameworks */, 157 | C9D9906D25E7815F00258865 /* CleanJSON in Frameworks */, 158 | C90EFE0C257E172E0008632B /* XcodeKit.framework in Frameworks */, 159 | C9AB1D6C26395F8E008256ED /* OrderJSON in Frameworks */, 160 | ); 161 | runOnlyForDeploymentPostprocessing = 0; 162 | }; 163 | /* End PBXFrameworksBuildPhase section */ 164 | 165 | /* Begin PBXGroup section */ 166 | C92A971B24E514D700C87CCD /* Constants */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | C92A971C24E514FB00C87CCD /* Constants.swift */, 170 | ); 171 | path = Constants; 172 | sourceTree = ""; 173 | }; 174 | C94AFC02241F4E6D00389AF3 /* YApi */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | C9AB1D2F2637B1FA008256ED /* OrderJSON+YApi */, 178 | C94AFC00241F4AE600389AF3 /* YApiHelper.swift */, 179 | C94AFC03241F4E8A00389AF3 /* YApiObject.swift */, 180 | C9CEE26C242B382900A04EA9 /* YApiCreator.swift */, 181 | C9D04F20242EF99F00843DC4 /* YApiRequest.swift */, 182 | ); 183 | path = YApi; 184 | sourceTree = ""; 185 | }; 186 | C9AB1D2F2637B1FA008256ED /* OrderJSON+YApi */ = { 187 | isa = PBXGroup; 188 | children = ( 189 | C9AB1D302637B211008256ED /* OrderJSON+Yapi.swift */, 190 | ); 191 | path = "OrderJSON+YApi"; 192 | sourceTree = ""; 193 | }; 194 | C9AB1D5A2638FA9A008256ED /* NormalJSON */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | C935B49B24EA24BE00E48231 /* JSONHelper.swift */, 198 | ); 199 | path = NormalJSON; 200 | sourceTree = ""; 201 | }; 202 | C9D04F29242F218200843DC4 /* SwiftJSONModeler For XcodeTests */ = { 203 | isa = PBXGroup; 204 | children = ( 205 | C9D04F32242F228400843DC4 /* SwiftJSONModelerTest */, 206 | C9D04F2A242F218200843DC4 /* SwiftJSONModeler_For_XcodeTests.swift */, 207 | C9D04F2C242F218200843DC4 /* Info.plist */, 208 | ); 209 | path = "SwiftJSONModeler For XcodeTests"; 210 | sourceTree = ""; 211 | }; 212 | C9D04F32242F228400843DC4 /* SwiftJSONModelerTest */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | C92A970524E50D5900C87CCD /* YApiObjectTest.swift */, 216 | C935B49D24EA56EF00E48231 /* JSONHelperTest.swift */, 217 | C9AB1D352637C34B008256ED /* OrderJSON+YApiTest.swift */, 218 | ); 219 | path = SwiftJSONModelerTest; 220 | sourceTree = ""; 221 | }; 222 | C9D9905625E7765C00258865 /* Config */ = { 223 | isa = PBXGroup; 224 | children = ( 225 | C9E9C09025CFD93900CD767D /* Model */, 226 | C9D9905725E776A900258865 /* ConfigCenter.swift */, 227 | ); 228 | path = Config; 229 | sourceTree = ""; 230 | }; 231 | C9E393E224EE245D00D80B28 /* View */ = { 232 | isa = PBXGroup; 233 | children = ( 234 | C9E393E324EE248500D80B28 /* TokenView.xib */, 235 | C9E393E724EE255900D80B28 /* TokenView.swift */, 236 | ); 237 | path = View; 238 | sourceTree = ""; 239 | }; 240 | C9E393EB24EF68E900D80B28 /* Controller */ = { 241 | isa = PBXGroup; 242 | children = ( 243 | C961C1DD23D82A8D008D0DE6 /* ConfigViewController.swift */, 244 | C9E393E924EE47D300D80B28 /* TokenViewController.swift */, 245 | ); 246 | path = Controller; 247 | sourceTree = ""; 248 | }; 249 | C9E9C08725CF905400CD767D /* Utils */ = { 250 | isa = PBXGroup; 251 | children = ( 252 | C9E9C08825CF907A00CD767D /* OpenSavePanel.swift */, 253 | ); 254 | path = Utils; 255 | sourceTree = ""; 256 | }; 257 | C9E9C09025CFD93900CD767D /* Model */ = { 258 | isa = PBXGroup; 259 | children = ( 260 | C9E9C09125CFD94E00CD767D /* ConfigModel.swift */, 261 | ); 262 | path = Model; 263 | sourceTree = ""; 264 | }; 265 | C9ED9CB923D7F9B3004567A1 = { 266 | isa = PBXGroup; 267 | children = ( 268 | C9ED9CC423D7F9B3004567A1 /* SwiftJSONModeler For Xcode */, 269 | C9ED9CDF23D7F9D0004567A1 /* SwiftJSONModeler */, 270 | C9D04F29242F218200843DC4 /* SwiftJSONModeler For XcodeTests */, 271 | C9ED9CDC23D7F9D0004567A1 /* Frameworks */, 272 | C9ED9CC323D7F9B3004567A1 /* Products */, 273 | ); 274 | sourceTree = ""; 275 | }; 276 | C9ED9CC323D7F9B3004567A1 /* Products */ = { 277 | isa = PBXGroup; 278 | children = ( 279 | C9ED9CC223D7F9B3004567A1 /* SwiftJSONModeler For Xcode.app */, 280 | C9ED9CDB23D7F9D0004567A1 /* SwiftJSONModeler.appex */, 281 | C9D04F28242F218200843DC4 /* SwiftJSONModeler For XcodeTests.xctest */, 282 | ); 283 | name = Products; 284 | sourceTree = ""; 285 | }; 286 | C9ED9CC423D7F9B3004567A1 /* SwiftJSONModeler For Xcode */ = { 287 | isa = PBXGroup; 288 | children = ( 289 | C9AB1D5A2638FA9A008256ED /* NormalJSON */, 290 | C9D9905625E7765C00258865 /* Config */, 291 | C9E9C08725CF905400CD767D /* Utils */, 292 | C9E393EB24EF68E900D80B28 /* Controller */, 293 | C9E393E224EE245D00D80B28 /* View */, 294 | C92A971B24E514D700C87CCD /* Constants */, 295 | C94AFC02241F4E6D00389AF3 /* YApi */, 296 | C9ED9CC523D7F9B3004567A1 /* AppDelegate.swift */, 297 | C9ED9CC923D7F9B3004567A1 /* Document.swift */, 298 | C9ED9CCB23D7F9B4004567A1 /* Assets.xcassets */, 299 | C9ED9CCD23D7F9B4004567A1 /* Main.storyboard */, 300 | C9ED9CD023D7F9B4004567A1 /* Info.plist */, 301 | C9ED9CD123D7F9B4004567A1 /* SwiftJSONModeler For Xcode.entitlements */, 302 | C9CB247F241F559C00F4D5CE /* ErrorCenter.swift */, 303 | ); 304 | path = "SwiftJSONModeler For Xcode"; 305 | sourceTree = ""; 306 | }; 307 | C9ED9CDC23D7F9D0004567A1 /* Frameworks */ = { 308 | isa = PBXGroup; 309 | children = ( 310 | C90EFE0B257E172E0008632B /* XcodeKit.framework */, 311 | C9ED9CDD23D7F9D0004567A1 /* Cocoa.framework */, 312 | ); 313 | name = Frameworks; 314 | sourceTree = ""; 315 | }; 316 | C9ED9CDF23D7F9D0004567A1 /* SwiftJSONModeler */ = { 317 | isa = PBXGroup; 318 | children = ( 319 | C9ED9CE023D7F9D0004567A1 /* SourceEditorExtension.swift */, 320 | C9ED9CE223D7F9D0004567A1 /* SourceEditorCommand.swift */, 321 | C9ED9CE423D7F9D0004567A1 /* Info.plist */, 322 | C9ED9CE523D7F9D0004567A1 /* SwiftJSONModeler.entitlements */, 323 | ); 324 | path = SwiftJSONModeler; 325 | sourceTree = ""; 326 | }; 327 | /* End PBXGroup section */ 328 | 329 | /* Begin PBXNativeTarget section */ 330 | C9D04F27242F218200843DC4 /* SwiftJSONModeler For XcodeTests */ = { 331 | isa = PBXNativeTarget; 332 | buildConfigurationList = C9D04F2F242F218200843DC4 /* Build configuration list for PBXNativeTarget "SwiftJSONModeler For XcodeTests" */; 333 | buildPhases = ( 334 | C9D04F24242F218200843DC4 /* Sources */, 335 | C9D04F25242F218200843DC4 /* Frameworks */, 336 | C9D04F26242F218200843DC4 /* Resources */, 337 | ); 338 | buildRules = ( 339 | ); 340 | dependencies = ( 341 | C9D04F2E242F218200843DC4 /* PBXTargetDependency */, 342 | ); 343 | name = "SwiftJSONModeler For XcodeTests"; 344 | productName = "SwiftJSONModeler For XcodeTests"; 345 | productReference = C9D04F28242F218200843DC4 /* SwiftJSONModeler For XcodeTests.xctest */; 346 | productType = "com.apple.product-type.bundle.unit-test"; 347 | }; 348 | C9ED9CC123D7F9B3004567A1 /* SwiftJSONModeler For Xcode */ = { 349 | isa = PBXNativeTarget; 350 | buildConfigurationList = C9ED9CD423D7F9B4004567A1 /* Build configuration list for PBXNativeTarget "SwiftJSONModeler For Xcode" */; 351 | buildPhases = ( 352 | C9ED9CBE23D7F9B3004567A1 /* Sources */, 353 | C9ED9CBF23D7F9B3004567A1 /* Frameworks */, 354 | C9ED9CC023D7F9B3004567A1 /* Resources */, 355 | C9ED9CEC23D7F9D0004567A1 /* Embed App Extensions */, 356 | ); 357 | buildRules = ( 358 | ); 359 | dependencies = ( 360 | C9ED9CE723D7F9D0004567A1 /* PBXTargetDependency */, 361 | ); 362 | name = "SwiftJSONModeler For Xcode"; 363 | packageProductDependencies = ( 364 | C9D9906625E7807300258865 /* CleanJSON */, 365 | C9AB1D6726395F82008256ED /* OrderJSON */, 366 | ); 367 | productName = JSONSwiftModelApp; 368 | productReference = C9ED9CC223D7F9B3004567A1 /* SwiftJSONModeler For Xcode.app */; 369 | productType = "com.apple.product-type.application"; 370 | }; 371 | C9ED9CDA23D7F9D0004567A1 /* SwiftJSONModeler */ = { 372 | isa = PBXNativeTarget; 373 | buildConfigurationList = C9ED9CE923D7F9D0004567A1 /* Build configuration list for PBXNativeTarget "SwiftJSONModeler" */; 374 | buildPhases = ( 375 | C9ED9CD723D7F9D0004567A1 /* Sources */, 376 | C9ED9CD823D7F9D0004567A1 /* Frameworks */, 377 | C9ED9CD923D7F9D0004567A1 /* Resources */, 378 | C90EFE0E257E172E0008632B /* Embed Frameworks */, 379 | ); 380 | buildRules = ( 381 | ); 382 | dependencies = ( 383 | ); 384 | name = SwiftJSONModeler; 385 | packageProductDependencies = ( 386 | C9D9906C25E7815F00258865 /* CleanJSON */, 387 | C9AB1D6B26395F8E008256ED /* OrderJSON */, 388 | ); 389 | productName = JSONSwiftModel; 390 | productReference = C9ED9CDB23D7F9D0004567A1 /* SwiftJSONModeler.appex */; 391 | productType = "com.apple.product-type.xcode-extension"; 392 | }; 393 | /* End PBXNativeTarget section */ 394 | 395 | /* Begin PBXProject section */ 396 | C9ED9CBA23D7F9B3004567A1 /* Project object */ = { 397 | isa = PBXProject; 398 | attributes = { 399 | LastSwiftUpdateCheck = 1120; 400 | LastUpgradeCheck = 1120; 401 | ORGANIZATIONNAME = Sven; 402 | TargetAttributes = { 403 | C9D04F27242F218200843DC4 = { 404 | CreatedOnToolsVersion = 11.2.1; 405 | TestTargetID = C9ED9CC123D7F9B3004567A1; 406 | }; 407 | C9ED9CC123D7F9B3004567A1 = { 408 | CreatedOnToolsVersion = 11.2.1; 409 | }; 410 | C9ED9CDA23D7F9D0004567A1 = { 411 | CreatedOnToolsVersion = 11.2.1; 412 | }; 413 | }; 414 | }; 415 | buildConfigurationList = C9ED9CBD23D7F9B3004567A1 /* Build configuration list for PBXProject "SwiftJSONModeler For Xcode" */; 416 | compatibilityVersion = "Xcode 9.3"; 417 | developmentRegion = en; 418 | hasScannedForEncodings = 0; 419 | knownRegions = ( 420 | en, 421 | Base, 422 | ); 423 | mainGroup = C9ED9CB923D7F9B3004567A1; 424 | packageReferences = ( 425 | C9D9906525E7807300258865 /* XCRemoteSwiftPackageReference "CleanJSON" */, 426 | C9AB1D6626395F82008256ED /* XCRemoteSwiftPackageReference "order-json" */, 427 | ); 428 | productRefGroup = C9ED9CC323D7F9B3004567A1 /* Products */; 429 | projectDirPath = ""; 430 | projectRoot = ""; 431 | targets = ( 432 | C9ED9CC123D7F9B3004567A1 /* SwiftJSONModeler For Xcode */, 433 | C9ED9CDA23D7F9D0004567A1 /* SwiftJSONModeler */, 434 | C9D04F27242F218200843DC4 /* SwiftJSONModeler For XcodeTests */, 435 | ); 436 | }; 437 | /* End PBXProject section */ 438 | 439 | /* Begin PBXResourcesBuildPhase section */ 440 | C9D04F26242F218200843DC4 /* Resources */ = { 441 | isa = PBXResourcesBuildPhase; 442 | buildActionMask = 2147483647; 443 | files = ( 444 | ); 445 | runOnlyForDeploymentPostprocessing = 0; 446 | }; 447 | C9ED9CC023D7F9B3004567A1 /* Resources */ = { 448 | isa = PBXResourcesBuildPhase; 449 | buildActionMask = 2147483647; 450 | files = ( 451 | C9E393E424EE248500D80B28 /* TokenView.xib in Resources */, 452 | C9ED9CCC23D7F9B4004567A1 /* Assets.xcassets in Resources */, 453 | C9ED9CCF23D7F9B4004567A1 /* Main.storyboard in Resources */, 454 | ); 455 | runOnlyForDeploymentPostprocessing = 0; 456 | }; 457 | C9ED9CD923D7F9D0004567A1 /* Resources */ = { 458 | isa = PBXResourcesBuildPhase; 459 | buildActionMask = 2147483647; 460 | files = ( 461 | ); 462 | runOnlyForDeploymentPostprocessing = 0; 463 | }; 464 | /* End PBXResourcesBuildPhase section */ 465 | 466 | /* Begin PBXSourcesBuildPhase section */ 467 | C9D04F24242F218200843DC4 /* Sources */ = { 468 | isa = PBXSourcesBuildPhase; 469 | buildActionMask = 2147483647; 470 | files = ( 471 | C935B49E24EA56EF00E48231 /* JSONHelperTest.swift in Sources */, 472 | C9D04F2B242F218200843DC4 /* SwiftJSONModeler_For_XcodeTests.swift in Sources */, 473 | C9AB1D362637C34B008256ED /* OrderJSON+YApiTest.swift in Sources */, 474 | C92A970A24E512BD00C87CCD /* YApiObjectTest.swift in Sources */, 475 | ); 476 | runOnlyForDeploymentPostprocessing = 0; 477 | }; 478 | C9ED9CBE23D7F9B3004567A1 /* Sources */ = { 479 | isa = PBXSourcesBuildPhase; 480 | buildActionMask = 2147483647; 481 | files = ( 482 | C92A971724E513EA00C87CCD /* YApiRequest.swift in Sources */, 483 | C92A971824E513F900C87CCD /* ErrorCenter.swift in Sources */, 484 | C9E9C09225CFD94E00CD767D /* ConfigModel.swift in Sources */, 485 | C9E393E824EE255900D80B28 /* TokenView.swift in Sources */, 486 | C9ED9CC623D7F9B3004567A1 /* AppDelegate.swift in Sources */, 487 | C9AB1D312637B211008256ED /* OrderJSON+Yapi.swift in Sources */, 488 | C9E393EA24EE47D300D80B28 /* TokenViewController.swift in Sources */, 489 | C92A971624E513EA00C87CCD /* YApiCreator.swift in Sources */, 490 | C92A971D24E514FB00C87CCD /* Constants.swift in Sources */, 491 | C92A971424E513EA00C87CCD /* YApiHelper.swift in Sources */, 492 | C9ED9CCA23D7F9B3004567A1 /* Document.swift in Sources */, 493 | C9E9C08925CF907A00CD767D /* OpenSavePanel.swift in Sources */, 494 | C935B49C24EA24BE00E48231 /* JSONHelper.swift in Sources */, 495 | C9D9905825E776A900258865 /* ConfigCenter.swift in Sources */, 496 | C961C1DE23D82A8D008D0DE6 /* ConfigViewController.swift in Sources */, 497 | C92A971524E513EA00C87CCD /* YApiObject.swift in Sources */, 498 | ); 499 | runOnlyForDeploymentPostprocessing = 0; 500 | }; 501 | C9ED9CD723D7F9D0004567A1 /* Sources */ = { 502 | isa = PBXSourcesBuildPhase; 503 | buildActionMask = 2147483647; 504 | files = ( 505 | C9DD88322431C630004E420F /* YApiRequest.swift in Sources */, 506 | C9CB2480241F559C00F4D5CE /* ErrorCenter.swift in Sources */, 507 | C9ED9CE123D7F9D0004567A1 /* SourceEditorExtension.swift in Sources */, 508 | C94AFC01241F4AE600389AF3 /* YApiHelper.swift in Sources */, 509 | C94AFC04241F4E8A00389AF3 /* YApiObject.swift in Sources */, 510 | C9ED9CE323D7F9D0004567A1 /* SourceEditorCommand.swift in Sources */, 511 | C9D9905C25E776EF00258865 /* ConfigModel.swift in Sources */, 512 | C9D9906E25E7816600258865 /* ConfigCenter.swift in Sources */, 513 | C9CEE26D242B382900A04EA9 /* YApiCreator.swift in Sources */, 514 | C92A971E24E5150600C87CCD /* Constants.swift in Sources */, 515 | C9AB1D322637B211008256ED /* OrderJSON+Yapi.swift in Sources */, 516 | C935B49F24EA664A00E48231 /* JSONHelper.swift in Sources */, 517 | ); 518 | runOnlyForDeploymentPostprocessing = 0; 519 | }; 520 | /* End PBXSourcesBuildPhase section */ 521 | 522 | /* Begin PBXTargetDependency section */ 523 | C9D04F2E242F218200843DC4 /* PBXTargetDependency */ = { 524 | isa = PBXTargetDependency; 525 | target = C9ED9CC123D7F9B3004567A1 /* SwiftJSONModeler For Xcode */; 526 | targetProxy = C9D04F2D242F218200843DC4 /* PBXContainerItemProxy */; 527 | }; 528 | C9ED9CE723D7F9D0004567A1 /* PBXTargetDependency */ = { 529 | isa = PBXTargetDependency; 530 | target = C9ED9CDA23D7F9D0004567A1 /* SwiftJSONModeler */; 531 | targetProxy = C9ED9CE623D7F9D0004567A1 /* PBXContainerItemProxy */; 532 | }; 533 | /* End PBXTargetDependency section */ 534 | 535 | /* Begin PBXVariantGroup section */ 536 | C9ED9CCD23D7F9B4004567A1 /* Main.storyboard */ = { 537 | isa = PBXVariantGroup; 538 | children = ( 539 | C9ED9CCE23D7F9B4004567A1 /* Base */, 540 | ); 541 | name = Main.storyboard; 542 | sourceTree = ""; 543 | }; 544 | /* End PBXVariantGroup section */ 545 | 546 | /* Begin XCBuildConfiguration section */ 547 | C9D04F30242F218200843DC4 /* Debug */ = { 548 | isa = XCBuildConfiguration; 549 | buildSettings = { 550 | BUNDLE_LOADER = "$(TEST_HOST)"; 551 | CODE_SIGN_STYLE = Automatic; 552 | COMBINE_HIDPI_IMAGES = YES; 553 | DEVELOPMENT_TEAM = K9DS6XKGWL; 554 | INFOPLIST_FILE = "SwiftJSONModeler For XcodeTests/Info.plist"; 555 | LD_RUNPATH_SEARCH_PATHS = ( 556 | "$(inherited)", 557 | "@executable_path/../Frameworks", 558 | "@loader_path/../Frameworks", 559 | ); 560 | MACOSX_DEPLOYMENT_TARGET = 10.14; 561 | PRODUCT_BUNDLE_IDENTIFIER = "com.lifu.SwiftJSONModeler-For-XcodeTests"; 562 | PRODUCT_NAME = "$(TARGET_NAME)"; 563 | SWIFT_VERSION = 5.0; 564 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftJSONModeler For Xcode.app/Contents/MacOS/SwiftJSONModeler For Xcode"; 565 | }; 566 | name = Debug; 567 | }; 568 | C9D04F31242F218200843DC4 /* Release */ = { 569 | isa = XCBuildConfiguration; 570 | buildSettings = { 571 | BUNDLE_LOADER = "$(TEST_HOST)"; 572 | CODE_SIGN_STYLE = Automatic; 573 | COMBINE_HIDPI_IMAGES = YES; 574 | DEVELOPMENT_TEAM = K9DS6XKGWL; 575 | INFOPLIST_FILE = "SwiftJSONModeler For XcodeTests/Info.plist"; 576 | LD_RUNPATH_SEARCH_PATHS = ( 577 | "$(inherited)", 578 | "@executable_path/../Frameworks", 579 | "@loader_path/../Frameworks", 580 | ); 581 | MACOSX_DEPLOYMENT_TARGET = 10.14; 582 | PRODUCT_BUNDLE_IDENTIFIER = "com.lifu.SwiftJSONModeler-For-XcodeTests"; 583 | PRODUCT_NAME = "$(TARGET_NAME)"; 584 | SWIFT_VERSION = 5.0; 585 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftJSONModeler For Xcode.app/Contents/MacOS/SwiftJSONModeler For Xcode"; 586 | }; 587 | name = Release; 588 | }; 589 | C9ED9CD223D7F9B4004567A1 /* Debug */ = { 590 | isa = XCBuildConfiguration; 591 | buildSettings = { 592 | ALWAYS_SEARCH_USER_PATHS = NO; 593 | CLANG_ANALYZER_NONNULL = YES; 594 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 595 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 596 | CLANG_CXX_LIBRARY = "libc++"; 597 | CLANG_ENABLE_MODULES = YES; 598 | CLANG_ENABLE_OBJC_ARC = YES; 599 | CLANG_ENABLE_OBJC_WEAK = YES; 600 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 601 | CLANG_WARN_BOOL_CONVERSION = YES; 602 | CLANG_WARN_COMMA = YES; 603 | CLANG_WARN_CONSTANT_CONVERSION = YES; 604 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 605 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 606 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 607 | CLANG_WARN_EMPTY_BODY = YES; 608 | CLANG_WARN_ENUM_CONVERSION = YES; 609 | CLANG_WARN_INFINITE_RECURSION = YES; 610 | CLANG_WARN_INT_CONVERSION = YES; 611 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 612 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 613 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 614 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 615 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 616 | CLANG_WARN_STRICT_PROTOTYPES = YES; 617 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 618 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 619 | CLANG_WARN_UNREACHABLE_CODE = YES; 620 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 621 | COPY_PHASE_STRIP = NO; 622 | DEBUG_INFORMATION_FORMAT = dwarf; 623 | ENABLE_STRICT_OBJC_MSGSEND = YES; 624 | ENABLE_TESTABILITY = YES; 625 | GCC_C_LANGUAGE_STANDARD = gnu11; 626 | GCC_DYNAMIC_NO_PIC = NO; 627 | GCC_NO_COMMON_BLOCKS = YES; 628 | GCC_OPTIMIZATION_LEVEL = 0; 629 | GCC_PREPROCESSOR_DEFINITIONS = ( 630 | "DEBUG=1", 631 | "$(inherited)", 632 | ); 633 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 634 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 635 | GCC_WARN_UNDECLARED_SELECTOR = YES; 636 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 637 | GCC_WARN_UNUSED_FUNCTION = YES; 638 | GCC_WARN_UNUSED_VARIABLE = YES; 639 | MACOSX_DEPLOYMENT_TARGET = 10.11; 640 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 641 | MTL_FAST_MATH = YES; 642 | ONLY_ACTIVE_ARCH = YES; 643 | SDKROOT = macosx; 644 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 645 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 646 | }; 647 | name = Debug; 648 | }; 649 | C9ED9CD323D7F9B4004567A1 /* Release */ = { 650 | isa = XCBuildConfiguration; 651 | buildSettings = { 652 | ALWAYS_SEARCH_USER_PATHS = NO; 653 | CLANG_ANALYZER_NONNULL = YES; 654 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 655 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 656 | CLANG_CXX_LIBRARY = "libc++"; 657 | CLANG_ENABLE_MODULES = YES; 658 | CLANG_ENABLE_OBJC_ARC = YES; 659 | CLANG_ENABLE_OBJC_WEAK = YES; 660 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 661 | CLANG_WARN_BOOL_CONVERSION = YES; 662 | CLANG_WARN_COMMA = YES; 663 | CLANG_WARN_CONSTANT_CONVERSION = YES; 664 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 665 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 666 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 667 | CLANG_WARN_EMPTY_BODY = YES; 668 | CLANG_WARN_ENUM_CONVERSION = YES; 669 | CLANG_WARN_INFINITE_RECURSION = YES; 670 | CLANG_WARN_INT_CONVERSION = YES; 671 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 672 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 673 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 674 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 675 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 676 | CLANG_WARN_STRICT_PROTOTYPES = YES; 677 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 678 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 679 | CLANG_WARN_UNREACHABLE_CODE = YES; 680 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 681 | COPY_PHASE_STRIP = NO; 682 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 683 | ENABLE_NS_ASSERTIONS = NO; 684 | ENABLE_STRICT_OBJC_MSGSEND = YES; 685 | GCC_C_LANGUAGE_STANDARD = gnu11; 686 | GCC_NO_COMMON_BLOCKS = YES; 687 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 688 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 689 | GCC_WARN_UNDECLARED_SELECTOR = YES; 690 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 691 | GCC_WARN_UNUSED_FUNCTION = YES; 692 | GCC_WARN_UNUSED_VARIABLE = YES; 693 | MACOSX_DEPLOYMENT_TARGET = 10.11; 694 | MTL_ENABLE_DEBUG_INFO = NO; 695 | MTL_FAST_MATH = YES; 696 | SDKROOT = macosx; 697 | SWIFT_COMPILATION_MODE = wholemodule; 698 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 699 | }; 700 | name = Release; 701 | }; 702 | C9ED9CD523D7F9B4004567A1 /* Debug */ = { 703 | isa = XCBuildConfiguration; 704 | buildSettings = { 705 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 706 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 707 | CODE_SIGN_ENTITLEMENTS = "SwiftJSONModeler For Xcode/SwiftJSONModeler For Xcode.entitlements"; 708 | CODE_SIGN_STYLE = Automatic; 709 | COMBINE_HIDPI_IMAGES = YES; 710 | CURRENT_PROJECT_VERSION = 2021.04.29; 711 | DEVELOPMENT_TEAM = K9DS6XKGWL; 712 | ENABLE_HARDENED_RUNTIME = YES; 713 | INFOPLIST_FILE = "SwiftJSONModeler For Xcode/Info.plist"; 714 | LD_RUNPATH_SEARCH_PATHS = ( 715 | "$(inherited)", 716 | "@executable_path/../Frameworks", 717 | ); 718 | MARKETING_VERSION = 3.0.0; 719 | PRODUCT_BUNDLE_IDENTIFIER = com.lifu.SwiftJSONModeler; 720 | PRODUCT_NAME = "$(TARGET_NAME)"; 721 | SWIFT_VERSION = 5.0; 722 | }; 723 | name = Debug; 724 | }; 725 | C9ED9CD623D7F9B4004567A1 /* Release */ = { 726 | isa = XCBuildConfiguration; 727 | buildSettings = { 728 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 729 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 730 | CODE_SIGN_ENTITLEMENTS = "SwiftJSONModeler For Xcode/SwiftJSONModeler For Xcode.entitlements"; 731 | CODE_SIGN_STYLE = Automatic; 732 | COMBINE_HIDPI_IMAGES = YES; 733 | CURRENT_PROJECT_VERSION = 2021.04.29; 734 | DEVELOPMENT_TEAM = K9DS6XKGWL; 735 | ENABLE_HARDENED_RUNTIME = YES; 736 | INFOPLIST_FILE = "SwiftJSONModeler For Xcode/Info.plist"; 737 | LD_RUNPATH_SEARCH_PATHS = ( 738 | "$(inherited)", 739 | "@executable_path/../Frameworks", 740 | ); 741 | MARKETING_VERSION = 3.0.0; 742 | PRODUCT_BUNDLE_IDENTIFIER = com.lifu.SwiftJSONModeler; 743 | PRODUCT_NAME = "$(TARGET_NAME)"; 744 | SWIFT_VERSION = 5.0; 745 | }; 746 | name = Release; 747 | }; 748 | C9ED9CEA23D7F9D0004567A1 /* Debug */ = { 749 | isa = XCBuildConfiguration; 750 | buildSettings = { 751 | CODE_SIGN_ENTITLEMENTS = SwiftJSONModeler/SwiftJSONModeler.entitlements; 752 | CODE_SIGN_IDENTITY = "Apple Development"; 753 | CODE_SIGN_STYLE = Automatic; 754 | COMBINE_HIDPI_IMAGES = YES; 755 | CURRENT_PROJECT_VERSION = 2021.04.29; 756 | DEVELOPMENT_TEAM = K9DS6XKGWL; 757 | ENABLE_HARDENED_RUNTIME = YES; 758 | INFOPLIST_FILE = SwiftJSONModeler/Info.plist; 759 | LD_RUNPATH_SEARCH_PATHS = ( 760 | "$(inherited)", 761 | "@executable_path/../Frameworks", 762 | "@executable_path/../../../../Frameworks", 763 | ); 764 | MARKETING_VERSION = 3.0.0; 765 | PRODUCT_BUNDLE_IDENTIFIER = com.lifu.SwiftJSONModeler; 766 | PRODUCT_NAME = "$(TARGET_NAME)"; 767 | SKIP_INSTALL = YES; 768 | SWIFT_VERSION = 5.0; 769 | }; 770 | name = Debug; 771 | }; 772 | C9ED9CEB23D7F9D0004567A1 /* Release */ = { 773 | isa = XCBuildConfiguration; 774 | buildSettings = { 775 | CODE_SIGN_ENTITLEMENTS = SwiftJSONModeler/SwiftJSONModeler.entitlements; 776 | CODE_SIGN_IDENTITY = "Apple Development"; 777 | CODE_SIGN_STYLE = Automatic; 778 | COMBINE_HIDPI_IMAGES = YES; 779 | CURRENT_PROJECT_VERSION = 2021.04.29; 780 | DEVELOPMENT_TEAM = K9DS6XKGWL; 781 | ENABLE_HARDENED_RUNTIME = YES; 782 | INFOPLIST_FILE = SwiftJSONModeler/Info.plist; 783 | LD_RUNPATH_SEARCH_PATHS = ( 784 | "$(inherited)", 785 | "@executable_path/../Frameworks", 786 | "@executable_path/../../../../Frameworks", 787 | ); 788 | MARKETING_VERSION = 3.0.0; 789 | PRODUCT_BUNDLE_IDENTIFIER = com.lifu.SwiftJSONModeler; 790 | PRODUCT_NAME = "$(TARGET_NAME)"; 791 | SKIP_INSTALL = YES; 792 | SWIFT_VERSION = 5.0; 793 | }; 794 | name = Release; 795 | }; 796 | /* End XCBuildConfiguration section */ 797 | 798 | /* Begin XCConfigurationList section */ 799 | C9D04F2F242F218200843DC4 /* Build configuration list for PBXNativeTarget "SwiftJSONModeler For XcodeTests" */ = { 800 | isa = XCConfigurationList; 801 | buildConfigurations = ( 802 | C9D04F30242F218200843DC4 /* Debug */, 803 | C9D04F31242F218200843DC4 /* Release */, 804 | ); 805 | defaultConfigurationIsVisible = 0; 806 | defaultConfigurationName = Release; 807 | }; 808 | C9ED9CBD23D7F9B3004567A1 /* Build configuration list for PBXProject "SwiftJSONModeler For Xcode" */ = { 809 | isa = XCConfigurationList; 810 | buildConfigurations = ( 811 | C9ED9CD223D7F9B4004567A1 /* Debug */, 812 | C9ED9CD323D7F9B4004567A1 /* Release */, 813 | ); 814 | defaultConfigurationIsVisible = 0; 815 | defaultConfigurationName = Release; 816 | }; 817 | C9ED9CD423D7F9B4004567A1 /* Build configuration list for PBXNativeTarget "SwiftJSONModeler For Xcode" */ = { 818 | isa = XCConfigurationList; 819 | buildConfigurations = ( 820 | C9ED9CD523D7F9B4004567A1 /* Debug */, 821 | C9ED9CD623D7F9B4004567A1 /* Release */, 822 | ); 823 | defaultConfigurationIsVisible = 0; 824 | defaultConfigurationName = Release; 825 | }; 826 | C9ED9CE923D7F9D0004567A1 /* Build configuration list for PBXNativeTarget "SwiftJSONModeler" */ = { 827 | isa = XCConfigurationList; 828 | buildConfigurations = ( 829 | C9ED9CEA23D7F9D0004567A1 /* Debug */, 830 | C9ED9CEB23D7F9D0004567A1 /* Release */, 831 | ); 832 | defaultConfigurationIsVisible = 0; 833 | defaultConfigurationName = Release; 834 | }; 835 | /* End XCConfigurationList section */ 836 | 837 | /* Begin XCRemoteSwiftPackageReference section */ 838 | C9AB1D6626395F82008256ED /* XCRemoteSwiftPackageReference "order-json" */ = { 839 | isa = XCRemoteSwiftPackageReference; 840 | repositoryURL = "https://gitee.com/Sven001/order-json.git"; 841 | requirement = { 842 | kind = upToNextMajorVersion; 843 | minimumVersion = 1.0.1; 844 | }; 845 | }; 846 | C9D9906525E7807300258865 /* XCRemoteSwiftPackageReference "CleanJSON" */ = { 847 | isa = XCRemoteSwiftPackageReference; 848 | repositoryURL = "https://github.com/Pircate/CleanJSON.git"; 849 | requirement = { 850 | kind = upToNextMajorVersion; 851 | minimumVersion = 1.0.8; 852 | }; 853 | }; 854 | /* End XCRemoteSwiftPackageReference section */ 855 | 856 | /* Begin XCSwiftPackageProductDependency section */ 857 | C9AB1D6726395F82008256ED /* OrderJSON */ = { 858 | isa = XCSwiftPackageProductDependency; 859 | package = C9AB1D6626395F82008256ED /* XCRemoteSwiftPackageReference "order-json" */; 860 | productName = OrderJSON; 861 | }; 862 | C9AB1D6B26395F8E008256ED /* OrderJSON */ = { 863 | isa = XCSwiftPackageProductDependency; 864 | package = C9AB1D6626395F82008256ED /* XCRemoteSwiftPackageReference "order-json" */; 865 | productName = OrderJSON; 866 | }; 867 | C9D9906625E7807300258865 /* CleanJSON */ = { 868 | isa = XCSwiftPackageProductDependency; 869 | package = C9D9906525E7807300258865 /* XCRemoteSwiftPackageReference "CleanJSON" */; 870 | productName = CleanJSON; 871 | }; 872 | C9D9906C25E7815F00258865 /* CleanJSON */ = { 873 | isa = XCSwiftPackageProductDependency; 874 | package = C9D9906525E7807300258865 /* XCRemoteSwiftPackageReference "CleanJSON" */; 875 | productName = CleanJSON; 876 | }; 877 | /* End XCSwiftPackageProductDependency section */ 878 | }; 879 | rootObject = C9ED9CBA23D7F9B3004567A1 /* Project object */; 880 | } 881 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "CleanJSON", 6 | "repositoryURL": "https://github.com/Pircate/CleanJSON.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "a60e181ec93e492af97a8ae4e444c2b7bf51149f", 10 | "version": "1.0.8" 11 | } 12 | }, 13 | { 14 | "package": "OrderJSON", 15 | "repositoryURL": "https://gitee.com/Sven001/order-json.git", 16 | "state": { 17 | "branch": null, 18 | "revision": "5d592f04d15c4283b8eb880ee7b2df3ce01388c5", 19 | "version": "1.0.1" 20 | } 21 | } 22 | ] 23 | }, 24 | "version": 1 25 | } 26 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode.xcodeproj/xcshareddata/xcschemes/SwiftJSONModeler For Xcode.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 44 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 81 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode.xcodeproj/xcshareddata/xcschemes/SwiftJSONModeler.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 6 | 9 | 10 | 16 | 22 | 23 | 24 | 30 | 36 | 37 | 38 | 39 | 40 | 45 | 46 | 48 | 54 | 55 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 80 | 84 | 85 | 86 | 92 | 93 | 94 | 95 | 102 | 104 | 110 | 111 | 112 | 113 | 115 | 116 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode.xcodeproj/xcuserdata/yibin.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 21 | 22 | 23 | 25 | 37 | 38 | 39 | 41 | 53 | 54 | 55 | 57 | 69 | 70 | 71 | 73 | 85 | 86 | 87 | 89 | 101 | 102 | 103 | 105 | 117 | 118 | 119 | 121 | 133 | 134 | 135 | 137 | 149 | 150 | 151 | 153 | 165 | 166 | 167 | 169 | 181 | 182 | 183 | 185 | 197 | 198 | 199 | 201 | 213 | 214 | 215 | 217 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode.xcodeproj/xcuserdata/yibin.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SwiftJSONModeler For Xcode.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | SwiftJSONModeler.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | C9ED9CC123D7F9B3004567A1 21 | 22 | primary 23 | 24 | 25 | C9ED9CDA23D7F9D0004567A1 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2020/1/22. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import SwiftJSONModeler 11 | 12 | @NSApplicationMain 13 | class AppDelegate: NSObject, NSApplicationDelegate { 14 | 15 | 16 | 17 | func applicationDidFinishLaunching(_ aNotification: Notification) { 18 | 19 | } 20 | 21 | func applicationWillTerminate(_ aNotification: Notification) { 22 | // Insert code here to tear down your application 23 | } 24 | 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "Icon_16x16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "Icon_16x16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "Icon_32x32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "Icon_32x32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "Icon_128x128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "Icon_128x128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "Icon_256x256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "Icon_256x256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "Icon_512x512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "Icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_128x128.png -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_128x128@2x.png -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_16x16.png -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_16x16@2x.png -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_256x256.png -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_256x256@2x.png -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_32x32.png -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_32x32@2x.png -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_512x512.png -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeOcenS/SwiftJSONModeler/1bdc074df754134d33c2b0e51e14f7b4c7f5bb4d/SwiftJSONModeler For Xcode/Assets.xcassets/AppIcon.appiconset/Icon_512x512@2x.png -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Config/ConfigCenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConfigCenter.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2021/2/25. 6 | // Copyright © 2021 Sven. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CleanJSON 11 | /// 配置存在路径 12 | let configPath = (NSHomeDirectory() as NSString).appendingPathComponent("Config.plist") 13 | 14 | class ConfigCenter { 15 | static let `default` = ConfigCenter() 16 | var config: ConfigModel 17 | 18 | private init() { 19 | config = Self.readConfig() 20 | } 21 | @discardableResult 22 | func save() -> Bool { 23 | return Self.writeConfig(config) 24 | } 25 | /// 获取最新配置 26 | func latest() -> ConfigModel { 27 | let model = Self.readConfig() 28 | config = model 29 | return model 30 | } 31 | 32 | 33 | } 34 | // MARK: - Private Static Method 35 | 36 | private extension ConfigCenter { 37 | static func readConfig() -> ConfigModel { 38 | let fileManager = FileManager.default 39 | guard let data = fileManager.contents(atPath: configPath) else { 40 | return writeDefaultConfig() 41 | } 42 | 43 | let decoder = PropertyListDecoder()//CleanJSONDecoder() 44 | do { 45 | let model = try decoder.decode(ConfigModel.self, from: data) 46 | return model 47 | } catch let error { 48 | print("读取 plist 转 model 失败") 49 | print(error) 50 | return writeDefaultConfig() 51 | } 52 | } 53 | 54 | static func writeDefaultConfig() -> ConfigModel { 55 | let defaultConfig = ConfigModel() 56 | writeConfig(defaultConfig) 57 | return defaultConfig 58 | } 59 | @discardableResult 60 | static func writeConfig(_ config: ConfigModel) -> Bool { 61 | // let propertyListEncoder = PropertyListEncoder() 62 | // propertyListEncoder.outputFormat = .xml 63 | // let plistData = try? propertyListEncoder.encode(config) 64 | guard let data = try? config.toJSON() else { 65 | return false 66 | } 67 | guard let dic = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary else { 68 | return false 69 | } 70 | let isSuccess = dic.write(toFile: configPath, atomically: true) 71 | //let isSuccess = FileManager.default.createFile(atPath: configPath, contents: data, attributes: nil) 72 | return isSuccess 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Config/Model/ConfigModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConfigModel.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2021/2/7. 6 | // Copyright © 2021 Sven. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class ConfigModel: Codable { 12 | var appVersion: String = "" 13 | var conform: String = "" 14 | var module: String = "" 15 | var prefix: String = "" 16 | var subffix = "" 17 | var isOptional: Bool = true 18 | /// 是否为隐式可选, 即 `Any!` 19 | var isImplicitlyOptional: Bool = false 20 | var isArrayDefaultEmpty: Bool = true 21 | /// 是否字符串类型默认为空 即 `""` 22 | var isStringDefaultEmpty: Bool = false 23 | var isShowYApiMock = false 24 | var yapiPath = "" 25 | /// 当前 token 26 | var yapiToken = "" 27 | var yapiHost = "" 28 | /// 备注 29 | var remark: String = "" 30 | /// 配置的多个 token 31 | var yapiTokenList: [YApiTokenModel] = [] 32 | } 33 | 34 | extension ConfigModel { 35 | var parent: String { 36 | let confroms = stringToArray(conform) 37 | if confroms.isEmpty { 38 | return "" 39 | } else { 40 | return confroms.joined(separator: ", ") 41 | } 42 | } 43 | 44 | var moduleArr: [String] { 45 | return stringToArray(module) 46 | } 47 | 48 | private func stringToArray(_ str: String) -> [String] { 49 | guard !str.isEmpty else { return [] } 50 | return str.components(separatedBy: ",") 51 | } 52 | 53 | } 54 | 55 | class YApiTokenModel: Codable { 56 | /// 项目名称 57 | var name: String = "" 58 | /// 项目 token 59 | var token: String = "" 60 | init(name: String, token: String) { 61 | self.name = name 62 | self.token = token 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Constants/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2020/8/13. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | let configCommand = "config" 12 | let structFromJSONCommand = "structFromJSON" 13 | let classFromJSONCommand = "classFromJSON" 14 | let structFromRAWCommand = "structFromRAW" 15 | let classFromRAWCommand = "classFromRAW" 16 | let structFromYApiIdCommand = "structFromYApiId" 17 | let classFromYApiIdCommand = "classFromYApiId" 18 | 19 | let domain = "SwiftJSONModeler" 20 | let keyImport = "import" 21 | let keyClass = "class" 22 | let keyStruct = "struct" 23 | 24 | typealias CommandId = String 25 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Controller/ConfigViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConfigViewController.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2020/1/22. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class ConfigViewController: NSViewController { 12 | private var configCenter = ConfigCenter.default 13 | private var config = ConfigCenter.default.config 14 | private var tokens: [YApiTokenModel] = [] 15 | private var token: String = "" 16 | 17 | @IBOutlet weak var confromTextField: NSTextField! 18 | 19 | @IBOutlet weak var moduleTextField: NSTextField! 20 | @IBOutlet weak var prefixTextField: NSTextField! 21 | @IBOutlet weak var subffixTextField: NSTextField! 22 | @IBOutlet weak var isAllowOptionalBtn: NSButton! 23 | @IBOutlet weak var isShowOptionalBtn: NSButton! 24 | @IBOutlet weak var isArrayEmptyBtn: NSButton! 25 | @IBOutlet weak var isShowYApiMockBtn: NSButton! 26 | @IBOutlet weak var pathTextField: NSTextField! 27 | @IBOutlet weak var tokenBox: NSComboBox! 28 | @IBOutlet weak var configTokenButton: NSButton! 29 | @IBOutlet weak var yapiHostTextField: NSTextField! 30 | @IBOutlet weak var remarkTextField: NSTextField! 31 | @IBOutlet weak var guideButton: NSButton! 32 | 33 | override func viewDidLoad() { 34 | super.viewDidLoad() 35 | title = "Model 设置" 36 | updateFromUserDefault() 37 | NotificationCenter.default.addObserver(forName: .tokenSaved, object: nil, queue: nil) { [weak self] (noti) in 38 | self?.setupBox() 39 | } 40 | } 41 | 42 | deinit { 43 | NotificationCenter.default.removeObserver(self) 44 | } 45 | 46 | private func updateFromUserDefault() { 47 | confromTextField.stringValue = config.conform 48 | moduleTextField.stringValue = config.module 49 | prefixTextField.stringValue = config.prefix 50 | subffixTextField.stringValue = config.subffix 51 | pathTextField.stringValue = config.yapiPath 52 | //yapiTokenTextField.stringValue = config.yapiToken 53 | yapiHostTextField.stringValue = config.yapiHost 54 | configTokenButton.attributedTitle = NSAttributedString(string: "配置Token", attributes: [NSAttributedString.Key.foregroundColor : NSColor.blue]) 55 | setupBox() 56 | remarkTextField.stringValue = config.remark 57 | 58 | isAllowOptionalBtn.state = config.isOptional ? .on : .off 59 | isShowOptionalBtn.state = config.isImplicitlyOptional ? .on : .off 60 | isArrayEmptyBtn.state = config.isArrayDefaultEmpty ? .on : .off 61 | isShowYApiMockBtn.state = config.isShowYApiMock ? .on : .off 62 | } 63 | 64 | private func setupBox() { 65 | tokenBox.removeAllItems() 66 | tokenBox.usesDataSource = false 67 | let historyToken = config.yapiToken 68 | tokens = ConfigCenter.default.config.yapiTokenList // token配置中的 token 69 | let tokensTitle = tokens.map { $0.name } 70 | tokenBox.addItems(withObjectValues: tokensTitle) 71 | 72 | if !historyToken.isEmpty { 73 | if tokens.isEmpty { 74 | tokenBox.stringValue = historyToken 75 | token = historyToken 76 | } else { 77 | let filter = tokens.filter { $0.token == historyToken } 78 | if filter.count > 0 { 79 | tokenBox.selectItem(withObjectValue: filter.first!.name) 80 | token = filter.first!.token 81 | } else { 82 | tokenBox.stringValue = historyToken 83 | token = historyToken 84 | } 85 | } 86 | } 87 | } 88 | 89 | private func tokenForSave() -> String { 90 | let boxValue = tokenBox.stringValue 91 | guard !boxValue.isEmpty else { 92 | return "" 93 | } 94 | // 判断是否为选中的 95 | let filter = tokens.filter { $0.name == boxValue } 96 | if filter.count > 0 { 97 | // 是选中的 98 | return filter.first!.token 99 | } else { 100 | // 填写的 101 | return boxValue 102 | } 103 | } 104 | 105 | @IBAction func guideButtonTap(_ sender: NSButton) { 106 | NSWorkspace.shared.open(URL(string: "https://gitee.com/Sven001/JSONSwfitModel")!) 107 | } 108 | 109 | @IBAction func saveButtonTap(_ sender: NSButton) { 110 | // 111 | config.conform = confromTextField.stringValue 112 | config.module = moduleTextField.stringValue 113 | config.prefix = prefixTextField.stringValue 114 | config.subffix = subffixTextField.stringValue 115 | config.yapiPath = pathTextField.stringValue 116 | config.yapiToken = tokenForSave() 117 | config.yapiHost = yapiHostTextField.stringValue 118 | config.remark = remarkTextField.stringValue 119 | ConfigCenter.default.save() 120 | view.window?.close() 121 | } 122 | 123 | @IBAction func typeOptionalBtnTap(_ sender: NSButton) { 124 | config.isOptional = (sender.state == .on) 125 | configCenter.save() 126 | } 127 | /// 是否为显示可选 128 | @IBAction func isShowOptional(_ sender: NSButton) { 129 | config.isImplicitlyOptional = (sender.state == .on) 130 | configCenter.save() 131 | } 132 | @IBAction func isEmptyArrayBtnTap(_ sender: NSButton) { 133 | config.isArrayDefaultEmpty = (sender.state == .on) 134 | configCenter.save() 135 | } 136 | @IBAction func isShowYApiMockBtnTap(_ sender: NSButton) { 137 | config.isShowYApiMock = sender.state == .on 138 | configCenter.save() 139 | } 140 | @IBAction func importConfig(_ sender: NSButton) { 141 | let panel = OpenSavePanel() 142 | panel.importFile { (error) in 143 | if error == nil { 144 | self.updateFromUserDefault() 145 | } 146 | } 147 | } 148 | @IBAction func exportConfig(_ sender: NSButton) { 149 | let panel = OpenSavePanel() 150 | panel.exportFile { (error) in 151 | print(error ?? "导出失败") 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Controller/TokenViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TokenViewController.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2020/8/20. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | extension Notification.Name { 12 | static let tokenSaved = Notification.Name(rawValue: "tokenSaved") 13 | } 14 | 15 | class TokenViewController: NSViewController { 16 | 17 | @IBOutlet weak var titleTextField: NSTextField! 18 | @IBOutlet weak var tokenTextField: NSTextField! 19 | @IBOutlet weak var stackView: NSStackView! 20 | @IBOutlet weak var tokenContentView: NSView! 21 | private let tokenContentLayer = CALayer() 22 | private let rowHeight: CGFloat = 40 23 | private var dataSource: [YApiTokenModel] = [] 24 | 25 | private var tokenViews: [TokenView] = [] 26 | override func viewDidLoad() { 27 | super.viewDidLoad() 28 | title = "配置 token" 29 | setupView() 30 | setupToken() 31 | } 32 | 33 | override func viewWillLayout() { 34 | super.viewWillLayout() 35 | tokenContentLayer.frame = tokenContentView.bounds 36 | } 37 | 38 | private func setupView() { 39 | tokenContentLayer.borderWidth = 1.0 40 | tokenContentLayer.borderColor = NSColor.lightGray.cgColor 41 | tokenContentLayer.cornerRadius = 10 42 | tokenContentView.layer = tokenContentLayer 43 | } 44 | private func setupToken() { 45 | dataSource = getToken() 46 | for (index, value) in dataSource.enumerated() { 47 | addTokenView(value, at: index) 48 | } 49 | } 50 | 51 | @IBAction func AddButtonTap(_ sender: NSButton) { 52 | addToken() 53 | NotificationCenter.default.post(name: .tokenSaved, object: nil) 54 | } 55 | } 56 | 57 | // MARK: - 数据处理 58 | private extension TokenViewController { 59 | func addToken() { 60 | let title = titleTextField.stringValue 61 | let token = tokenTextField.stringValue 62 | guard !title.isEmpty && !token.isEmpty else { 63 | showAlert() 64 | return 65 | } 66 | let willAddToken = YApiTokenModel(name: title, token: token) 67 | dataSource.append(willAddToken) 68 | updateToken() 69 | addTokenView(willAddToken, at: dataSource.count - 1) 70 | titleTextField.stringValue = "" 71 | tokenTextField.stringValue = "" 72 | } 73 | func addTokenView(_ token: YApiTokenModel, at index: Int) { 74 | let tokenView = TokenView() 75 | tokenView.heightAnchor.constraint(equalToConstant: rowHeight).isActive = true 76 | stackView.addArrangedSubview(tokenView) 77 | tokenView.widthAnchor.constraint(equalTo: stackView.widthAnchor, multiplier: 1).isActive = true 78 | tokenViews.append(tokenView) 79 | tokenView.deleteClosure = { 80 | [weak self] index in 81 | self?.deleteTokenAddView(at: index) 82 | NotificationCenter.default.post(name: .tokenSaved, object: nil) 83 | } 84 | tokenView.buttonTag = index 85 | tokenView.config(token: token) 86 | } 87 | func deleteTokenAddView(at index: Int) -> Void { 88 | dataSource.remove(at: index) 89 | updateToken() 90 | 91 | let willDeleteView = tokenViews[index] 92 | tokenViews.remove(at: index) 93 | stackView.removeArrangedSubview(willDeleteView) 94 | willDeleteView.removeFromSuperview() 95 | // 重置 tag 防止越界 96 | for (index, view) in tokenViews.enumerated() { 97 | view.buttonTag = index 98 | } 99 | 100 | } 101 | 102 | func showAlert() -> Void { 103 | let alert = NSAlert() 104 | alert.messageText = "错误" 105 | alert.informativeText = "项目名和 token不能为空" 106 | alert.alertStyle = .warning 107 | alert.addButton(withTitle: "确定") 108 | alert.beginSheetModal(for: NSApplication.shared.keyWindow!) { (modal) in 109 | 110 | } 111 | 112 | } 113 | } 114 | extension UserDefaults { 115 | enum Key: String { 116 | case tokens 117 | } 118 | } 119 | // MARK: - 数据持久化 120 | private extension TokenViewController { 121 | func updateToken() -> Void { 122 | ConfigCenter.default.config.yapiTokenList = dataSource 123 | ConfigCenter.default.save() 124 | } 125 | 126 | func getToken() -> [YApiTokenModel] { 127 | return ConfigCenter.default.config.yapiTokenList 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Document.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Document.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2020/1/22. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class Document: NSDocument { 12 | 13 | override init() { 14 | super.init() 15 | // Add your subclass-specific initialization here. 16 | } 17 | 18 | override class var autosavesInPlace: Bool { 19 | return true 20 | } 21 | 22 | override func makeWindowControllers() { 23 | // Returns the Storyboard that contains your Document window. 24 | let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil) 25 | let windowController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("Document Window Controller")) as! NSWindowController 26 | self.addWindowController(windowController) 27 | } 28 | 29 | override func data(ofType typeName: String) throws -> Data { 30 | // Insert code here to write your document to data of the specified type, throwing an error in case of failure. 31 | // Alternatively, you could remove this method and override fileWrapper(ofType:), write(to:ofType:), or write(to:ofType:for:originalContentsURL:) instead. 32 | throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil) 33 | } 34 | 35 | override func read(from data: Data, ofType typeName: String) throws { 36 | // Insert code here to read your document from the given data of the specified type, throwing an error in case of failure. 37 | // Alternatively, you could remove this method and override read(from:ofType:) instead. 38 | // If you do, you should also override isEntireFileLoaded to return false if the contents are lazily loaded. 39 | throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil) 40 | } 41 | 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/ErrorCenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ErrorCenter.swift 3 | // SwiftJSONModeler 4 | // 5 | // Created by Sven on 2020/3/16. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Notification.Name { 12 | static let errorNotification = Notification.Name("errorNoti") 13 | } 14 | 15 | class ErrorCenter { 16 | static let shared: ErrorCenter = ErrorCenter() 17 | 18 | var message: String = "" { 19 | didSet { 20 | print(message) 21 | NotificationCenter.default.post(name: .errorNotification, object: nil) 22 | } 23 | } 24 | private init() { 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDocumentTypes 8 | 9 | 10 | CFBundleTypeExtensions 11 | 12 | mydoc 13 | 14 | CFBundleTypeIconFile 15 | 16 | CFBundleTypeName 17 | DocumentType 18 | CFBundleTypeOSTypes 19 | 20 | ???? 21 | 22 | CFBundleTypeRole 23 | Editor 24 | NSDocumentClass 25 | $(PRODUCT_MODULE_NAME).Document 26 | 27 | 28 | CFBundleExecutable 29 | $(EXECUTABLE_NAME) 30 | CFBundleIconFile 31 | 32 | CFBundleIdentifier 33 | $(PRODUCT_BUNDLE_IDENTIFIER) 34 | CFBundleInfoDictionaryVersion 35 | 6.0 36 | CFBundleName 37 | SwiftJSONModeler For Xcode 38 | CFBundlePackageType 39 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 40 | CFBundleShortVersionString 41 | $(MARKETING_VERSION) 42 | CFBundleVersion 43 | $(CURRENT_PROJECT_VERSION) 44 | LSMinimumSystemVersion 45 | $(MACOSX_DEPLOYMENT_TARGET) 46 | NSAppTransportSecurity 47 | 48 | NSAllowsArbitraryLoads 49 | 50 | 51 | NSHumanReadableCopyright 52 | Copyright © 2020 Sven. All rights reserved. 53 | NSMainStoryboardFile 54 | Main 55 | NSPrincipalClass 56 | NSApplication 57 | NSSupportsAutomaticTermination 58 | 59 | NSSupportsSuddenTermination 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/NormalJSON/JSONHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JSONHelper.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2020/8/17. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | /// 将普通josn 转化为 YapiObject 9 | 10 | import Foundation 11 | import OrderJSON 12 | 13 | public class JSONHelper { 14 | /// 复制的文本 15 | var paste: String = "" 16 | private var currentPath: [String] = [] 17 | private var orderJSON: OrderJSON? { 18 | return try? JsonParser.parse(text: paste) 19 | } 20 | init(paste: String) { 21 | self.paste = paste 22 | } 23 | /// 将复制的文本 转化为 YApiObject 对象。 24 | func transform() -> YApiObject? { 25 | do { 26 | let dicJson = try JSONSerialization.jsonObject(with: paste.data(using: .utf8)!, options: .mutableLeaves) 27 | if let dic = dicJson as? [String: Any]{ 28 | return objectOf(dic, key: "") 29 | } else if let arr = dicJson as? [Any] { 30 | return objectOf(arr, key: "") 31 | } else { 32 | return nil 33 | } 34 | } catch let e { 35 | print(e) 36 | ErrorCenter.shared.message = "json 序列化失败,请检查 json 数据" 37 | print(paste) 38 | return nil 39 | 40 | } 41 | } 42 | 43 | /// 字典转对象 44 | /// - Parameter dic: 字典数据 45 | private func objectOf(_ dic: [String: Any], key: String) -> YApiObject { 46 | var childs: [YApiObject] = [] 47 | currentPath.append(key) 48 | let subKeys = orderJSONSubKeysFor(path: currentPath) 49 | if subKeys.isEmpty { 50 | for (label, value) in dic { 51 | let child = typeOf(label, value: value, parentKey: key) 52 | childs.append(child) 53 | } 54 | } else { 55 | for key in subKeys { 56 | if let value = dic[key] { 57 | let child = typeOf(key, value: value, parentKey: key) 58 | childs.append(child) 59 | } 60 | } 61 | } 62 | currentPath.removeLast() 63 | let object = YApiObject(parentKey: nil, key: key, mock: "", type: YApiType.object, typeRaw: "Object", des: "", childs: childs) 64 | return object 65 | } 66 | private func orderJSONSubKeysFor(path current:[String]) -> [String] { 67 | guard let json = orderJSON else { 68 | return [] 69 | } 70 | return json.subKeysFor(keyPath: current) 71 | } 72 | /// 数组转对象 73 | /// - Parameter arry: 数据数组 74 | private func objectOf(_ arry: [Any], key:String) -> YApiObject { 75 | let type = YApiType.array 76 | guard let first = arry.first else { 77 | //ErrorCenter.shared.message = "json 序列化 数组第一个元素类型判断异常" 78 | let childType = YApiType.undefined 79 | let objct = YApiObject(parentKey: key, key: key, mock: "", type: childType, typeRaw: "<#Undefined#>", des: nil, childs: []) 80 | let arrObjct = YApiObject(parentKey: key, key: key, mock: "", type: type, typeRaw: "Array", des: nil, childs: [objct]) 81 | return arrObjct 82 | } 83 | let arrObjct = YApiObject(parentKey: key, key: key, mock: "", type: type, typeRaw: "Array", des: nil, childs: [typeOf(key, value: first)]) 84 | return arrObjct 85 | } 86 | /// 类型数据类型判断 87 | /// - Parameter value: 值 88 | private func typeOf(_ key: String?, value: Any, parentKey: String? = nil) -> YApiObject { 89 | if value is NSNull { 90 | print("存在null") 91 | let type = YApiType.undefined 92 | let objct = YApiObject(parentKey: parentKey, key: key, mock: "", type: type, typeRaw: "NSNull", des: nil, childs: []) 93 | return objct 94 | } else if value is String { 95 | let type = YApiType.string 96 | let objct = YApiObject(parentKey: parentKey, key: key, mock: "", type: type, typeRaw: "String", des: nil, childs: []) 97 | return objct 98 | } else if value is Int { 99 | let type = YApiType.integer 100 | let objct = YApiObject(parentKey: parentKey, key: key, mock: "", type: type, typeRaw: "Int", des: nil, childs: []) 101 | return objct 102 | } else if value is Double { 103 | let type = YApiType.number 104 | let objct = YApiObject(parentKey: parentKey, key: key, mock: "", type: type, typeRaw: "Double", des: nil, childs: []) 105 | return objct 106 | } else if value is Bool { 107 | let type = YApiType.boolean 108 | let objct = YApiObject(parentKey: parentKey, key: key, mock: "", type: type, typeRaw: "Bool", des: nil, childs: []) 109 | return objct 110 | } else if let arr = value as? [Any] { 111 | return objectOf(arr, key: key ?? "") 112 | } else if let dic = value as? [String: Any]{ 113 | return objectOf(dic, key: key ?? "") 114 | } else { 115 | ErrorCenter.shared.message = "json 格式异常,无法解析为 model" 116 | return YApiObject() 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/NormalJSON/OrderJSON+NormalJSON.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OrderJSON+NormalJSON.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2021/4/28. 6 | // Copyright © 2021 Sven. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/SwiftJSONModeler For Xcode.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.application-groups 8 | 9 | SwiftJSONModeler 10 | 11 | com.apple.security.files.user-selected.read-write 12 | 13 | com.apple.security.network.client 14 | 15 | com.apple.security.network.server 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/Utils/OpenSavePanel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OpenSavePanel.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2021/2/7. 6 | // Copyright © 2021 Sven. All rights reserved. 7 | // 8 | /// 文件导入和导出 9 | 10 | import AppKit 11 | import CleanJSON 12 | 13 | struct OpenSavePanel { 14 | /// 导入文件 15 | func importFile(completion: @escaping (_ error: Error?) -> Void) -> Void { 16 | let panel = NSOpenPanel() 17 | panel.prompt = "确定" 18 | panel.message = "选择配置" 19 | panel.canChooseDirectories = false 20 | panel.canCreateDirectories = false 21 | panel.allowedFileTypes = ["plist"] 22 | panel.allowsMultipleSelection = false 23 | //panel.directoryURL = 24 | panel.beginSheetModal(for: NSApp.mainWindow ?? NSWindow() ) { (response) in 25 | if response == .OK { 26 | if let url = panel.url { 27 | let isSuccess = read(url: url) 28 | let error = NSError(domain: "swiftjsonmodeler.error", code: 5000, userInfo: [NSLocalizedDescriptionKey: "导入保存失败"]) 29 | completion(isSuccess ? nil : error ) 30 | } else { 31 | let error = NSError(domain: "swiftjsonmodeler.error", code: 5000, userInfo: [NSLocalizedDescriptionKey: "导入文件 url不存在"]) 32 | completion(error) 33 | } 34 | 35 | } else { 36 | //取消 37 | completion(NSError(domain: "swiftjsonmodeler.error", code: 5000, userInfo: [NSLocalizedDescriptionKey: "取消选择"])) 38 | } 39 | } 40 | } 41 | 42 | /// 导出文件 43 | func exportFile(completion: @escaping (_ error: Error?) -> Void) -> Void { 44 | let savePanel = NSSavePanel() 45 | savePanel.nameFieldStringValue = "Config.plist" 46 | savePanel.message = "请选择路径保存配置" 47 | savePanel.allowedFileTypes = ["plist"] 48 | savePanel.isExtensionHidden = false 49 | savePanel.canCreateDirectories = true 50 | //savePanel.directoryURL = 51 | savePanel.beginSheetModal(for: NSApp.mainWindow ?? NSWindow()) { (response) in 52 | if response == .OK { 53 | if let path = savePanel.url { 54 | let isSuccess = saveFile(url: path) 55 | let error = NSError(domain: "swiftjsonmodeler.error", code: 5000, userInfo: [NSLocalizedDescriptionKey: "导入保存失败"]) 56 | completion(isSuccess ? nil : error ) 57 | } else { 58 | completion(NSError(domain: "swiftjsonmodeler.error", code: 5000, userInfo: [NSLocalizedDescriptionKey: "导入文件 url不存在"])) 59 | } 60 | } else { 61 | completion(NSError(domain: "swiftjsonmodeler.error", code: 5000, userInfo: [NSLocalizedDescriptionKey: "取消选择"])) 62 | } 63 | } 64 | } 65 | /// 导入保存 66 | private func read(url: URL) -> Bool { 67 | let configCenter = ConfigCenter.default 68 | guard let dic = NSDictionary(contentsOfFile:url.path), JSONSerialization.isValidJSONObject(dic) else { 69 | return false 70 | } 71 | guard let dicData = try? JSONSerialization.data(withJSONObject: dic, options: .fragmentsAllowed) else { 72 | return false 73 | } 74 | 75 | let decoder = CleanJSONDecoder() 76 | guard let model = try? decoder.decode(ConfigModel.self, from: dicData) else { 77 | return false 78 | } 79 | configCenter.config = model 80 | return configCenter.save() 81 | } 82 | 83 | /// 导出保存文件 84 | func saveFile( url: URL) -> Bool { 85 | let fileManager = FileManager.default 86 | let contents = fileManager.contents(atPath: configPath) 87 | let isSuccess = fileManager.createFile(atPath: url.path, contents: contents, attributes: [FileAttributeKey.appendOnly : false, FileAttributeKey.extensionHidden: false]) 88 | if isSuccess { 89 | print("保存成功") 90 | } else { 91 | print("保存失败") 92 | } 93 | return isSuccess 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/View/TokenView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TokenView.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2020/8/20. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class TokenView: NSView { 12 | 13 | var buttonTag: Int { 14 | set { 15 | deleteButton.tag = newValue 16 | } get { 17 | return deleteButton.tag 18 | } 19 | } 20 | 21 | var deleteClosure: (_ index: Int) -> Void = { _ in } 22 | 23 | @IBOutlet weak var titleLabel: NSTextField! 24 | @IBOutlet private var contentView: NSView! 25 | @IBOutlet weak var tokenLabel: NSTextField! 26 | @IBOutlet private weak var deleteButton: NSButton! 27 | override init(frame frameRect: NSRect) { 28 | super.init(frame: frameRect) 29 | commonInit() 30 | } 31 | required init?(coder: NSCoder) { 32 | super.init(coder: coder) 33 | commonInit() 34 | } 35 | 36 | override func draw(_ dirtyRect: NSRect) { 37 | super.draw(dirtyRect) 38 | } 39 | 40 | override func layout() { 41 | super.layout() 42 | contentView.frame = bounds 43 | } 44 | 45 | private func commonInit() { 46 | NSNib(nibNamed: "TokenView", bundle: nil)!.instantiate(withOwner: self, topLevelObjects: nil) 47 | addSubview(contentView) 48 | contentView.layer?.backgroundColor = NSColor.orange.cgColor 49 | contentView.frame = bounds 50 | deleteButton.attributedTitle = NSAttributedString(string: "删除", attributes: [NSAttributedString.Key.foregroundColor : NSColor.red]) 51 | } 52 | 53 | func config(token: YApiTokenModel) -> Void { 54 | tokenLabel.stringValue = token.token 55 | titleLabel.stringValue = token.name 56 | } 57 | 58 | @IBAction func deleteButtonTap(_ sender: NSButton) { 59 | deleteClosure(sender.tag) 60 | } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/View/TokenView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 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 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // JSONSwiftModelApp 4 | // 5 | // Created by Sven on 2020/1/22. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class ConfigViewController: 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 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/YApi/OrderJSON+YApi/OrderJSON+Yapi.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OrderJSON+Yapi.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2021/4/27. 6 | // Copyright © 2021 Sven. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import OrderJSON 11 | 12 | 13 | func logError(_ msg: String = "错误", functionName: String = #function){ 14 | print("") 15 | print(#line,functionName,#fileID) 16 | print("_____Error:\(msg)") 17 | } 18 | /// 解析出 YApi 路径某个路径下的子 key 19 | public extension OrderJSON { 20 | /// 返回YApi Raw json中当前 key 的子键数组(具有顺序) 21 | /// 22 | /// 原理,由于 Yapi json 类型为`object`字段和格式一致。 23 | func yapiSubKeysFor(keyPath: [String]) -> [String] { 24 | let tempPath = keyPath.filter{ $0 != ""} 25 | guard case .object(_) = self else { 26 | return [] 27 | } 28 | guard !tempPath.isEmpty else { 29 | return searchKeysIn(self) 30 | } 31 | let paths = tempPath //: [String] = keyPath.components(separatedBy: ".") 32 | return keysFor(paths: paths, in: self) 33 | } 34 | 35 | private func keysFor(paths: [String], in json: OrderJSON) -> [String] { 36 | guard !paths.isEmpty else { 37 | logError("异常错误,请检查") 38 | return [] // 应该永远不会发生 39 | } 40 | let currentKey = paths.first! 41 | let nextPaths = Array(paths.dropFirst()) 42 | guard let currentOrderJSON = searchJSONFor(key: currentKey, in: json) else { 43 | logError("找不到key=\(currentKey)的 OrderJSON 对象") 44 | return [] 45 | } 46 | if nextPaths.isEmpty { 47 | // 结束 48 | return searchKeysIn(currentOrderJSON) 49 | } else { 50 | return keysFor(paths: nextPaths, in: currentOrderJSON) 51 | } 52 | } 53 | 54 | private func searchJSONFor(key: String, in json: OrderJSON) -> OrderJSON? { 55 | guard case .object(let objc) = json else { 56 | logError("\(key)不是JSON.object类型") 57 | return nil 58 | } 59 | guard let properties = orderJSONFor(key: YApiKeys.properties.rawValue, in: objc) else { 60 | logError("\(key)的 properties 字段不存在") 61 | return nil 62 | } 63 | guard case .object(let aim) = properties else { 64 | logError("\(key)下 properties不是JSON.object类型") 65 | return nil 66 | } 67 | guard let keyObject = orderJSONFor(key: key, in: aim) else { 68 | logError("\(key)下 properties 不存在该OrderJSON对象") 69 | return nil 70 | } 71 | return keyObject 72 | } 73 | private func searchKeysIn(_ json: OrderJSON) -> [String] { 74 | if case .object(let subKeys) = json { 75 | if let type = orderJSONFor(key: YApiKeys.type.rawValue, in: subKeys), case .string(let typeValue) = type, typeValue == "array" { 76 | // 该 key 为数组 77 | return searchKeysForArray(json) 78 | } 79 | return searchKeysForObject(subKeys) 80 | } 81 | return [] 82 | 83 | } 84 | /// 取object 类型的 keys 85 | private func searchKeysForObject(_ json: [[String: OrderJSON]]) -> [String] { 86 | guard let properties = orderJSONFor(key: YApiKeys.properties.rawValue, in: json) else { 87 | return [] 88 | } 89 | guard case .object(let aim) = properties else { 90 | return [] 91 | } 92 | var keys: [String] = [] 93 | aim.forEach { (value) in 94 | keys.append(value.keys.first!) 95 | } 96 | return keys 97 | } 98 | /// 取 array 类型下为 object 的 keys 99 | private func searchKeysForArray(_ json: OrderJSON) -> [String] { 100 | guard case .object(let arrayObjects) = json else { 101 | return [] 102 | } 103 | guard let items = orderJSONFor(key: "items", in: arrayObjects) else { 104 | return [] 105 | } 106 | guard case .object(let itemObj) = items else { 107 | return [] 108 | } 109 | guard let properties = orderJSONFor(key: YApiKeys.properties.rawValue, in: itemObj) else { 110 | return [] 111 | } 112 | guard case .object(let aim) = properties else { 113 | return [] 114 | } 115 | var keys: [String] = [] 116 | aim.forEach { (value) in 117 | keys.append(value.keys.first!) 118 | } 119 | return keys 120 | } 121 | 122 | private func orderJSONFor(key: String, in arr:[[String: OrderJSON]]) -> OrderJSON? { 123 | return arr.first(where: {$0.first!.key == key })?.first?.value 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/YApi/YApiCreator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // YApiCreator.swift 3 | // SwiftJSONModeler 4 | // 5 | // Created by Sven on 2020/3/25. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | import XcodeKit 11 | 12 | extension String { 13 | func upperCaseFirst() -> String { 14 | let temp = self 15 | guard !self.isEmpty else { 16 | return temp 17 | } 18 | let firstIndex = temp.startIndex 19 | let replaceEndIndex = temp.index(after: startIndex) 20 | let firstLetter = temp.prefix(1) 21 | let upper = firstLetter.uppercased() 22 | let new = temp.replacingCharacters(in: firstIndex.. = [] 38 | /// 只包含对象的行,不包含个struct或class关键字 39 | private var objectLines: [(yapiObject:YApiObject, lines:[String])] = [] 40 | init(invocation: XCSourceEditorCommandInvocation, pasteText: String) { 41 | self.invocation = invocation 42 | self.pasteText = pasteText 43 | let buffer = invocation.buffer 44 | lines = buffer.lines 45 | objectHelper = YApiHelper(paste: pasteText) 46 | getPathObject() 47 | } 48 | 49 | init(invocation: XCSourceEditorCommandInvocation, yapiObject: YApiObject) { 50 | self.invocation = invocation 51 | self.creatObjects.insert(yapiObject) 52 | let buffer = invocation.buffer 53 | lines = buffer.lines 54 | lineObject(self.creatObjects.first!) 55 | } 56 | 57 | private func getPathObject() -> Void { 58 | objectHelper.aimPath = ConfigCenter.default.config.yapiPath //设置获取data下数据 59 | guard let object = objectHelper.pathObject else { 60 | return 61 | } 62 | creatObjects.insert(object) 63 | lineObject(self.creatObjects.first!) 64 | } 65 | 66 | private func lineObject(_ object: YApiObject) -> Void { 67 | var aimObject: YApiObject = object 68 | 69 | if object.type! == .object { 70 | aimObject = object 71 | }else if object.type! == .array { 72 | if let firstOb = object.childs.first, firstOb.type! == .object { 73 | aimObject = firstOb 74 | }else { 75 | return 76 | } 77 | }else { 78 | errorCenter.message = "\(#function)对象类型异常" 79 | return 80 | } 81 | var objectLines: [String] = [] 82 | for child in aimObject.childs { 83 | if let line = lineRow(from: child) { 84 | objectLines.append(contentsOf: line) 85 | } 86 | } 87 | self.objectLines.append((object,objectLines)) 88 | self.creatObjects.remove(object) 89 | if self.creatObjects.count != 0 { 90 | lineObject(self.creatObjects.first!) 91 | } 92 | } 93 | /// 返回注释和每个对象的行内容(处理非 array 和 object类型) 94 | private func lineRow(from object: YApiObject) -> [String]? { 95 | let type = object.type! 96 | var swiftType = type.swiftType() 97 | switch type { 98 | case .array: 99 | if let subObject = object.childs.first { 100 | let subObjectType = subObject.type! 101 | if subObjectType == .object { 102 | creatObjects.insert(subObject) 103 | if let temp = subObject.key?.upperCaseFirst() { 104 | swiftType = "[\(config.prefix + temp + config.subffix)]" 105 | } else { 106 | swiftType = "<#Undefined#>" 107 | } 108 | } else { 109 | swiftType = "[\(subObjectType.swiftType())]" 110 | } 111 | } else { 112 | return nil 113 | } 114 | case .object: 115 | creatObjects.insert(object) 116 | swiftType = object.key!.upperCaseFirst() 117 | swiftType = config.prefix + swiftType + config.subffix 118 | case .integer, .string, .number, .boolean, .undefined: 119 | break 120 | } 121 | 122 | isShowMock = config.isShowYApiMock 123 | var comment = "" 124 | if let objectDes = object.des { 125 | comment = "/// \(objectDes)\(isShowMock && !object.mock.isEmpty ? "\tMock:\(object.mock)" : "")" 126 | } 127 | if swiftType == "<#Undefined#>" { 128 | swiftType = "<#\(object.typeRaw)#>" 129 | } 130 | var line = "var \(object.key!): \(swiftType)" 131 | let isOptional = config.isOptional 132 | let isStringdefaultEmpty = config.isStringDefaultEmpty 133 | if isOptional { 134 | if type == .array, config.isArrayDefaultEmpty { 135 | line.append(contentsOf: " = []") 136 | } else if type == .string, isStringdefaultEmpty { 137 | line.append(contentsOf: #" = """#) 138 | } else { 139 | let optionalStr = config.isImplicitlyOptional ? "!" : "?" 140 | line.append(contentsOf: optionalStr) 141 | } 142 | } else { 143 | if type == .array, config.isArrayDefaultEmpty { 144 | line.append(contentsOf: " = []") 145 | } 146 | if type == .string, isStringdefaultEmpty { 147 | line.append(contentsOf: #" = """#) 148 | } 149 | } 150 | 151 | 152 | return [comment,line] 153 | } 154 | func getModels() -> [String] { 155 | var models: [String] = [] 156 | for object in objectLines { 157 | models.append(contentsOf: model(commandIdentifier: invocation.commandIdentifier, yapiObject: object.yapiObject, yapiLines: object.lines)) 158 | } 159 | return models 160 | } 161 | /// 获取完整模型定义 162 | private func model(commandIdentifier: CommandId, yapiObject: YApiObject, yapiLines: [String]) -> [String] { 163 | var name: String = "<#Model#>" 164 | if yapiObject.key != nil { 165 | name = yapiObject.key!.upperCaseFirst() 166 | } 167 | let des: String = yapiObject.des ?? "" 168 | var keyword = keyStruct 169 | if commandIdentifier.contains(keyStruct) { 170 | keyword = keyStruct 171 | } else if commandIdentifier.contains(keyClass) { 172 | keyword = keyClass 173 | } 174 | name = config.prefix + name + config.subffix 175 | let parent = config.parent 176 | var objctLines: [String] = [] 177 | if !des.isEmpty { 178 | objctLines.append("/// \(des)") 179 | } 180 | if parent.isEmpty { 181 | objctLines.append("\(keyword) \(name) {") 182 | } else { 183 | objctLines.append("\(keyword) \(name): \(parent) {") 184 | } 185 | let lines = yapiLines.map{ "\t\($0)" } 186 | objctLines.append(contentsOf: lines) 187 | if keyword == keyClass , parent.contains("HandyJSON") { 188 | objctLines.append("") 189 | objctLines.append("\trequired init() { }") 190 | } 191 | objctLines.append("}") 192 | objctLines.append("\n") 193 | return objctLines 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/YApi/YApiHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // YApiHelper.swift 3 | // SwiftJSONModeler 4 | // 5 | // Created by Sven on 2020/3/16. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import OrderJSON 11 | 12 | enum YApiKeys: String { 13 | case type 14 | case properties 15 | case des = "description" 16 | } 17 | 18 | /// 将Yapi RAW数据解析为目标YApiObject 19 | class YApiHelper { 20 | private var pasteJSON: String 21 | var pathObject: YApiObject? { 22 | return pathObjectTransform() 23 | } 24 | 25 | /// 按照path解析 `""`表示最外层, 默认值 26 | var aimPath: String = "" 27 | 28 | private lazy var originJOSN: [String: Any]? = { 29 | transformToDic() 30 | }() 31 | 32 | private lazy var customJSON: OrderJSON? = { 33 | try? JsonParser.parse(text: pasteJSON) 34 | }() 35 | 36 | /// 用于 OrderJOSN key 寻找的 37 | private var currentPath: [String] = [] 38 | 39 | init(paste: String) { 40 | self.pasteJSON = paste 41 | } 42 | 43 | private func getPathObjects(path: String, from object: YApiObject) -> YApiObject? { 44 | guard !path.isEmpty else { 45 | return object 46 | } 47 | let pathArr = path.components(separatedBy: ".") 48 | 49 | func searchObject(key: String, in object: YApiObject) -> YApiObject? { 50 | if object.key == key { 51 | return object 52 | } else { 53 | var subObjec: YApiObject? 54 | for child in object.childs { 55 | if let sub = searchObject(key: key, in: child) { 56 | subObjec = sub 57 | } 58 | } 59 | return subObjec 60 | } 61 | } 62 | var search = object 63 | for path in pathArr { 64 | if let aimObject = searchObject(key: path, in: search) { 65 | search = aimObject 66 | } else { 67 | ErrorCenter.shared.message = "寻找\(path)目标失败" 68 | return nil 69 | } 70 | } 71 | return search 72 | } 73 | 74 | // type 类型 如果不含type则为完整模型 75 | private func apiType(of dic: [String: Any]) -> YApiType? { 76 | guard let typeStr = dic["type"] as? String else { 77 | return nil 78 | } 79 | return YApiType.of(typeStr) 80 | } 81 | 82 | private func objectsOf(key parent: String, properties: [String: Any]) -> [YApiObject] { 83 | currentPath.append(parent) 84 | print("当前路径:\(currentPath)") 85 | let subKeys = customJSON?.yapiSubKeysFor(keyPath: currentPath) ?? [] 86 | print("子健:\(subKeys)") 87 | var objectArr: [YApiObject] = [] 88 | if subKeys.isEmpty { 89 | logError("无法通过 OrderJSON 解析获取 subkey") 90 | print("\(pasteJSON)") 91 | // 直接解析 92 | for item in properties { 93 | if let value = item.value as? [String: Any] { 94 | if let object = self.object(key: item.key, json: value) { 95 | var temp = object 96 | temp.parentKey = parent 97 | objectArr.append(temp) 98 | } 99 | } else { 100 | ErrorCenter.shared.message = "存在不确定类型\(parent)" 101 | } 102 | } 103 | } else { 104 | // 使用与 json key 顺序一致解析 105 | for key in subKeys { 106 | if let value = properties[key] as? [String: Any] { 107 | if let object = self.object(key: key, json: value) { 108 | var temp = object 109 | temp.parentKey = parent 110 | objectArr.append(temp) 111 | } 112 | } else { 113 | ErrorCenter.shared.message = "存在不确定类型\(parent)" 114 | } 115 | } 116 | } 117 | currentPath.removeLast() 118 | return objectArr 119 | } 120 | 121 | /// 获取某一具体类型的对象 122 | private func object(key: String = "", json: [String: Any]) -> YApiObject? { 123 | guard let type = apiType(of: json) else { 124 | ErrorCenter.shared.message = "key数据格式异常\n:\(json)" 125 | return nil 126 | } 127 | var object = YApiObject() 128 | object.key = key 129 | object.type = type 130 | object.typeRaw = ((json["type"] as? String) ?? "") 131 | switch type { 132 | case .object: 133 | if let properties = json["properties"] as? [String: Any] { 134 | object.childs = self.objectsOf(key: key, properties: properties) 135 | } else { 136 | ErrorCenter.shared.message = "json 对象\(key) properties异常" 137 | return nil 138 | } 139 | 140 | case .array: 141 | if let items = json["items"] as? [String: Any], let type = items["type"] as? String { 142 | object.des = json["description"] as? String ?? "" 143 | let apiType = YApiType.of(type) 144 | if apiType == .object { 145 | if let arrObject = self.object(key: key, json: items) { 146 | object.childs = [arrObject] 147 | } else { 148 | object.childs = [] 149 | } 150 | } else { 151 | let childs = self.object(json: items) 152 | object.childs = childs == nil ? [] : [childs!] 153 | } 154 | } else { 155 | ErrorCenter.shared.message = "数组\(key)异常,可能不存在items或type" 156 | return nil 157 | } 158 | case .integer, .boolean, .string, .number, .undefined: 159 | if let mockJson = json["mock"] as? [String: Any], let mock = mockJson["mock"] as? String { 160 | object.mock = mock 161 | } 162 | } 163 | if let des = json["description"] as? String { 164 | object.des = des 165 | } 166 | return object 167 | } 168 | } 169 | 170 | // MARK: - Get 171 | 172 | extension YApiHelper { 173 | /// 从 174 | private func transformToDic() -> [String: Any]? { 175 | let paste = pasteJSON 176 | guard let data = paste.data(using: .utf8) else { 177 | ErrorCenter.shared.message = "string 转换 data 异常" 178 | return nil 179 | } 180 | 181 | // 使用系统解析 182 | guard let jsonObject = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) else { 183 | ErrorCenter.shared.message = "json 序列化异常" 184 | return nil 185 | } 186 | 187 | guard let jsonDic = jsonObject as? [String: Any] else { 188 | ErrorCenter.shared.message = "json 转为字典失败" 189 | return nil 190 | } 191 | return jsonDic 192 | } 193 | 194 | /// 获取目标路径下的 YapiOject 195 | private func pathObjectTransform() -> YApiObject? { 196 | guard let dic = originJOSN else { 197 | return nil 198 | } 199 | var apiObj: YApiObject? 200 | if apiType(of: dic) != nil { 201 | apiObj = object(json: dic) 202 | } else { 203 | var ob = YApiObject() 204 | ob.childs = objectsOf(key: "", properties: dic) 205 | ob.type = .object 206 | ob.typeRaw = "object" 207 | apiObj = ob 208 | } 209 | guard let object = apiObj else { 210 | return nil 211 | } 212 | return getPathObjects(path: aimPath, from: object) 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/YApi/YApiObject.swift: -------------------------------------------------------------------------------- 1 | // 2 | // YApiObject.swift 3 | // SwiftJSONModeler 4 | // 5 | // Created by Sven on 2020/3/16. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | // 可能存在的YApi类型,通过插件导入的 11 | private let keyJavaDouble = "double" 12 | private let keyJavaFloat = "float" 13 | private let keyJavaLong = "long" 14 | private let keyJavaInt = "int" 15 | /// YApi标准数据类型 16 | /// - Important: 请务必使用类方法 of()进行类型初始化 17 | enum YApiType: String { 18 | case object = "object" 19 | case array = "array" 20 | case integer = "integer" 21 | case boolean = "boolean" 22 | case string = "string" 23 | case number = "number" 24 | case undefined 25 | /// 对于Swift基本类型。object和arry为Undefined 则需要自行构造 26 | func swiftType() -> String { 27 | switch self { 28 | case .integer: 29 | return "Int" 30 | case .boolean: 31 | return "Bool" 32 | case .string: 33 | return "String" 34 | case .number: 35 | return "Double" 36 | case .undefined: 37 | return "<#Undefined#>" 38 | default: 39 | return "<#Undefined#>" 40 | } 41 | } 42 | /// 规范化 yapi 类型 43 | static func of(_ string: String) -> Self { 44 | let lowerStr = string.lowercased() // 由于java存在基本数据类型和对象类型。 45 | if let apiType = YApiType(rawValue: lowerStr) { 46 | return apiType 47 | } else { 48 | switch lowerStr { 49 | case keyJavaLong: 50 | return .integer 51 | case keyJavaFloat, keyJavaDouble: 52 | return .number 53 | case keyJavaInt: 54 | return .integer 55 | default: 56 | return .undefined 57 | } 58 | } 59 | } 60 | } 61 | struct YApiObject: Hashable { 62 | func hash(into hasher: inout Hasher) { 63 | hasher.combine(key) 64 | } 65 | // static func == (lhs: YApiObject, rhs: YApiObject) -> Bool { 66 | // return lhs.key == rhs.key && lhs.parentKey == rhs.parentKey && lhs.des == rhs.des 67 | // } 68 | 69 | /// 只有当type为object时提供 70 | var parentKey: String? 71 | var key: String! 72 | var mock: String = "" 73 | var type: YApiType! 74 | /// 原始 类型 75 | var typeRaw: String = "" 76 | var des: String? 77 | var childs: [YApiObject] = [] 78 | 79 | 80 | } 81 | -------------------------------------------------------------------------------- /SwiftJSONModeler For Xcode/YApi/YApiRequest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // YApiRequest.swift 3 | // SwiftJSONModeler 4 | // 5 | // Created by Sven on 2020/3/28. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | private let path = "/api/interface/get" 13 | 14 | extension String { 15 | fileprivate func isPurnInt() -> Bool { 16 | let scan: Scanner = Scanner(string: self) 17 | var value: Int = 0 18 | return scan.scanInt(&value) && scan.isAtEnd 19 | } 20 | } 21 | 22 | class YApiRequest { 23 | private static let errorCenter = ErrorCenter.shared 24 | private static var config: ConfigModel { return ConfigCenter.default.latest() }// 25 | private static func isAvailable(id: String) -> Bool { 26 | guard !id.isEmpty else { 27 | errorCenter.message = "YApi接口id不能为空" 28 | return false 29 | } 30 | guard id.isPurnInt() else { 31 | errorCenter.message = "YApi接口id格式异常" 32 | return false 33 | } 34 | guard !config.yapiToken.isEmpty else { 35 | errorCenter.message = "YApi项目token为空,请前往设置填写YApi项目token" 36 | return false 37 | } 38 | guard !config.yapiHost.isEmpty else { 39 | errorCenter.message = "YApi项目host为空,请前往设置填写YApi项目host" 40 | return false 41 | } 42 | return true 43 | } 44 | static func data(id: String, comple: @escaping (String?) -> Void){ 45 | let token = config.yapiToken 46 | let host = config.yapiHost 47 | guard isAvailable(id: id) else { 48 | comple(nil) 49 | return 50 | } 51 | data(id: id, token: token, host: host, comple: comple) 52 | } 53 | 54 | static func data(id: String, token: String, host: String, comple: @escaping (String?) -> Void){ 55 | let url = host + path + "?token=\(token)&id=\(id)" 56 | var request = URLRequest(url: URL(string: url)!, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 30) 57 | request.httpMethod = "GET" 58 | request.setValue("application/json", forHTTPHeaderField: "Content-Type") 59 | print(request) 60 | let session = URLSession(configuration: .default) 61 | let task = session.dataTask(with: request) { (data, response, error) in 62 | if error != nil { 63 | print(error!) 64 | errorCenter.message = "获取YApi接口数据失败" 65 | comple(nil) 66 | }else { 67 | 68 | comple(handleData(data!)) 69 | } 70 | } 71 | task.resume() 72 | } 73 | 74 | private static func handleData(_ data: Data) -> String?{ 75 | let dataStr = String(data: data, encoding: .utf8) 76 | print("____dataStr") 77 | print(dataStr ?? "") 78 | guard let json = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] else { 79 | errorCenter.message = "获取数据 json 解析异常" 80 | return nil 81 | } 82 | guard let code = json["errcode"] as? Int, code == 0, let dataDic = json["data"] as? [String: Any], let resBody = dataDic["res_body"] as? String else { 83 | var error = "获取接口数据异常" 84 | if let message = json["errmsg"] as? String { 85 | error = message 86 | } 87 | errorCenter.message = error 88 | return nil 89 | } 90 | let raw = resBody.replacingOccurrences(of: #"\""#, with: "\"") 91 | print("_____RAW\(raw)") 92 | return raw 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /SwiftJSONModeler For XcodeTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /SwiftJSONModeler For XcodeTests/SwiftJSONModelerTest/JSONHelperTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JSONHelperTest.swift 3 | // SwiftJSONModeler For XcodeTests 4 | // 5 | // Created by Sven on 2020/8/17. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import SwiftJSONModeler_For_Xcode 11 | 12 | class JSONHelperTest: XCTestCase { 13 | private let multiJson = 14 | """ 15 | { 16 | "title": "第一层 json", 17 | "stringValue": "字符串值", 18 | "intValue": 58, 19 | "doubleValue": 18.2, 20 | "nullValue": null, 21 | "boolValue": true, 22 | "subJson": { 23 | "title": "第二层 json", 24 | "stringValue": "字符串值" 25 | }, 26 | "arrayValue1": [ 27 | "value1", 28 | "value2", 29 | "value3" 30 | ], 31 | "arrayValue2": [{ 32 | "title": "数组包含子 json", 33 | "intValue": 12, 34 | "boolValue": false 35 | }] 36 | } 37 | """ 38 | override func setUpWithError() throws { 39 | // Put setup code here. This method is called before the invocation of each test method in the class. 40 | } 41 | 42 | override func tearDownWithError() throws { 43 | // Put teardown code here. This method is called after the invocation of each test method in the class. 44 | } 45 | 46 | func testExample() throws { 47 | // This is an example of a functional test case. 48 | // Use XCTAssert and related functions to verify your tests produce the correct results. 49 | } 50 | 51 | func testPerformanceExample() throws { 52 | // This is an example of a performance test case. 53 | self.measure { 54 | // Put the code you want to measure the time of here. 55 | } 56 | } 57 | 58 | /// 测试异常 json 格式 59 | func testAbnormalJSON() -> Void { 60 | let json = """ 61 | { 62 | "title": "这不是一个正确的 json", 63 | "property1": "第一个属性" // 不加逗号 64 | property: "" // 没用引号 65 | } 66 | """ 67 | let helper = JSONHelper(paste: json) 68 | let object = helper.transform() 69 | XCTAssertNil(object) 70 | } 71 | 72 | /// 测试 第一层为数组 json 73 | func testArrayJSON() { 74 | let json = 75 | """ 76 | [ 77 | "value1", 78 | "value2", 79 | "value3" 80 | ] 81 | """ 82 | let helper = JSONHelper(paste: json) 83 | let object = helper.transform() 84 | XCTAssertNotNil(object) 85 | XCTAssert(object!.childs.first!.type == YApiType.string, "数组类型应该为 String") 86 | } 87 | 88 | /// 测试 数组为空情况 89 | func testEmptyArray() { 90 | let json = 91 | """ 92 | { 93 | "title": "空数组", 94 | "emptyArray": [] 95 | } 96 | """ 97 | let helper = JSONHelper(paste: json) 98 | let object = helper.transform() 99 | XCTAssertNotNil(object) 100 | XCTAssert(object!.childs.filter { $0.key == "emptyArray" }.first!.childs.first!.type == YApiType.undefined, "数组类型应该为 Undefined") 101 | } 102 | 103 | /// 测试 单层 接送 104 | func testSingleJSON() -> Void { 105 | let json = 106 | """ 107 | { 108 | "title": "第一层 json", 109 | "stringValue": "字符串值", 110 | "intValue": 58, 111 | "doubleValue": 18.2, 112 | "nullValue": null, 113 | "boolValue": true 114 | } 115 | """ 116 | let helper = JSONHelper(paste: json) 117 | let object = helper.transform() 118 | XCTAssertNotNil(object) 119 | let objc = object! 120 | 121 | XCTAssertNotNil(objc.childs.filter { $0.key == "stringValue" }.first) 122 | XCTAssertNotNil(objc.childs.filter { $0.key == "intValue" }.first) 123 | XCTAssertNotNil(objc.childs.filter { $0.key == "boolValue" }.first) 124 | XCTAssertNotNil(objc.childs.filter { $0.key == "nullValue" }.first) 125 | XCTAssertNotNil(objc.childs.filter { $0.key == "doubleValue" }.first) 126 | 127 | } 128 | 129 | /// 测试多层嵌套 json 130 | func testMultiLevelJSON() -> Void { 131 | let json = multiJson 132 | 133 | let helper = JSONHelper(paste: json) 134 | let transformObject = helper.transform() 135 | XCTAssertNotNil(transformObject) 136 | guard let object = transformObject else { 137 | return 138 | } 139 | let subJsonArr = object.childs.filter{ $0.key == "subJson" } 140 | XCTAssertNotNil(subJsonArr.first) 141 | guard let subJson = subJsonArr.first else { 142 | return 143 | } 144 | XCTAssert(subJson.childs.count == 2, "subJson 属性数量为2") 145 | XCTAssert(object.childs.filter { $0.key == "arrayValue1" }.first!.childs.first!.type == YApiType.string, "arrayValue1 数组类型应该为 String") 146 | XCTAssert(object.childs.filter { $0.key == "arrayValue2" }.first!.childs.first!.type == YApiType.object, "arrayValue2 数组类型应该为 object") 147 | 148 | // key 顺序测试 149 | let orderKeys = ["title", "stringValue", "intValue", "doubleValue", "nullValue", "boolValue", "arrayValue1", "arrayValue2"] 150 | 151 | let currentKeys = object.childs.compactMap {$0.parentKey} 152 | XCTAssertTrue(orderKeys == currentKeys, "json key 顺序应该一致") 153 | 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /SwiftJSONModeler For XcodeTests/SwiftJSONModelerTest/OrderJSON+YApiTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OrderJSON+YApiTest.swift 3 | // SwiftJSONModeler For XcodeTests 4 | // 5 | // Created by Sven on 2021/4/27. 6 | // Copyright © 2021 Sven. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import OrderJSON 11 | @testable import SwiftJSONModeler_For_Xcode 12 | 13 | class OrderJSONYApiTest: XCTestCase { 14 | private let testStr = """ 15 | {\"type\":\"object\",\"title\":\"empty object\",\"properties\":{\"data\":{\"type\":\"object\",\"properties\":{\"stringValue\":{\"type\":\"string\",\"description\":\"字符串类型\",\"mock\":{\"mock\":\"字符串\"}},\"integerValue\":{\"type\":\"integer\",\"description\":\"整型数据类型\",\"mock\":{\"mock\":\"20\"}},\"numberValue\":{\"type\":\"number\",\"description\":\"浮点数据类型\",\"mock\":{\"mock\":\"15.5\"}},\"booleanValue\":{\"type\":\"boolean\",\"description\":\"布尔类型\",\"mock\":{\"mock\":\"true\"}},\"arrayValue\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"mock\":{\"mock\":\"数组字符串\"}},\"description\":\"数组类型\"}},\"required\":[\"stringValue\",\"integerValue\",\"numberValue\",\"booleanValue\",\"arrayValue\"]},\"code\":{\"type\":\"string\",\"mock\":{\"mock\":\"200\"}}},\"required\":[\"data\",\"code\"]} 16 | """ 17 | override func setUpWithError() throws { 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | override func tearDownWithError() throws { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | func testExample() throws { 26 | // This is an example of a functional test case. 27 | // Use XCTAssert and related functions to verify your tests produce the correct results. 28 | } 29 | 30 | func testPerformanceExample() throws { 31 | // This is an example of a performance test case. 32 | self.measure { 33 | // Put the code you want to measure the time of here. 34 | } 35 | } 36 | private func transformStringToArray(_ string: String) -> [String] { 37 | if string.isEmpty { 38 | return [] 39 | } 40 | return string.components(separatedBy: ",") 41 | } 42 | /// 测试自定解析 Yapi数据, 且 key 顺序与 json 一致 43 | func testYApiJSON() { 44 | let str = testStr 45 | let path = "data" 46 | let rootPath = "" 47 | guard let jsonObject = try? JsonParser.parse(text: str) else { 48 | XCTAssertFalse(true) 49 | return 50 | } 51 | let rootKeys = jsonObject.yapiSubKeysFor(keyPath: transformStringToArray(rootPath)) 52 | XCTAssertTrue(rootKeys == ["data","code"]) 53 | let dataKeysWhenRight = ["stringValue", "integerValue", "numberValue", "booleanValue", "arrayValue"] 54 | let dataKeys = jsonObject.yapiSubKeysFor(keyPath: transformStringToArray(path)) 55 | XCTAssertTrue(dataKeys == dataKeysWhenRight) 56 | 57 | let stringValuePath = "stringValue" 58 | let stringValueKeys = jsonObject.yapiSubKeysFor(keyPath: transformStringToArray(stringValuePath)) 59 | XCTAssertTrue(stringValueKeys.isEmpty) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /SwiftJSONModeler For XcodeTests/SwiftJSONModelerTest/YApiObjectTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // YApiObjectTest.swift 3 | // SwiftJSONModeler For XcodeTests 4 | // 5 | // Created by Sven on 2020/8/13. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import SwiftJSONModeler_For_Xcode 11 | 12 | class YApiObjectTest: XCTestCase { 13 | 14 | override func setUpWithError() throws { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDownWithError() throws { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testExample() throws { 23 | // This is an example of a functional test case. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testPerformanceExample() throws { 28 | // This is an example of a performance test case. 29 | self.measure { 30 | // Put the code you want to measure the time of here. 31 | } 32 | } 33 | /// 测试将 Raw 数据解析按照路径解析 YapiObject 34 | func testYapiRawTransformObjedt() -> Void { 35 | let rawStr = 36 | """ 37 | {"type":"object","title":"empty object","properties":{"person":{"type":"object","properties":{"name":{"type":"string","description":"姓名","mock":{"mock":"小明"}},"age":{"type":"integer","description":"年龄","mock":{"mock":"12"}},"school":{"type":"object","properties":{"address":{"type":"string","mock":{"mock":"xx街道xx号"},"description":"学校地址"},"schoolName":{"type":"string","description":"学校名字"}},"required":["address","schoolName"],"description":"学校"},"likes":{"type":"array","items":{"type":"string"},"description":"好友"},"teachers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"老师名字"},"subject":{"type":"string","description":"科目","mock":{"mock":"语文"}},"isMale":{"type":"boolean","description":"是否为男"}},"required":["name","subject","isMale"]}}},"required":["name","age","school","likes","teachers"],"description":"个人信息详情"}},"required":["person"]} 38 | 39 | """ 40 | let helper = YApiHelper(paste: rawStr) 41 | helper.aimPath = "" 42 | let yapiObject = helper.pathObject 43 | XCTAssertNotNil(yapiObject) 44 | } 45 | 46 | /// yapi 基本类型(object, array, string, integer, number, boolean)兼容测试 47 | func testYapiBaseType() { 48 | let rawStr = """ 49 | {"type":"object","title":"empty object","properties":{"data":{"type":"object","properties":{"stringValue":{"type":"string","description":"字符串类型","mock":{"mock":"字符串"}},"integerValue":{"type":"integer","description":"整型数据类型","mock":{"mock":"20"}},"numberValue":{"type":"number","description":"浮点数据类型","mock":{"mock":"15.5"}},"booleanValue":{"type":"boolean","description":"布尔类型","mock":{"mock":"true"}},"arrayValue":{"type":"array","items":{"type":"string","mock":{"mock":"数组字符串"}},"description":"数组类型"}},"required":["stringValue","integerValue","numberValue","booleanValue","arrayValue"]},"code":{"type":"string","mock":{"mock":"200"}}},"required":["data","code"]} 50 | """ 51 | let yapiObjc = helper(raw: rawStr) 52 | XCTAssertNotNil(yapiObjc) 53 | let stringObjct = yapiObjc!.childs.filter{ $0.key == "stringValue" } 54 | XCTAssert(stringObjct.last!.type.swiftType() == "String") 55 | let integerObjct = yapiObjc!.childs.filter{ $0.key == "integerValue" } 56 | XCTAssert(integerObjct.last!.type.swiftType() == "Int") 57 | let numberObjct = yapiObjc!.childs.filter{ $0.key == "numberValue" } 58 | XCTAssert(numberObjct.last!.type.swiftType() == "Double") 59 | let booleanObjct = yapiObjc!.childs.filter{ $0.key == "booleanValue" } 60 | XCTAssert(booleanObjct.last!.type.swiftType() == "Bool") 61 | } 62 | 63 | /// 测试type 为非 Java基本类型,包含不规范基本数据(String, Integer)和其他自定义类型(Date, Other) 64 | func testOtherType() -> Void { 65 | let rawStr = """ 66 | {"type":"object","title":"empty object","properties":{"data":{"type":"object","properties":{"StringValue":{"type":"String","description":"字符串类型","mock":{"mock":"字符串"}},"IntegerValue":{"type":"Integer","description":"整型数据类型","mock":{"mock":"20"}},"DateValue":{"type":"Date","description":"日期类型","mock":{"mock":"2020年08月01日"}},"OtherValue":{"type":"Other","description":"其他任意类型","mock":{"mock":"any"}},"arrayValue":{"type":"array","items":{"type":"string","mock":{"mock":"数组字符串"}},"description":"数组类型"}},"required":["stringValue","integerValue","numberValue","booleanValue","arrayValue"]},"code":{"type":"string","mock":{"mock":"200"}}},"required":["data","code"]} 67 | """ 68 | let yapiObjc = helper(raw: rawStr) 69 | XCTAssertNotNil(yapiObjc) 70 | let stringObjct = yapiObjc!.childs.filter{ $0.key == "StringValue" } 71 | XCTAssert(stringObjct.last!.type.swiftType() == "String") 72 | let integerObjct = yapiObjc!.childs.filter{ $0.key == "IntegerValue" } 73 | XCTAssert(integerObjct.last!.type.swiftType() == "Int") 74 | let numberObjct = yapiObjc!.childs.filter{ $0.key == "DateValue" } 75 | XCTAssert(numberObjct.last!.type.swiftType() == "<#Undefined#>" && numberObjct.last!.typeRaw == "Date") 76 | let booleanObjct = yapiObjc!.childs.filter{ $0.key == "OtherValue" } 77 | XCTAssert(booleanObjct.last!.type.swiftType() == "<#Undefined#>" && booleanObjct.last!.typeRaw == "Other") 78 | } 79 | 80 | func helper(raw: String) -> YApiObject? { 81 | let helper = YApiHelper(paste: raw) 82 | helper.aimPath = "data" 83 | return helper.pathObject 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /SwiftJSONModeler For XcodeTests/SwiftJSONModeler_For_XcodeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftJSONModeler_For_XcodeTests.swift 3 | // SwiftJSONModeler For XcodeTests 4 | // 5 | // Created by Sven on 2020/3/28. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import SwiftJSONModeler_For_Xcode 11 | 12 | class SwiftJSONModeler_For_XcodeTests: XCTestCase { 13 | private let baseTypeRaw = 14 | """ 15 | {"type":"object","title":"empty object","properties":{"data":{"type":"object","properties":{"stringValue":{"type":"string","description":"字符串类型","mock":{"mock":"字符串"}},"integerValue":{"type":"integer","description":"整型数据类型","mock":{"mock":"20"}},"numberValue":{"type":"number","description":"浮点数据类型","mock":{"mock":"15.5"}},"booleanValue":{"type":"boolean","description":"布尔类型","mock":{"mock":"true"}},"arrayValue":{"type":"array","items":{"type":"string","mock":{"mock":"数组字符串"}},"description":"数组类型"}},"required":["stringValue","integerValue","numberValue","booleanValue","arrayValue"]},"code":{"type":"string","mock":{"mock":"200"}}},"required":["data","code"]} 16 | """ 17 | override func setUp() { 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | override func tearDown() { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | func testExample() { 26 | // This is an example of a functional test case. 27 | // Use XCTAssert and related functions to verify your tests produce the correct results. 28 | } 29 | 30 | func testPerformanceExample() { 31 | // This is an example of a performance test case. 32 | measure { 33 | // Put the code you want to measure the time of here. 34 | } 35 | } 36 | 37 | func testConfig() { 38 | // let config = Config() 39 | // let conform = config.conform 40 | // config.conform = "AnyConform" 41 | // XCTAssert(config.conform == "AnyConform") 42 | // config.conform = conform 43 | } 44 | 45 | func testOrderJSON() { 46 | let data = baseTypeRaw.data(using: .utf8) 47 | 48 | } 49 | 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /SwiftJSONModeler/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | SwiftJSONModeler For Xcode 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSAppTransportSecurity 26 | 27 | NSAllowsArbitraryLoads 28 | 29 | 30 | NSExtension 31 | 32 | NSExtensionAttributes 33 | 34 | XCSourceEditorCommandDefinitions 35 | 36 | 37 | XCSourceEditorCommandClassName 38 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 39 | XCSourceEditorCommandIdentifier 40 | structFromJSON 41 | XCSourceEditorCommandName 42 | Struct JSON 43 | 44 | 45 | XCSourceEditorCommandClassName 46 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 47 | XCSourceEditorCommandIdentifier 48 | classFromJSON 49 | XCSourceEditorCommandName 50 | Class JSON 51 | 52 | 53 | XCSourceEditorCommandClassName 54 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 55 | XCSourceEditorCommandIdentifier 56 | structFromYApiId 57 | XCSourceEditorCommandName 58 | Struct Yapi Id 59 | 60 | 61 | XCSourceEditorCommandClassName 62 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 63 | XCSourceEditorCommandIdentifier 64 | classFromYApiId 65 | XCSourceEditorCommandName 66 | Class YApi Id 67 | 68 | 69 | XCSourceEditorCommandClassName 70 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 71 | XCSourceEditorCommandIdentifier 72 | structFromRAW 73 | XCSourceEditorCommandName 74 | Struct Yapi RAW 75 | 76 | 77 | XCSourceEditorCommandClassName 78 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 79 | XCSourceEditorCommandIdentifier 80 | classFromRAW 81 | XCSourceEditorCommandName 82 | Class YApi RAW 83 | 84 | 85 | XCSourceEditorCommandClassName 86 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 87 | XCSourceEditorCommandIdentifier 88 | config 89 | XCSourceEditorCommandName 90 | Config 91 | 92 | 93 | XCSourceEditorExtensionPrincipalClass 94 | $(PRODUCT_MODULE_NAME).SourceEditorExtension 95 | 96 | NSExtensionPointIdentifier 97 | com.apple.dt.Xcode.extension.source-editor 98 | 99 | NSHumanReadableCopyright 100 | Copyright © 2020 Sven. All rights reserved. 101 | 102 | 103 | -------------------------------------------------------------------------------- /SwiftJSONModeler/SourceEditorCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SourceEditorCommand.swift 3 | // LExt 4 | // 5 | // Created by Sven on 2020/1/21. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | import XcodeKit 11 | 12 | class SourceEditorCommand: NSObject, XCSourceEditorCommand { 13 | let config = ConfigCenter.default.config 14 | private var completionHandler: (Error?) -> Void = { _ in } 15 | /// 复制版内容 16 | var pasteboardTest: String { 17 | guard let paste = NSPasteboard.general.string(forType: .string) else { 18 | return "" 19 | } 20 | guard !paste.isEmpty else { 21 | return "" 22 | } 23 | return paste 24 | } 25 | func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void) { 26 | print("启动插件") 27 | self.completionHandler = completionHandler 28 | addErrorNoti() 29 | // TODO: json多层解析 30 | let commandIdentifier = invocation.commandIdentifier 31 | if commandIdentifier == configCommand { 32 | NSWorkspace.shared.open(URL(fileURLWithPath: "/Applications/SwiftJSONModeler For Xcode.app")) 33 | completionHandler(nil) 34 | } else if commandIdentifier == classFromRAWCommand || commandIdentifier == structFromRAWCommand { 35 | handleInvocation(invocation, raw: pasteboardTest, completionHandler: completionHandler) 36 | 37 | } else if commandIdentifier == classFromJSONCommand || commandIdentifier == structFromJSONCommand { 38 | handleInvocation(invocation, json: pasteboardTest, completionHandler: completionHandler) 39 | //handleInvocation(invocation, handler: completionHandler) 40 | } else if commandIdentifier == classFromYApiIdCommand || commandIdentifier == structFromYApiIdCommand { 41 | YApiRequest.data(id: pasteboardTest) { [weak self](raw) in 42 | if let raw = raw { 43 | self?.handleInvocation(invocation, raw: raw, completionHandler: completionHandler) 44 | }else { 45 | completionHandler(nil) 46 | } 47 | } 48 | } 49 | } 50 | /// 通过 YApi RAW数据转模 51 | private func handleInvocation(_ invocation: XCSourceEditorCommandInvocation, raw: String, completionHandler: @escaping (Error?) -> Void) { 52 | let yapiCreator = YApiCreator(invocation: invocation, pasteText: raw) 53 | let models = yapiCreator.getModels() 54 | var lines = invocation.buffer.lines 55 | lines.addObjects(from: models) 56 | importModel(lines: &lines) 57 | completionHandler(nil) 58 | } 59 | /// 通过json 转模 60 | private func handleInvocation(_ invocation: XCSourceEditorCommandInvocation, json: String, completionHandler: @escaping (Error?) -> Void) { 61 | guard let transformObject = JSONHelper(paste: json).transform() else { 62 | completionHandler(nil) 63 | return 64 | } 65 | let yapiCreator = YApiCreator(invocation: invocation, 66 | yapiObject: transformObject) 67 | let models = yapiCreator.getModels() 68 | var lines = invocation.buffer.lines 69 | lines.addObjects(from: models) 70 | importModel(lines: &lines) 71 | completionHandler(nil) 72 | } 73 | 74 | 75 | } 76 | 77 | // MARK: - 添加通知 78 | 79 | private extension SourceEditorCommand { 80 | func addErrorNoti() { 81 | NotificationCenter.default.addObserver(self, selector: #selector(errorNoti(noti:)), name: NSNotification.Name.errorNotification, object: nil) 82 | } 83 | @objc 84 | func errorNoti(noti: Notification) { 85 | if ErrorCenter.shared.message.isEmpty { 86 | completionHandler(nil) 87 | }else { 88 | completionHandler(error(msg: ErrorCenter.shared.message)) 89 | } 90 | } 91 | } 92 | 93 | private extension SourceEditorCommand { 94 | func error(msg: String) -> Error { 95 | return NSError(domain: domain, code: 300, userInfo: [NSLocalizedDescriptionKey: msg]) 96 | } 97 | 98 | /// 添加引入模块 99 | func importModel(lines: inout NSMutableArray) { 100 | var firstImportIndex: Int = 8 101 | if lines.count < 9 { 102 | firstImportIndex = 0 103 | } 104 | var aimIndex = firstImportIndex 105 | for (index, value) in lines.enumerated() { 106 | guard let value = value as? String else { 107 | return 108 | } 109 | if value.contains(keyImport) { 110 | if value.contains("Foundation") || value.contains("UIKit") { 111 | aimIndex = index + 1 112 | } else { 113 | aimIndex = index 114 | } 115 | break 116 | } 117 | } 118 | let needImport = filterModle(lines: &lines) 119 | for modle in needImport { 120 | lines.insert("\(keyImport) \(modle)\n", at: aimIndex) 121 | } 122 | } 123 | 124 | /// 过滤已添加的Modle 125 | func filterModle(lines: inout NSMutableArray) -> [String] { 126 | let waitImport = config.moduleArr 127 | let imported: [String] = lines.filter { ($0 as! String).contains(keyImport) } as! [String] 128 | let needImport = waitImport.filter { (modle) -> Bool in 129 | for line in imported { 130 | if line.contains(modle) { 131 | return false 132 | } 133 | } 134 | return true 135 | } 136 | return needImport 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /SwiftJSONModeler/SourceEditorExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SourceEditorExtension.swift 3 | // SwiftJSONModeler For Xcode 4 | // 5 | // Created by Sven on 2020/1/22. 6 | // Copyright © 2020 Sven. 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 | /* 21 | var commandDefinitions: [[XCSourceEditorCommandDefinitionKey: Any]] { 22 | // If your extension needs to return a collection of command definitions that differs from those in its Info.plist, implement this optional property getter. 23 | return [] 24 | } 25 | */ 26 | 27 | } 28 | -------------------------------------------------------------------------------- /SwiftJSONModeler/SwiftJSONModeler.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.application-groups 8 | 9 | SwiftJSONModeler 10 | 11 | com.apple.security.network.client 12 | 13 | com.apple.security.network.server 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C9648113242D8FB800EFFCB6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9648112242D8FB800EFFCB6 /* AppDelegate.swift */; }; 11 | C9648115242D8FB800EFFCB6 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9648114242D8FB800EFFCB6 /* SceneDelegate.swift */; }; 12 | C9648117242D8FB800EFFCB6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9648116242D8FB800EFFCB6 /* ViewController.swift */; }; 13 | C964811A242D8FB800EFFCB6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C9648118242D8FB800EFFCB6 /* Main.storyboard */; }; 14 | C964811C242D8FB900EFFCB6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C964811B242D8FB900EFFCB6 /* Assets.xcassets */; }; 15 | C964811F242D8FB900EFFCB6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C964811D242D8FB900EFFCB6 /* LaunchScreen.storyboard */; }; 16 | C964812B242D9B0D00EFFCB6 /* TestJSONModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C964812A242D9B0D00EFFCB6 /* TestJSONModel.swift */; }; 17 | C964812D242D9B2700EFFCB6 /* TestYapiRAWModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C964812C242D9B2700EFFCB6 /* TestYapiRAWModel.swift */; }; 18 | C9E9C08225CF81E900CD767D /* Config.plist in Resources */ = {isa = PBXBuildFile; fileRef = C9E9C08125CF81E900CD767D /* Config.plist */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | C964810F242D8FB800EFFCB6 /* SwiftJSONModelerDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftJSONModelerDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | C9648112242D8FB800EFFCB6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 24 | C9648114242D8FB800EFFCB6 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 25 | C9648116242D8FB800EFFCB6 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 26 | C9648119242D8FB800EFFCB6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 27 | C964811B242D8FB900EFFCB6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 28 | C964811E242D8FB900EFFCB6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 29 | C9648120242D8FB900EFFCB6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 30 | C964812A242D9B0D00EFFCB6 /* TestJSONModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestJSONModel.swift; sourceTree = ""; }; 31 | C964812C242D9B2700EFFCB6 /* TestYapiRAWModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestYapiRAWModel.swift; sourceTree = ""; }; 32 | C9E9C08125CF81E900CD767D /* Config.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Config.plist; sourceTree = ""; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | C964810C242D8FB800EFFCB6 /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | ); 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | /* End PBXFrameworksBuildPhase section */ 44 | 45 | /* Begin PBXGroup section */ 46 | C9648106242D8FB800EFFCB6 = { 47 | isa = PBXGroup; 48 | children = ( 49 | C9648111242D8FB800EFFCB6 /* SwiftJSONModelerDemo */, 50 | C9648110242D8FB800EFFCB6 /* Products */, 51 | ); 52 | sourceTree = ""; 53 | }; 54 | C9648110242D8FB800EFFCB6 /* Products */ = { 55 | isa = PBXGroup; 56 | children = ( 57 | C964810F242D8FB800EFFCB6 /* SwiftJSONModelerDemo.app */, 58 | ); 59 | name = Products; 60 | sourceTree = ""; 61 | }; 62 | C9648111242D8FB800EFFCB6 /* SwiftJSONModelerDemo */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | C9648112242D8FB800EFFCB6 /* AppDelegate.swift */, 66 | C9648114242D8FB800EFFCB6 /* SceneDelegate.swift */, 67 | C9648116242D8FB800EFFCB6 /* ViewController.swift */, 68 | C9648118242D8FB800EFFCB6 /* Main.storyboard */, 69 | C964811B242D8FB900EFFCB6 /* Assets.xcassets */, 70 | C964811D242D8FB900EFFCB6 /* LaunchScreen.storyboard */, 71 | C9648120242D8FB900EFFCB6 /* Info.plist */, 72 | C964812A242D9B0D00EFFCB6 /* TestJSONModel.swift */, 73 | C964812C242D9B2700EFFCB6 /* TestYapiRAWModel.swift */, 74 | C9E9C08125CF81E900CD767D /* Config.plist */, 75 | ); 76 | path = SwiftJSONModelerDemo; 77 | sourceTree = ""; 78 | }; 79 | /* End PBXGroup section */ 80 | 81 | /* Begin PBXNativeTarget section */ 82 | C964810E242D8FB800EFFCB6 /* SwiftJSONModelerDemo */ = { 83 | isa = PBXNativeTarget; 84 | buildConfigurationList = C9648123242D8FB900EFFCB6 /* Build configuration list for PBXNativeTarget "SwiftJSONModelerDemo" */; 85 | buildPhases = ( 86 | C964810B242D8FB800EFFCB6 /* Sources */, 87 | C964810C242D8FB800EFFCB6 /* Frameworks */, 88 | C964810D242D8FB800EFFCB6 /* Resources */, 89 | ); 90 | buildRules = ( 91 | ); 92 | dependencies = ( 93 | ); 94 | name = SwiftJSONModelerDemo; 95 | productName = SwiftJSONModelerDemo; 96 | productReference = C964810F242D8FB800EFFCB6 /* SwiftJSONModelerDemo.app */; 97 | productType = "com.apple.product-type.application"; 98 | }; 99 | /* End PBXNativeTarget section */ 100 | 101 | /* Begin PBXProject section */ 102 | C9648107242D8FB800EFFCB6 /* Project object */ = { 103 | isa = PBXProject; 104 | attributes = { 105 | LastSwiftUpdateCheck = 1120; 106 | LastUpgradeCheck = 1120; 107 | ORGANIZATIONNAME = Sven; 108 | TargetAttributes = { 109 | C964810E242D8FB800EFFCB6 = { 110 | CreatedOnToolsVersion = 11.2.1; 111 | }; 112 | }; 113 | }; 114 | buildConfigurationList = C964810A242D8FB800EFFCB6 /* Build configuration list for PBXProject "SwiftJSONModelerDemo" */; 115 | compatibilityVersion = "Xcode 9.3"; 116 | developmentRegion = en; 117 | hasScannedForEncodings = 0; 118 | knownRegions = ( 119 | en, 120 | Base, 121 | ); 122 | mainGroup = C9648106242D8FB800EFFCB6; 123 | productRefGroup = C9648110242D8FB800EFFCB6 /* Products */; 124 | projectDirPath = ""; 125 | projectRoot = ""; 126 | targets = ( 127 | C964810E242D8FB800EFFCB6 /* SwiftJSONModelerDemo */, 128 | ); 129 | }; 130 | /* End PBXProject section */ 131 | 132 | /* Begin PBXResourcesBuildPhase section */ 133 | C964810D242D8FB800EFFCB6 /* Resources */ = { 134 | isa = PBXResourcesBuildPhase; 135 | buildActionMask = 2147483647; 136 | files = ( 137 | C9E9C08225CF81E900CD767D /* Config.plist in Resources */, 138 | C964811F242D8FB900EFFCB6 /* LaunchScreen.storyboard in Resources */, 139 | C964811C242D8FB900EFFCB6 /* Assets.xcassets in Resources */, 140 | C964811A242D8FB800EFFCB6 /* Main.storyboard in Resources */, 141 | ); 142 | runOnlyForDeploymentPostprocessing = 0; 143 | }; 144 | /* End PBXResourcesBuildPhase section */ 145 | 146 | /* Begin PBXSourcesBuildPhase section */ 147 | C964810B242D8FB800EFFCB6 /* Sources */ = { 148 | isa = PBXSourcesBuildPhase; 149 | buildActionMask = 2147483647; 150 | files = ( 151 | C9648117242D8FB800EFFCB6 /* ViewController.swift in Sources */, 152 | C9648113242D8FB800EFFCB6 /* AppDelegate.swift in Sources */, 153 | C964812D242D9B2700EFFCB6 /* TestYapiRAWModel.swift in Sources */, 154 | C9648115242D8FB800EFFCB6 /* SceneDelegate.swift in Sources */, 155 | C964812B242D9B0D00EFFCB6 /* TestJSONModel.swift in Sources */, 156 | ); 157 | runOnlyForDeploymentPostprocessing = 0; 158 | }; 159 | /* End PBXSourcesBuildPhase section */ 160 | 161 | /* Begin PBXVariantGroup section */ 162 | C9648118242D8FB800EFFCB6 /* Main.storyboard */ = { 163 | isa = PBXVariantGroup; 164 | children = ( 165 | C9648119242D8FB800EFFCB6 /* Base */, 166 | ); 167 | name = Main.storyboard; 168 | sourceTree = ""; 169 | }; 170 | C964811D242D8FB900EFFCB6 /* LaunchScreen.storyboard */ = { 171 | isa = PBXVariantGroup; 172 | children = ( 173 | C964811E242D8FB900EFFCB6 /* Base */, 174 | ); 175 | name = LaunchScreen.storyboard; 176 | sourceTree = ""; 177 | }; 178 | /* End PBXVariantGroup section */ 179 | 180 | /* Begin XCBuildConfiguration section */ 181 | C9648121242D8FB900EFFCB6 /* Debug */ = { 182 | isa = XCBuildConfiguration; 183 | buildSettings = { 184 | ALWAYS_SEARCH_USER_PATHS = NO; 185 | CLANG_ANALYZER_NONNULL = YES; 186 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 187 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 188 | CLANG_CXX_LIBRARY = "libc++"; 189 | CLANG_ENABLE_MODULES = YES; 190 | CLANG_ENABLE_OBJC_ARC = YES; 191 | CLANG_ENABLE_OBJC_WEAK = YES; 192 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 193 | CLANG_WARN_BOOL_CONVERSION = YES; 194 | CLANG_WARN_COMMA = YES; 195 | CLANG_WARN_CONSTANT_CONVERSION = YES; 196 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 197 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 198 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 199 | CLANG_WARN_EMPTY_BODY = YES; 200 | CLANG_WARN_ENUM_CONVERSION = YES; 201 | CLANG_WARN_INFINITE_RECURSION = YES; 202 | CLANG_WARN_INT_CONVERSION = YES; 203 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 204 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 205 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 206 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 207 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 208 | CLANG_WARN_STRICT_PROTOTYPES = YES; 209 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 210 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 211 | CLANG_WARN_UNREACHABLE_CODE = YES; 212 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 213 | COPY_PHASE_STRIP = NO; 214 | DEBUG_INFORMATION_FORMAT = dwarf; 215 | ENABLE_STRICT_OBJC_MSGSEND = YES; 216 | ENABLE_TESTABILITY = YES; 217 | GCC_C_LANGUAGE_STANDARD = gnu11; 218 | GCC_DYNAMIC_NO_PIC = NO; 219 | GCC_NO_COMMON_BLOCKS = YES; 220 | GCC_OPTIMIZATION_LEVEL = 0; 221 | GCC_PREPROCESSOR_DEFINITIONS = ( 222 | "DEBUG=1", 223 | "$(inherited)", 224 | ); 225 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 226 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 227 | GCC_WARN_UNDECLARED_SELECTOR = YES; 228 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 229 | GCC_WARN_UNUSED_FUNCTION = YES; 230 | GCC_WARN_UNUSED_VARIABLE = YES; 231 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 232 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 233 | MTL_FAST_MATH = YES; 234 | ONLY_ACTIVE_ARCH = YES; 235 | SDKROOT = iphoneos; 236 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 237 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 238 | }; 239 | name = Debug; 240 | }; 241 | C9648122242D8FB900EFFCB6 /* Release */ = { 242 | isa = XCBuildConfiguration; 243 | buildSettings = { 244 | ALWAYS_SEARCH_USER_PATHS = NO; 245 | CLANG_ANALYZER_NONNULL = YES; 246 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 247 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 248 | CLANG_CXX_LIBRARY = "libc++"; 249 | CLANG_ENABLE_MODULES = YES; 250 | CLANG_ENABLE_OBJC_ARC = YES; 251 | CLANG_ENABLE_OBJC_WEAK = YES; 252 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 253 | CLANG_WARN_BOOL_CONVERSION = YES; 254 | CLANG_WARN_COMMA = YES; 255 | CLANG_WARN_CONSTANT_CONVERSION = YES; 256 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 257 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 258 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 259 | CLANG_WARN_EMPTY_BODY = YES; 260 | CLANG_WARN_ENUM_CONVERSION = YES; 261 | CLANG_WARN_INFINITE_RECURSION = YES; 262 | CLANG_WARN_INT_CONVERSION = YES; 263 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 264 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 265 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 266 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 267 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 268 | CLANG_WARN_STRICT_PROTOTYPES = YES; 269 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 270 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 271 | CLANG_WARN_UNREACHABLE_CODE = YES; 272 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 273 | COPY_PHASE_STRIP = NO; 274 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 275 | ENABLE_NS_ASSERTIONS = NO; 276 | ENABLE_STRICT_OBJC_MSGSEND = YES; 277 | GCC_C_LANGUAGE_STANDARD = gnu11; 278 | GCC_NO_COMMON_BLOCKS = YES; 279 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 280 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 281 | GCC_WARN_UNDECLARED_SELECTOR = YES; 282 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 283 | GCC_WARN_UNUSED_FUNCTION = YES; 284 | GCC_WARN_UNUSED_VARIABLE = YES; 285 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 286 | MTL_ENABLE_DEBUG_INFO = NO; 287 | MTL_FAST_MATH = YES; 288 | SDKROOT = iphoneos; 289 | SWIFT_COMPILATION_MODE = wholemodule; 290 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 291 | VALIDATE_PRODUCT = YES; 292 | }; 293 | name = Release; 294 | }; 295 | C9648124242D8FB900EFFCB6 /* Debug */ = { 296 | isa = XCBuildConfiguration; 297 | buildSettings = { 298 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 299 | CODE_SIGN_STYLE = Automatic; 300 | DEVELOPMENT_TEAM = K9DS6XKGWL; 301 | INFOPLIST_FILE = SwiftJSONModelerDemo/Info.plist; 302 | LD_RUNPATH_SEARCH_PATHS = ( 303 | "$(inherited)", 304 | "@executable_path/Frameworks", 305 | ); 306 | PRODUCT_BUNDLE_IDENTIFIER = com.lifu.SwiftJSONModelerDemo; 307 | PRODUCT_NAME = "$(TARGET_NAME)"; 308 | SWIFT_VERSION = 5.0; 309 | TARGETED_DEVICE_FAMILY = "1,2"; 310 | }; 311 | name = Debug; 312 | }; 313 | C9648125242D8FB900EFFCB6 /* Release */ = { 314 | isa = XCBuildConfiguration; 315 | buildSettings = { 316 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 317 | CODE_SIGN_STYLE = Automatic; 318 | DEVELOPMENT_TEAM = K9DS6XKGWL; 319 | INFOPLIST_FILE = SwiftJSONModelerDemo/Info.plist; 320 | LD_RUNPATH_SEARCH_PATHS = ( 321 | "$(inherited)", 322 | "@executable_path/Frameworks", 323 | ); 324 | PRODUCT_BUNDLE_IDENTIFIER = com.lifu.SwiftJSONModelerDemo; 325 | PRODUCT_NAME = "$(TARGET_NAME)"; 326 | SWIFT_VERSION = 5.0; 327 | TARGETED_DEVICE_FAMILY = "1,2"; 328 | }; 329 | name = Release; 330 | }; 331 | /* End XCBuildConfiguration section */ 332 | 333 | /* Begin XCConfigurationList section */ 334 | C964810A242D8FB800EFFCB6 /* Build configuration list for PBXProject "SwiftJSONModelerDemo" */ = { 335 | isa = XCConfigurationList; 336 | buildConfigurations = ( 337 | C9648121242D8FB900EFFCB6 /* Debug */, 338 | C9648122242D8FB900EFFCB6 /* Release */, 339 | ); 340 | defaultConfigurationIsVisible = 0; 341 | defaultConfigurationName = Release; 342 | }; 343 | C9648123242D8FB900EFFCB6 /* Build configuration list for PBXNativeTarget "SwiftJSONModelerDemo" */ = { 344 | isa = XCConfigurationList; 345 | buildConfigurations = ( 346 | C9648124242D8FB900EFFCB6 /* Debug */, 347 | C9648125242D8FB900EFFCB6 /* Release */, 348 | ); 349 | defaultConfigurationIsVisible = 0; 350 | defaultConfigurationName = Release; 351 | }; 352 | /* End XCConfigurationList section */ 353 | }; 354 | rootObject = C9648107242D8FB800EFFCB6 /* Project object */; 355 | } 356 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo.xcodeproj/xcuserdata/yibin.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SwiftJSONModelerDemo.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SwiftJSONModelerDemo 4 | // 5 | // Created by Sven on 2020/3/27. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | return true 19 | } 20 | 21 | // MARK: UISceneSession Lifecycle 22 | 23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 24 | // Called when a new scene session is being created. 25 | // Use this method to select a configuration to create the new scene with. 26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 27 | } 28 | 29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 30 | // Called when the user discards a scene session. 31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 33 | } 34 | 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo/Base.lproj/LaunchScreen.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 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo/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 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Base 6 | 7 | Conform 8 | 9 | Import module 10 | 11 | Model prefix 12 | 13 | Model suffix 14 | 15 | Option 16 | 17 | Is array empty 18 | 19 | Is option 20 | 21 | Is wrapped option 22 | 23 | 24 | YApi 25 | 26 | Is show mock 27 | 28 | Path 29 | 30 | Token 31 | 32 | Host 33 | 34 | 35 | Comment 36 | 37 | YApi list 38 | 39 | 40 | name 41 | 42 | token 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIMainStoryboardFile 45 | Main 46 | UIRequiredDeviceCapabilities 47 | 48 | armv7 49 | 50 | UISupportedInterfaceOrientations 51 | 52 | UIInterfaceOrientationPortrait 53 | UIInterfaceOrientationLandscapeLeft 54 | UIInterfaceOrientationLandscapeRight 55 | 56 | UISupportedInterfaceOrientations~ipad 57 | 58 | UIInterfaceOrientationPortrait 59 | UIInterfaceOrientationPortraitUpsideDown 60 | UIInterfaceOrientationLandscapeLeft 61 | UIInterfaceOrientationLandscapeRight 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // SwiftJSONModelerDemo 4 | // 5 | // Created by Sven on 2020/3/27. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 12 | 13 | var window: UIWindow? 14 | 15 | 16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 20 | guard let _ = (scene as? UIWindowScene) else { return } 21 | } 22 | 23 | func sceneDidDisconnect(_ scene: UIScene) { 24 | // Called as the scene is being released by the system. 25 | // This occurs shortly after the scene enters the background, or when its session is discarded. 26 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 28 | } 29 | 30 | func sceneDidBecomeActive(_ scene: UIScene) { 31 | // Called when the scene has moved from an inactive state to an active state. 32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 33 | } 34 | 35 | func sceneWillResignActive(_ scene: UIScene) { 36 | // Called when the scene will move from an active state to an inactive state. 37 | // This may occur due to temporary interruptions (ex. an incoming phone call). 38 | } 39 | 40 | func sceneWillEnterForeground(_ scene: UIScene) { 41 | // Called as the scene transitions from the background to the foreground. 42 | // Use this method to undo the changes made on entering the background. 43 | } 44 | 45 | func sceneDidEnterBackground(_ scene: UIScene) { 46 | // Called as the scene transitions from the foreground to the background. 47 | // Use this method to save data, release shared resources, and store enough scene-specific state information 48 | // to restore the scene back to its current state. 49 | } 50 | 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo/TestJSONModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestJSONModel.swift 3 | // SwiftJSONModelerDemo 4 | // 5 | // Created by Sven on 2020/3/27. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Codable 11 | import HandJSON 12 | import HandyJSON 13 | 14 | /// 普通json 数据 15 | let normalJSON = """ 16 | { 17 | "title": "第一层 json", 18 | "stringValue": "字符串值", 19 | "intValue": 58, 20 | "doubleValue": 18.2, 21 | "nullValue": null, 22 | "boolValue": true, 23 | "subJson": { 24 | "title": "第二层 json", 25 | "stringValue": "字符串值" 26 | }, 27 | "arrayValue1": [ 28 | "value1", 29 | "value2", 30 | "value3" 31 | ], 32 | "arrayValue2": [{ 33 | "title": "数组包含子 json", 34 | "intValue": 12, 35 | "boolValue": false 36 | }] 37 | } 38 | """ 39 | 40 | // MARK: - 插件创建模型 41 | 42 | 43 | /// 44 | struct HKModel: HandyJSON { 45 | 46 | var arrayValue2: [HKArrayValue2Model] = [] 47 | 48 | var nullValue: <#NSNull#>? 49 | 50 | var intValue: Int? 51 | 52 | var arrayValue1: [String] = [] 53 | 54 | var title: String? 55 | 56 | var stringValue: String? 57 | /// 58 | var subJson: HKSubJsonModel? 59 | 60 | var doubleValue: Double? 61 | 62 | var boolValue: Int? 63 | } 64 | 65 | /// 66 | struct HKArrayValue2Model: HandyJSON { 67 | 68 | var title: String? 69 | 70 | var boolValue: Int? 71 | 72 | var intValue: Int? 73 | } 74 | 75 | /// 76 | struct HKSubJsonModel: HandyJSON { 77 | 78 | var title: String? 79 | 80 | var stringValue: String? 81 | } 82 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo/TestYapiRAWModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestYapiRAWModel.swift 3 | // SwiftJSONModelerDemo 4 | // 5 | // Created by Sven on 2020/3/27. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Codable 11 | import HandJSON 12 | import HandyJSON 13 | 14 | /// YApi RAW类型json数据 15 | let yapiRAWData = """ 16 | {"type":"object","title":"empty object","properties":{"message":{"type":"string"},"code":{"type":"string"},"response":{"type":"object","properties":{"teachers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","mock":{"mock":"Mrs Yang"},"description":"名字"},"subject":{"type":"string","mock":{"mock":"语文"},"description":"科目"},"phone":{"type":"string","mock":{"mock":"13459923098"},"description":"联系电话"}},"required":["name","subject","phone"]},"description":"老师"},"name":{"type":"string","description":"姓名"},"age":{"type":"integer","mock":{"mock":"18"},"description":"年龄"},"score":{"type":"number","mock":{"mock":"89.8"},"description":"综合成绩"},"likes":{"type":"array","items":{"type":"string","mock":{"mock":"英雄联盟"}},"description":"爱好"},"emergercyContact":{"type":"object","properties":{"name":{"type":"string"},"phone":{"type":"string","description":"联系电话"},"address":{"type":"string","description":"联系地址","mock":{"mock":"xx街道xx栋xx单元"}}},"description":"紧急联系人","required":["name","phone","address"]},"isBoy":{"type":"boolean","description":"是否为男孩"}},"required":["teachers","name","age","score","likes","emergercyContact","isBoy"]}},"required":["message","code","response"]} 17 | """ 18 | 19 | // 通过 YApi RAW数据转换Swift模型 20 | 21 | 22 | 23 | /// <#描述#> 24 | struct HKModel: HandJSON { 25 | 26 | var code: String = "" 27 | 28 | var response: HKResponseModel? 29 | 30 | var message: String = "" 31 | } 32 | 33 | /// <#描述#> 34 | struct HKResponseModel: HandJSON { 35 | /// 老师 36 | var teachers: [HKTeachersModel] = [] 37 | /// 爱好 38 | var likes: [String] = [] 39 | /// 年龄 40 | var age: Int? 41 | /// 是否为男孩 42 | var isBoy: Bool? 43 | /// 紧急联系人 44 | var emergercyContact: HKEmergercyContactModel? 45 | /// 综合成绩 46 | var score: Double? 47 | /// 姓名 48 | var name: String = "" 49 | } 50 | 51 | /// <#描述#> 52 | struct HKTeachersModel: HandJSON { 53 | /// 科目 54 | var subject: String = "" 55 | /// 名字 56 | var name: String = "" 57 | /// 联系电话 58 | var phone: String = "" 59 | } 60 | 61 | /// 紧急联系人 62 | struct HKEmergercyContactModel: HandJSON { 63 | /// 联系地址 64 | var address: String = "" 65 | /// 联系电话 66 | var phone: String = "" 67 | 68 | var name: String = "" 69 | } 70 | 71 | 72 | -------------------------------------------------------------------------------- /SwiftJSONModelerDemo/SwiftJSONModelerDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SwiftJSONModelerDemo 4 | // 5 | // Created by Sven on 2020/3/27. 6 | // Copyright © 2020 Sven. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view. 16 | } 17 | 18 | 19 | } 20 | 21 | --------------------------------------------------------------------------------