├── .github └── workflows │ └── xcode.yml ├── .gitignore ├── Gravity.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── swiftpm │ └── Package.resolved ├── LICENSE ├── README.md ├── Shared ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── ContentView.swift ├── Environment.swift ├── GravityApp.swift ├── SectionDetails │ ├── CodeSectionView.swift │ ├── FuncSectionView.swift │ ├── NameSectionView.swift │ ├── RawSectionView.swift │ ├── SectionDetails.swift │ └── TypeSectionView.swift ├── SectionItem.swift ├── State.swift └── Wasm │ ├── CodeSection.swift │ ├── FuncSection.swift │ ├── NameSection.swift │ ├── TypeSection.swift │ └── WasmDocument.swift └── macOS ├── Info.plist └── macOS.entitlements /.github/workflows/xcode.yml: -------------------------------------------------------------------------------- 1 | name: Xcode - Build and Analyze 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | name: Build and analyse default scheme using xcodebuild command 12 | runs-on: macos-12 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | - name: Set Default Scheme 18 | run: | 19 | scheme_list=$(xcodebuild -list -json | tr -d "\n") 20 | default=$(echo $scheme_list | ruby -e "require 'json'; puts JSON.parse(STDIN.gets)['project']['targets'][0]") 21 | echo $default | cat >default 22 | echo Using default scheme: $default 23 | - name: Build 24 | env: 25 | scheme: ${{ 'default' }} 26 | run: | 27 | if [ $scheme = default ]; then scheme=$(cat default); fi 28 | if [ "`ls -A | grep -i \\.xcworkspace\$`" ]; then filetype_parameter="workspace" && file_to_build="`ls -A | grep -i \\.xcworkspace\$`"; else filetype_parameter="project" && file_to_build="`ls -A | grep -i \\.xcodeproj\$`"; fi 29 | file_to_build=`echo $file_to_build | awk '{$1=$1;print}'` 30 | xcodebuild clean build analyze -scheme "$scheme" -"$filetype_parameter" "$file_to_build" | xcpretty && exit ${PIPESTATUS[0]} 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | .swiftpm/xcode 22 | *.xcodeproj 23 | 24 | # Bundler 25 | .bundle 26 | 27 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 28 | # Carthage/Checkouts 29 | 30 | Carthage/Build 31 | 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 35 | # 36 | # Note: if you ignore the Pods directory, make sure to uncomment 37 | # `pod install` in .travis.yml 38 | # 39 | Pods/ 40 | 41 | # SwiftPM 42 | .build 43 | /Packages 44 | -------------------------------------------------------------------------------- /Gravity.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D119897328A15CF000F83E46 /* TypeSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D119897128A15CF000F83E46 /* TypeSection.swift */; }; 11 | D12CBCD02586BA0D00AB2B1B /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = D12CBCCF2586BA0D00AB2B1B /* ComposableArchitecture */; }; 12 | D12CBCD52586BADA00AB2B1B /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12CBCD32586BADA00AB2B1B /* State.swift */; }; 13 | D192777D258795410071A096 /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D192777B258795410071A096 /* Environment.swift */; }; 14 | D19277902587AEF70071A096 /* SectionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D192778E2587AEF70071A096 /* SectionItem.swift */; }; 15 | D19277952587C90A0071A096 /* WasmDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = D19277932587C90A0071A096 /* WasmDocument.swift */; }; 16 | D192779C2587EF340071A096 /* SectionDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = D192779A2587EF340071A096 /* SectionDetails.swift */; }; 17 | D1B532C6258A265400543607 /* FuncSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1B532C4258A265400543607 /* FuncSection.swift */; }; 18 | D1B532CB258A347400543607 /* FuncSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1B532C9258A347400543607 /* FuncSectionView.swift */; }; 19 | D1BEDBCD258927FC00DEEF96 /* NameSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1BEDBCB258927FC00DEEF96 /* NameSectionView.swift */; }; 20 | D1C5A9D02588D7D400F74991 /* RawSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1C5A9CE2588D7D400F74991 /* RawSectionView.swift */; }; 21 | D1C5A9D72588DA0300F74991 /* TypeSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1C5A9D52588DA0300F74991 /* TypeSectionView.swift */; }; 22 | D1C5A9DC2588E9D000F74991 /* NameSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1C5A9DA2588E9D000F74991 /* NameSection.swift */; }; 23 | D1FDC43328A3F8A100F6B08B /* CodeSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1FDC43228A3F8A100F6B08B /* CodeSectionView.swift */; }; 24 | D1FDC43928A4191000F6B08B /* CodeSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1FDC43828A4191000F6B08B /* CodeSection.swift */; }; 25 | D1FF98A2257D7119004ECE90 /* GravityApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1FF988E257D7116004ECE90 /* GravityApp.swift */; }; 26 | D1FF98A4257D7119004ECE90 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1FF988F257D7116004ECE90 /* ContentView.swift */; }; 27 | D1FF98A6257D7119004ECE90 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D1FF9890257D7119004ECE90 /* Assets.xcassets */; }; 28 | D1FF98B3257D725D004ECE90 /* WasmTransformer in Frameworks */ = {isa = PBXBuildFile; productRef = D1FF98B2257D725D004ECE90 /* WasmTransformer */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | D119897128A15CF000F83E46 /* TypeSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypeSection.swift; sourceTree = ""; }; 33 | D12CBCD32586BADA00AB2B1B /* State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = ""; }; 34 | D192777B258795410071A096 /* Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = ""; }; 35 | D192778E2587AEF70071A096 /* SectionItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionItem.swift; sourceTree = ""; }; 36 | D19277932587C90A0071A096 /* WasmDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WasmDocument.swift; sourceTree = ""; }; 37 | D192779A2587EF340071A096 /* SectionDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionDetails.swift; sourceTree = ""; }; 38 | D1B532C4258A265400543607 /* FuncSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FuncSection.swift; sourceTree = ""; }; 39 | D1B532C9258A347400543607 /* FuncSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FuncSectionView.swift; sourceTree = ""; }; 40 | D1BEDBCB258927FC00DEEF96 /* NameSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NameSectionView.swift; sourceTree = ""; }; 41 | D1C5A9CE2588D7D400F74991 /* RawSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawSectionView.swift; sourceTree = ""; }; 42 | D1C5A9D52588DA0300F74991 /* TypeSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypeSectionView.swift; sourceTree = ""; }; 43 | D1C5A9DA2588E9D000F74991 /* NameSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NameSection.swift; sourceTree = ""; }; 44 | D1FDC43228A3F8A100F6B08B /* CodeSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeSectionView.swift; sourceTree = ""; }; 45 | D1FDC43828A4191000F6B08B /* CodeSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeSection.swift; sourceTree = ""; }; 46 | D1FF988E257D7116004ECE90 /* GravityApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GravityApp.swift; sourceTree = ""; }; 47 | D1FF988F257D7116004ECE90 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 48 | D1FF9890257D7119004ECE90 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 49 | D1FF989D257D7119004ECE90 /* Gravity.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Gravity.app; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | D1FF989F257D7119004ECE90 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | D1FF98A0257D7119004ECE90 /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | D1FF989A257D7119004ECE90 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | D12CBCD02586BA0D00AB2B1B /* ComposableArchitecture in Frameworks */, 60 | D1FF98B3257D725D004ECE90 /* WasmTransformer in Frameworks */, 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | /* End PBXFrameworksBuildPhase section */ 65 | 66 | /* Begin PBXGroup section */ 67 | D1B532C1258A259C00543607 /* Wasm */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | D1C5A9DA2588E9D000F74991 /* NameSection.swift */, 71 | D19277932587C90A0071A096 /* WasmDocument.swift */, 72 | D1B532C4258A265400543607 /* FuncSection.swift */, 73 | D119897128A15CF000F83E46 /* TypeSection.swift */, 74 | D1FDC43828A4191000F6B08B /* CodeSection.swift */, 75 | ); 76 | path = Wasm; 77 | sourceTree = ""; 78 | }; 79 | D1C5A9CB2588D7C300F74991 /* SectionDetails */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | D192779A2587EF340071A096 /* SectionDetails.swift */, 83 | D1C5A9CE2588D7D400F74991 /* RawSectionView.swift */, 84 | D1C5A9D52588DA0300F74991 /* TypeSectionView.swift */, 85 | D1BEDBCB258927FC00DEEF96 /* NameSectionView.swift */, 86 | D1B532C9258A347400543607 /* FuncSectionView.swift */, 87 | D1FDC43228A3F8A100F6B08B /* CodeSectionView.swift */, 88 | ); 89 | path = SectionDetails; 90 | sourceTree = ""; 91 | }; 92 | D1FF9888257D7116004ECE90 = { 93 | isa = PBXGroup; 94 | children = ( 95 | D1FF988D257D7116004ECE90 /* Shared */, 96 | D1FF989E257D7119004ECE90 /* macOS */, 97 | D1FF9896257D7119004ECE90 /* Products */, 98 | ); 99 | indentWidth = 2; 100 | sourceTree = ""; 101 | tabWidth = 2; 102 | }; 103 | D1FF988D257D7116004ECE90 /* Shared */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | D1FF988F257D7116004ECE90 /* ContentView.swift */, 107 | D192777B258795410071A096 /* Environment.swift */, 108 | D1FF988E257D7116004ECE90 /* GravityApp.swift */, 109 | D192778E2587AEF70071A096 /* SectionItem.swift */, 110 | D12CBCD32586BADA00AB2B1B /* State.swift */, 111 | D1FF9890257D7119004ECE90 /* Assets.xcassets */, 112 | D1C5A9CB2588D7C300F74991 /* SectionDetails */, 113 | D1B532C1258A259C00543607 /* Wasm */, 114 | ); 115 | path = Shared; 116 | sourceTree = ""; 117 | }; 118 | D1FF9896257D7119004ECE90 /* Products */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | D1FF989D257D7119004ECE90 /* Gravity.app */, 122 | ); 123 | name = Products; 124 | sourceTree = ""; 125 | }; 126 | D1FF989E257D7119004ECE90 /* macOS */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | D1FF989F257D7119004ECE90 /* Info.plist */, 130 | D1FF98A0257D7119004ECE90 /* macOS.entitlements */, 131 | ); 132 | path = macOS; 133 | sourceTree = ""; 134 | }; 135 | /* End PBXGroup section */ 136 | 137 | /* Begin PBXNativeTarget section */ 138 | D1FF989C257D7119004ECE90 /* Gravity (macOS) */ = { 139 | isa = PBXNativeTarget; 140 | buildConfigurationList = D1FF98AC257D7119004ECE90 /* Build configuration list for PBXNativeTarget "Gravity (macOS)" */; 141 | buildPhases = ( 142 | D1FF9899257D7119004ECE90 /* Sources */, 143 | D1FF989A257D7119004ECE90 /* Frameworks */, 144 | D1FF989B257D7119004ECE90 /* Resources */, 145 | ); 146 | buildRules = ( 147 | ); 148 | dependencies = ( 149 | ); 150 | name = "Gravity (macOS)"; 151 | packageProductDependencies = ( 152 | D1FF98B2257D725D004ECE90 /* WasmTransformer */, 153 | D12CBCCF2586BA0D00AB2B1B /* ComposableArchitecture */, 154 | ); 155 | productName = "Gravity (macOS)"; 156 | productReference = D1FF989D257D7119004ECE90 /* Gravity.app */; 157 | productType = "com.apple.product-type.application"; 158 | }; 159 | /* End PBXNativeTarget section */ 160 | 161 | /* Begin PBXProject section */ 162 | D1FF9889257D7116004ECE90 /* Project object */ = { 163 | isa = PBXProject; 164 | attributes = { 165 | LastSwiftUpdateCheck = 1220; 166 | LastUpgradeCheck = 1220; 167 | TargetAttributes = { 168 | D1FF989C257D7119004ECE90 = { 169 | CreatedOnToolsVersion = 12.2; 170 | }; 171 | }; 172 | }; 173 | buildConfigurationList = D1FF988C257D7116004ECE90 /* Build configuration list for PBXProject "Gravity" */; 174 | compatibilityVersion = "Xcode 9.3"; 175 | developmentRegion = en; 176 | hasScannedForEncodings = 0; 177 | knownRegions = ( 178 | en, 179 | Base, 180 | ); 181 | mainGroup = D1FF9888257D7116004ECE90; 182 | packageReferences = ( 183 | D1FF98B1257D725D004ECE90 /* XCRemoteSwiftPackageReference "WasmTransformer" */, 184 | D12CBCCE2586BA0D00AB2B1B /* XCRemoteSwiftPackageReference "swift-composable-architecture" */, 185 | ); 186 | productRefGroup = D1FF9896257D7119004ECE90 /* Products */; 187 | projectDirPath = ""; 188 | projectRoot = ""; 189 | targets = ( 190 | D1FF989C257D7119004ECE90 /* Gravity (macOS) */, 191 | ); 192 | }; 193 | /* End PBXProject section */ 194 | 195 | /* Begin PBXResourcesBuildPhase section */ 196 | D1FF989B257D7119004ECE90 /* Resources */ = { 197 | isa = PBXResourcesBuildPhase; 198 | buildActionMask = 2147483647; 199 | files = ( 200 | D1FF98A6257D7119004ECE90 /* Assets.xcassets in Resources */, 201 | ); 202 | runOnlyForDeploymentPostprocessing = 0; 203 | }; 204 | /* End PBXResourcesBuildPhase section */ 205 | 206 | /* Begin PBXSourcesBuildPhase section */ 207 | D1FF9899257D7119004ECE90 /* Sources */ = { 208 | isa = PBXSourcesBuildPhase; 209 | buildActionMask = 2147483647; 210 | files = ( 211 | D1FDC43328A3F8A100F6B08B /* CodeSectionView.swift in Sources */, 212 | D1B532CB258A347400543607 /* FuncSectionView.swift in Sources */, 213 | D1FF98A4257D7119004ECE90 /* ContentView.swift in Sources */, 214 | D1B532C6258A265400543607 /* FuncSection.swift in Sources */, 215 | D192777D258795410071A096 /* Environment.swift in Sources */, 216 | D1C5A9D72588DA0300F74991 /* TypeSectionView.swift in Sources */, 217 | D19277952587C90A0071A096 /* WasmDocument.swift in Sources */, 218 | D1BEDBCD258927FC00DEEF96 /* NameSectionView.swift in Sources */, 219 | D119897328A15CF000F83E46 /* TypeSection.swift in Sources */, 220 | D1FDC43928A4191000F6B08B /* CodeSection.swift in Sources */, 221 | D1FF98A2257D7119004ECE90 /* GravityApp.swift in Sources */, 222 | D1C5A9D02588D7D400F74991 /* RawSectionView.swift in Sources */, 223 | D192779C2587EF340071A096 /* SectionDetails.swift in Sources */, 224 | D19277902587AEF70071A096 /* SectionItem.swift in Sources */, 225 | D1C5A9DC2588E9D000F74991 /* NameSection.swift in Sources */, 226 | D12CBCD52586BADA00AB2B1B /* State.swift in Sources */, 227 | ); 228 | runOnlyForDeploymentPostprocessing = 0; 229 | }; 230 | /* End PBXSourcesBuildPhase section */ 231 | 232 | /* Begin XCBuildConfiguration section */ 233 | D1FF98A7257D7119004ECE90 /* Debug */ = { 234 | isa = XCBuildConfiguration; 235 | buildSettings = { 236 | ALWAYS_SEARCH_USER_PATHS = NO; 237 | CLANG_ANALYZER_NONNULL = YES; 238 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_MODULES = YES; 242 | CLANG_ENABLE_OBJC_ARC = YES; 243 | CLANG_ENABLE_OBJC_WEAK = YES; 244 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 245 | CLANG_WARN_BOOL_CONVERSION = YES; 246 | CLANG_WARN_COMMA = YES; 247 | CLANG_WARN_CONSTANT_CONVERSION = YES; 248 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 249 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 250 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 251 | CLANG_WARN_EMPTY_BODY = YES; 252 | CLANG_WARN_ENUM_CONVERSION = YES; 253 | CLANG_WARN_INFINITE_RECURSION = YES; 254 | CLANG_WARN_INT_CONVERSION = YES; 255 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 257 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 258 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 259 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 260 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 261 | CLANG_WARN_STRICT_PROTOTYPES = YES; 262 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 263 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 264 | CLANG_WARN_UNREACHABLE_CODE = YES; 265 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 266 | COPY_PHASE_STRIP = NO; 267 | DEBUG_INFORMATION_FORMAT = dwarf; 268 | ENABLE_STRICT_OBJC_MSGSEND = YES; 269 | ENABLE_TESTABILITY = YES; 270 | GCC_C_LANGUAGE_STANDARD = gnu11; 271 | GCC_DYNAMIC_NO_PIC = NO; 272 | GCC_NO_COMMON_BLOCKS = YES; 273 | GCC_OPTIMIZATION_LEVEL = 0; 274 | GCC_PREPROCESSOR_DEFINITIONS = ( 275 | "DEBUG=1", 276 | "$(inherited)", 277 | ); 278 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 279 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 280 | GCC_WARN_UNDECLARED_SELECTOR = YES; 281 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 282 | GCC_WARN_UNUSED_FUNCTION = YES; 283 | GCC_WARN_UNUSED_VARIABLE = YES; 284 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 285 | MTL_FAST_MATH = YES; 286 | ONLY_ACTIVE_ARCH = YES; 287 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 288 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 289 | }; 290 | name = Debug; 291 | }; 292 | D1FF98A8257D7119004ECE90 /* Release */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | ALWAYS_SEARCH_USER_PATHS = NO; 296 | CLANG_ANALYZER_NONNULL = YES; 297 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 298 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 299 | CLANG_CXX_LIBRARY = "libc++"; 300 | CLANG_ENABLE_MODULES = YES; 301 | CLANG_ENABLE_OBJC_ARC = YES; 302 | CLANG_ENABLE_OBJC_WEAK = YES; 303 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 304 | CLANG_WARN_BOOL_CONVERSION = YES; 305 | CLANG_WARN_COMMA = YES; 306 | CLANG_WARN_CONSTANT_CONVERSION = YES; 307 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 308 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 309 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 310 | CLANG_WARN_EMPTY_BODY = YES; 311 | CLANG_WARN_ENUM_CONVERSION = YES; 312 | CLANG_WARN_INFINITE_RECURSION = YES; 313 | CLANG_WARN_INT_CONVERSION = YES; 314 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 315 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 316 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 317 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 318 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 319 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 320 | CLANG_WARN_STRICT_PROTOTYPES = YES; 321 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 322 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 323 | CLANG_WARN_UNREACHABLE_CODE = YES; 324 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 325 | COPY_PHASE_STRIP = NO; 326 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 327 | ENABLE_NS_ASSERTIONS = NO; 328 | ENABLE_STRICT_OBJC_MSGSEND = YES; 329 | GCC_C_LANGUAGE_STANDARD = gnu11; 330 | GCC_NO_COMMON_BLOCKS = YES; 331 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 332 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 333 | GCC_WARN_UNDECLARED_SELECTOR = YES; 334 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 335 | GCC_WARN_UNUSED_FUNCTION = YES; 336 | GCC_WARN_UNUSED_VARIABLE = YES; 337 | MTL_ENABLE_DEBUG_INFO = NO; 338 | MTL_FAST_MATH = YES; 339 | SWIFT_COMPILATION_MODE = wholemodule; 340 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 341 | }; 342 | name = Release; 343 | }; 344 | D1FF98AD257D7119004ECE90 /* Debug */ = { 345 | isa = XCBuildConfiguration; 346 | buildSettings = { 347 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 348 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 349 | CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; 350 | CODE_SIGN_IDENTITY = "-"; 351 | CODE_SIGN_STYLE = Manual; 352 | COMBINE_HIDPI_IMAGES = YES; 353 | DEVELOPMENT_TEAM = ""; 354 | ENABLE_HARDENED_RUNTIME = YES; 355 | ENABLE_PREVIEWS = YES; 356 | INFOPLIST_FILE = macOS/Info.plist; 357 | LD_RUNPATH_SEARCH_PATHS = ( 358 | "$(inherited)", 359 | "@executable_path/../Frameworks", 360 | ); 361 | MACOSX_DEPLOYMENT_TARGET = 12.0; 362 | PRODUCT_BUNDLE_IDENTIFIER = com.dsignal.Gravity; 363 | PRODUCT_NAME = Gravity; 364 | PROVISIONING_PROFILE_SPECIFIER = ""; 365 | SDKROOT = macosx; 366 | SWIFT_VERSION = 5.0; 367 | }; 368 | name = Debug; 369 | }; 370 | D1FF98AE257D7119004ECE90 /* Release */ = { 371 | isa = XCBuildConfiguration; 372 | buildSettings = { 373 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 374 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 375 | CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; 376 | CODE_SIGN_IDENTITY = "-"; 377 | CODE_SIGN_STYLE = Manual; 378 | COMBINE_HIDPI_IMAGES = YES; 379 | DEVELOPMENT_TEAM = ""; 380 | ENABLE_HARDENED_RUNTIME = YES; 381 | ENABLE_PREVIEWS = YES; 382 | INFOPLIST_FILE = macOS/Info.plist; 383 | LD_RUNPATH_SEARCH_PATHS = ( 384 | "$(inherited)", 385 | "@executable_path/../Frameworks", 386 | ); 387 | MACOSX_DEPLOYMENT_TARGET = 12.0; 388 | PRODUCT_BUNDLE_IDENTIFIER = com.dsignal.Gravity; 389 | PRODUCT_NAME = Gravity; 390 | PROVISIONING_PROFILE_SPECIFIER = ""; 391 | SDKROOT = macosx; 392 | SWIFT_VERSION = 5.0; 393 | }; 394 | name = Release; 395 | }; 396 | /* End XCBuildConfiguration section */ 397 | 398 | /* Begin XCConfigurationList section */ 399 | D1FF988C257D7116004ECE90 /* Build configuration list for PBXProject "Gravity" */ = { 400 | isa = XCConfigurationList; 401 | buildConfigurations = ( 402 | D1FF98A7257D7119004ECE90 /* Debug */, 403 | D1FF98A8257D7119004ECE90 /* Release */, 404 | ); 405 | defaultConfigurationIsVisible = 0; 406 | defaultConfigurationName = Release; 407 | }; 408 | D1FF98AC257D7119004ECE90 /* Build configuration list for PBXNativeTarget "Gravity (macOS)" */ = { 409 | isa = XCConfigurationList; 410 | buildConfigurations = ( 411 | D1FF98AD257D7119004ECE90 /* Debug */, 412 | D1FF98AE257D7119004ECE90 /* Release */, 413 | ); 414 | defaultConfigurationIsVisible = 0; 415 | defaultConfigurationName = Release; 416 | }; 417 | /* End XCConfigurationList section */ 418 | 419 | /* Begin XCRemoteSwiftPackageReference section */ 420 | D12CBCCE2586BA0D00AB2B1B /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = { 421 | isa = XCRemoteSwiftPackageReference; 422 | repositoryURL = "https://github.com/pointfreeco/swift-composable-architecture.git"; 423 | requirement = { 424 | kind = upToNextMinorVersion; 425 | minimumVersion = 0.39.0; 426 | }; 427 | }; 428 | D1FF98B1257D725D004ECE90 /* XCRemoteSwiftPackageReference "WasmTransformer" */ = { 429 | isa = XCRemoteSwiftPackageReference; 430 | repositoryURL = "https://github.com/swiftwasm/WasmTransformer.git"; 431 | requirement = { 432 | kind = upToNextMinorVersion; 433 | minimumVersion = 0.4.0; 434 | }; 435 | }; 436 | /* End XCRemoteSwiftPackageReference section */ 437 | 438 | /* Begin XCSwiftPackageProductDependency section */ 439 | D12CBCCF2586BA0D00AB2B1B /* ComposableArchitecture */ = { 440 | isa = XCSwiftPackageProductDependency; 441 | package = D12CBCCE2586BA0D00AB2B1B /* XCRemoteSwiftPackageReference "swift-composable-architecture" */; 442 | productName = ComposableArchitecture; 443 | }; 444 | D1FF98B2257D725D004ECE90 /* WasmTransformer */ = { 445 | isa = XCSwiftPackageProductDependency; 446 | package = D1FF98B1257D725D004ECE90 /* XCRemoteSwiftPackageReference "WasmTransformer" */; 447 | productName = WasmTransformer; 448 | }; 449 | /* End XCSwiftPackageProductDependency section */ 450 | }; 451 | rootObject = D1FF9889257D7116004ECE90 /* Project object */; 452 | } 453 | -------------------------------------------------------------------------------- /Gravity.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Gravity.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Gravity.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "combine-schedulers", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/pointfreeco/combine-schedulers", 7 | "state" : { 8 | "revision" : "f7c8277f05f27a5bfb2f6ecccb0bad126ffcf472", 9 | "version" : "0.7.0" 10 | } 11 | }, 12 | { 13 | "identity" : "swift-case-paths", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/pointfreeco/swift-case-paths", 16 | "state" : { 17 | "revision" : "ce9c0d897db8a840c39de64caaa9b60119cf4be8", 18 | "version" : "0.8.1" 19 | } 20 | }, 21 | { 22 | "identity" : "swift-collections", 23 | "kind" : "remoteSourceControl", 24 | "location" : "https://github.com/apple/swift-collections", 25 | "state" : { 26 | "revision" : "48254824bb4248676bf7ce56014ff57b142b77eb", 27 | "version" : "1.0.2" 28 | } 29 | }, 30 | { 31 | "identity" : "swift-composable-architecture", 32 | "kind" : "remoteSourceControl", 33 | "location" : "https://github.com/pointfreeco/swift-composable-architecture.git", 34 | "state" : { 35 | "revision" : "108e3a536fcebb16c4f247ef92c2d7326baf9fe3", 36 | "version" : "0.39.0" 37 | } 38 | }, 39 | { 40 | "identity" : "swift-custom-dump", 41 | "kind" : "remoteSourceControl", 42 | "location" : "https://github.com/pointfreeco/swift-custom-dump", 43 | "state" : { 44 | "revision" : "c4f78db9b90ca57b7b6abc2223e235242739ea3c", 45 | "version" : "0.4.0" 46 | } 47 | }, 48 | { 49 | "identity" : "swift-identified-collections", 50 | "kind" : "remoteSourceControl", 51 | "location" : "https://github.com/pointfreeco/swift-identified-collections", 52 | "state" : { 53 | "revision" : "680bf440178a78a627b1c2c64c0855f6523ad5b9", 54 | "version" : "0.3.2" 55 | } 56 | }, 57 | { 58 | "identity" : "wasmtransformer", 59 | "kind" : "remoteSourceControl", 60 | "location" : "https://github.com/swiftwasm/WasmTransformer.git", 61 | "state" : { 62 | "revision" : "b65e7c5f062b8959ce159aa4e1c4bb8d7938e941", 63 | "version" : "0.4.0" 64 | } 65 | }, 66 | { 67 | "identity" : "xctest-dynamic-overlay", 68 | "kind" : "remoteSourceControl", 69 | "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", 70 | "state" : { 71 | "revision" : "38bc9242e4388b80bd23ddfdf3071428859e3260", 72 | "version" : "0.4.0" 73 | } 74 | } 75 | ], 76 | "version" : 2 77 | } 78 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020 Gravity contributors 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gravity 2 | 3 | Binary code size profiler for WebAssembly built with [WasmTransformer](https://github.com/swiftwasm/WasmTransformer), [SwiftUI](https://developer.apple.com/xcode/swiftui/), and [TCA](https://github.com/pointfreeco/swift-composable-architecture/). 4 | 5 | While it is not fully implemented yet, the goal of the app is to pinpoint biggest sections and functions in your binaries built with [SwiftWasm](https://swiftwasm.org). Star and watch for updates! 6 | -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | }, 93 | { 94 | "idiom" : "mac", 95 | "scale" : "1x", 96 | "size" : "16x16" 97 | }, 98 | { 99 | "idiom" : "mac", 100 | "scale" : "2x", 101 | "size" : "16x16" 102 | }, 103 | { 104 | "idiom" : "mac", 105 | "scale" : "1x", 106 | "size" : "32x32" 107 | }, 108 | { 109 | "idiom" : "mac", 110 | "scale" : "2x", 111 | "size" : "32x32" 112 | }, 113 | { 114 | "idiom" : "mac", 115 | "scale" : "1x", 116 | "size" : "128x128" 117 | }, 118 | { 119 | "idiom" : "mac", 120 | "scale" : "2x", 121 | "size" : "128x128" 122 | }, 123 | { 124 | "idiom" : "mac", 125 | "scale" : "1x", 126 | "size" : "256x256" 127 | }, 128 | { 129 | "idiom" : "mac", 130 | "scale" : "2x", 131 | "size" : "256x256" 132 | }, 133 | { 134 | "idiom" : "mac", 135 | "scale" : "1x", 136 | "size" : "512x512" 137 | }, 138 | { 139 | "idiom" : "mac", 140 | "scale" : "2x", 141 | "size" : "512x512" 142 | } 143 | ], 144 | "info" : { 145 | "author" : "xcode", 146 | "version" : 1 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Shared/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Shared/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // Shared 4 | // 5 | // Created by Max Desiatov on 06/12/2020. 6 | // 7 | 8 | import ComposableArchitecture 9 | import SwiftUI 10 | 11 | let measurementFormatter: MeasurementFormatter = { 12 | let result = MeasurementFormatter() 13 | result.unitStyle = .short 14 | result.unitOptions = [.naturalScale] 15 | return result 16 | }() 17 | 18 | struct ContentView: View { 19 | let store: RootStore 20 | 21 | var body: some View { 22 | WithViewStore(store) { viewStore in 23 | if let file = viewStore.openedFile { 24 | NavigationView { 25 | VStack { 26 | Text("Total size: \(file.totalSize, formatter: measurementFormatter)") 27 | List(file.sections, id: \.startOffset) { section in 28 | if let id = file.sections.firstIndex(where: { $0.startOffset == section.startOffset }) { 29 | NavigationLink(destination: SectionDetails(file: file, sectionID: id)) { 30 | SectionItem(section: section) 31 | } 32 | } 33 | } 34 | }.frame(width: 200) 35 | } 36 | } else { 37 | HStack { 38 | Spacer() 39 | VStack { 40 | Spacer() 41 | Button("Open...") { 42 | viewStore.send(.openFile) 43 | } 44 | Spacer() 45 | } 46 | Spacer() 47 | } 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Shared/Environment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Environment.swift 3 | // Gravity 4 | // 5 | // Created by Max Desiatov on 14/12/2020. 6 | // 7 | 8 | import AppKit 9 | import Combine 10 | import ComposableArchitecture 11 | import Dispatch 12 | import WasmTransformer 13 | 14 | private let profilerQueue = DispatchQueue.global(qos: .userInitiated) 15 | 16 | let rootEnvironment = RootEnvironment( 17 | mainQueue: DispatchQueue.main.eraseToAnyScheduler(), 18 | openFile: { 19 | .future { promise in 20 | let openPanel = NSOpenPanel() 21 | openPanel.allowedFileTypes = ["wasm"] 22 | openPanel.canChooseFiles = true 23 | openPanel.begin { result in 24 | if result == .OK { 25 | if let url = openPanel.url { 26 | promise(.success(url)) 27 | } 28 | } else if result == .cancel { 29 | promise(.success(nil)) 30 | } 31 | } 32 | } 33 | }, 34 | profile: { url in 35 | Just(url) 36 | .tryMap { 37 | try .init(filename: url.lastPathComponent, data: Data(contentsOf: $0)) 38 | } 39 | .subscribe(on: profilerQueue) 40 | .eraseToEffect() 41 | } 42 | ) 43 | -------------------------------------------------------------------------------- /Shared/GravityApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GravityApp.swift 3 | // Shared 4 | // 5 | // Created by Max Desiatov on 06/12/2020. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct GravityApp: App { 12 | var body: some Scene { 13 | DocumentGroup(viewing: WasmDocument.self) { 14 | ContentView( 15 | store: .init( 16 | initialState: .init(openedFile: $0.document), 17 | reducer: rootReducer, 18 | environment: rootEnvironment 19 | ) 20 | ) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Shared/SectionDetails/CodeSectionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodeSectionView.swift 3 | // Gravity (macOS) 4 | // 5 | // Created by Max Desiatov on 10/08/2022. 6 | // 7 | 8 | import SwiftUI 9 | import WasmTransformer 10 | 11 | private enum FunctionOrder: String, CaseIterable, Identifiable, CustomStringConvertible { 12 | case index 13 | case size 14 | 15 | var id: String { rawValue } 16 | 17 | var description: String { 18 | rawValue 19 | } 20 | } 21 | 22 | struct CodeSectionView: View { 23 | let codeSection: CodeSection 24 | 25 | @State private var orderSelection = FunctionOrder.index 26 | 27 | @ScaledMetric var functionSizeTextWidth = 80 28 | 29 | var body: some View { 30 | VStack { 31 | Picker("Order by", selection: $orderSelection) { 32 | ForEach(FunctionOrder.allCases) { 33 | Text($0.description).tag($0) 34 | } 35 | } 36 | .pickerStyle(SegmentedPickerStyle()) 37 | .padding([.horizontal, .bottom]) 38 | 39 | ScrollView { 40 | LazyVStack(alignment: .leading) { 41 | ForEach( 42 | orderSelection == .index ? 43 | codeSection.functions : codeSection.functions.sorted { $0.body.size > $1.body.size } 44 | ) { item in 45 | HStack { 46 | Text("\(item.sizeMeasurement, formatter: measurementFormatter)") 47 | .frame(width: functionSizeTextWidth, alignment: .trailing) 48 | Text(item.name) 49 | .font( 50 | .body 51 | .monospaced() 52 | ) 53 | } 54 | .padding(.horizontal) 55 | .padding(.vertical, 3) 56 | } 57 | }.padding() 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Shared/SectionDetails/FuncSectionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FuncSectionView.swift 3 | // Gravity 4 | // 5 | // Created by Max Desiatov on 16/12/2020. 6 | // 7 | 8 | import SwiftUI 9 | import WasmTransformer 10 | 11 | struct FuncSectionView: View { 12 | private struct Function: Identifiable { 13 | let id: Int 14 | let signature: FuncSignature 15 | let name: String 16 | } 17 | 18 | init(typeSection: TypeSection, funcSection: FuncSection, nameSection: NameSection) { 19 | functions = funcSection.typeIndices.enumerated().map { 20 | .init( 21 | id: $0, 22 | signature: typeSection.signatures[Int($1)], 23 | name: nameSection.functionNames[$0] ?? "\($0)" 24 | ) 25 | } 26 | } 27 | 28 | private let functions: [Function] 29 | 30 | @State private var orderSelection = FunctionsWithParametersOrder.index 31 | 32 | var body: some View { 33 | VStack { 34 | Picker("Order by", selection: $orderSelection) { 35 | ForEach(FunctionsWithParametersOrder.allCases) { 36 | Text($0.description).tag($0) 37 | } 38 | } 39 | .pickerStyle(SegmentedPickerStyle()) 40 | .padding([.horizontal, .bottom]) 41 | 42 | ScrollView { 43 | LazyVStack { 44 | ForEach( 45 | orderSelection == .index ? 46 | functions : 47 | functions.sorted { $0.signature.params.count > $1.signature.params.count } 48 | ) { f in 49 | HStack { 50 | Text(f.name).font(.headline) 51 | Spacer() 52 | Text(f.signature.description) 53 | } 54 | .padding(.horizontal) 55 | .padding(.vertical, 2) 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Shared/SectionDetails/NameSectionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NameSectionView.swift 3 | // Gravity 4 | // 5 | // Created by Max Desiatov on 15/12/2020. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct NameSectionView: View { 11 | let section: NameSection 12 | 13 | var body: some View { 14 | VStack { 15 | if let name = section.moduleName { 16 | Text(name) 17 | .font(.headline) 18 | .padding() 19 | } 20 | 21 | ScrollView { 22 | LazyVStack(alignment: .leading) { 23 | ForEach( 24 | section.functionNames.map { ($0, $1) }, 25 | id: \.0 26 | ) { idx, name in 27 | HStack { 28 | Text("\(idx)") 29 | .frame(width: 100) 30 | Text(name) 31 | } 32 | } 33 | }.padding() 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Shared/SectionDetails/RawSectionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Max Desiatov on 15/12/2020. 3 | // 4 | 5 | import SwiftUI 6 | import WasmTransformer 7 | 8 | struct RawSectionView: View { 9 | let bytes: ArraySlice 10 | 11 | private let symbolWidth: CGFloat = 16 12 | 13 | var body: some View { 14 | GeometryReader { proxy in 15 | let symbols = proxy.size.width < symbolWidth ? 1 : Int(proxy.size.width / symbolWidth) 16 | 17 | ScrollView { 18 | LazyVStack(alignment: .leading) { 19 | ForEach( 20 | Array(stride(from: bytes.startIndex, to: bytes.endIndex, by: symbols)), 21 | id: \.self 22 | ) { 23 | Text(bytes[$0.. String { 18 | let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx" 19 | return map { String(format: format, $0) }.joined() 20 | } 21 | } 22 | 23 | extension SectionInfo { 24 | public func description(customSectionName: String?) -> String { 25 | switch type { 26 | case .custom: 27 | if let name = customSectionName { 28 | return "Custom section named: `\(name)`" 29 | } else { 30 | return "Unnamed custom section" 31 | } 32 | 33 | case .type: 34 | return "Types section" 35 | 36 | case .function: 37 | return "Functions to types mapping section" 38 | 39 | case .code: 40 | return "Code section" 41 | 42 | case .global: 43 | return "Globals section" 44 | 45 | case .import: 46 | return "Imports section" 47 | 48 | case .export: 49 | return "Exports section" 50 | 51 | case .data: 52 | return "Data segments section" 53 | 54 | default: 55 | return "Unknown section" 56 | } 57 | } 58 | } 59 | 60 | struct SectionDetails: View { 61 | let file: WasmDocument 62 | let sectionID: Int 63 | 64 | private func customSectionName(_ section: SectionInfo) -> String? { 65 | var input = file.input 66 | input.seek(section.endOffset - section.size) 67 | return input.readName() 68 | } 69 | 70 | var body: some View { 71 | let section = file.sections[sectionID] 72 | VStack { 73 | let name = customSectionName(section) 74 | Text(try! AttributedString(markdown: section.description(customSectionName: name))) 75 | .font(.headline) 76 | .padding() 77 | 78 | switch section.type { 79 | case .type: 80 | TypeSectionView(signatures: file.typeSection.signatures) 81 | case .function: 82 | if let nameSection = file.nameSection { 83 | FuncSectionView( 84 | typeSection: file.typeSection, 85 | funcSection: file.funcSection, 86 | nameSection: nameSection 87 | ) 88 | } else { 89 | RawSectionView(bytes: file.input.bytes[section.startOffset.. $1.params.count }, 50 | id: \.self 51 | ) { 52 | Text($0.description) 53 | .padding(.horizontal) 54 | } 55 | }.padding() 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Shared/SectionItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SectionItem.swift 3 | // Gravity 4 | // 5 | // Created by Max Desiatov on 14/12/2020. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | import WasmTransformer 11 | 12 | extension SectionType: CustomStringConvertible { 13 | public var description: String { 14 | switch self { 15 | case .code: return "code" 16 | case .custom: return "custom" 17 | case .data: return "data" 18 | case .dataCount: return "dataCount" 19 | case .element: return "elem" 20 | case .export: return "export" 21 | case .function: return "function" 22 | case .global: return "global" 23 | case .import: return "import" 24 | case .type: return "type" 25 | case .table: return "table" 26 | case .memory: return "memory" 27 | case .start: return "start" 28 | } 29 | } 30 | } 31 | 32 | extension SectionInfo { 33 | var sizeMeasurement: Measurement { 34 | .init(value: Double(size), unit: .bytes) 35 | } 36 | } 37 | 38 | struct SectionItem: View { 39 | let section: SectionInfo 40 | 41 | var body: some View { 42 | HStack { 43 | Text(section.type.description) 44 | Spacer() 45 | Text("\(section.sizeMeasurement, formatter: measurementFormatter)") 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Shared/State.swift: -------------------------------------------------------------------------------- 1 | // 2 | // State.swift 3 | // Gravity 4 | // 5 | // Created by Max Desiatov on 13/12/2020. 6 | // 7 | 8 | import ComposableArchitecture 9 | import Combine 10 | 11 | struct RootState: Equatable { 12 | var openedFile: WasmDocument? 13 | var isLoading = false 14 | 15 | var alert: AlertState? 16 | } 17 | 18 | extension AlertState { 19 | init(_ error: Error) { 20 | self.init( 21 | title: .init((error as? LocalizedError)?.errorDescription ?? error.localizedDescription) 22 | ) 23 | } 24 | } 25 | 26 | enum AlertAction { 27 | case dismiss 28 | } 29 | 30 | enum RootAction { 31 | case openFile 32 | case openFileResponse(URL?) 33 | case profilerResponse(Result) 34 | case alert(AlertAction) 35 | } 36 | 37 | typealias RootStore = Store 38 | 39 | struct RootEnvironment { 40 | let mainQueue: AnySchedulerOf 41 | let openFile: () -> Effect 42 | let profile: (URL) -> Effect 43 | } 44 | 45 | let rootReducer = Reducer { state, action, environment in 46 | switch action { 47 | case .openFile: 48 | return environment.openFile() 49 | .receive(on: environment.mainQueue) 50 | .map(RootAction.openFileResponse) 51 | .eraseToEffect() 52 | 53 | case let .openFileResponse(url?): 54 | state.isLoading = false 55 | return environment.profile(url) 56 | .receive(on: environment.mainQueue) 57 | .catchToEffect() 58 | .map(RootAction.profilerResponse) 59 | 60 | case .openFileResponse(nil): 61 | return .none 62 | 63 | case let .profilerResponse(.success(file)): 64 | state.openedFile = file 65 | state.isLoading = false 66 | return .none 67 | 68 | case let .profilerResponse(.failure(error)): 69 | state.alert = .init(error) 70 | state.isLoading = false 71 | return .none 72 | 73 | case .alert(.dismiss): 74 | state.alert = nil 75 | return .none 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Shared/Wasm/CodeSection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodeSection.swift 3 | // Gravity (macOS) 4 | // 5 | // Created by Max Desiatov on 10/08/2022. 6 | // 7 | 8 | import Foundation 9 | import WasmTransformer 10 | 11 | struct CodeSection: Equatable { 12 | struct Item: Identifiable, Equatable { 13 | let id: Int 14 | let name: String 15 | let body: FunctionBody 16 | 17 | var sizeMeasurement: Measurement { 18 | .init(value: Double(body.size), unit: .bytes) 19 | } 20 | } 21 | 22 | let functions: [Item] 23 | } 24 | -------------------------------------------------------------------------------- /Shared/Wasm/FuncSection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FuncSection.swift 3 | // Gravity 4 | // 5 | // Created by Max Desiatov on 16/12/2020. 6 | // 7 | 8 | import WasmTransformer 9 | 10 | /// https://webassembly.github.io/spec/core/binary/modules.html#function-section 11 | struct FuncSection: Equatable { 12 | let typeIndices: [UInt32] 13 | } 14 | -------------------------------------------------------------------------------- /Shared/Wasm/NameSection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NameSection.swift 3 | // Gravity 4 | // 5 | // Created by Max Desiatov on 15/12/2020. 6 | // 7 | 8 | import Darwin 9 | import WasmTransformer 10 | 11 | @_silgen_name("swift_demangle") 12 | public func _stdlib_demangleImplementation( 13 | mangledName: UnsafePointer?, 14 | mangledNameLength: UInt, 15 | outputBuffer: UnsafeMutablePointer?, 16 | outputBufferSize: UnsafeMutablePointer?, 17 | flags: UInt32 18 | ) -> UnsafeMutablePointer? 19 | 20 | func demangle(_ mangledName: String) -> String { 21 | mangledName.utf8CString.withUnsafeBufferPointer { mangledNameUTF8CStr in 22 | let demangledNamePtr = _stdlib_demangleImplementation( 23 | mangledName: mangledNameUTF8CStr.baseAddress, 24 | mangledNameLength: UInt(mangledNameUTF8CStr.count - 1), 25 | outputBuffer: nil, 26 | outputBufferSize: nil, 27 | flags: 0 28 | ) 29 | 30 | if let demangledNamePtr = demangledNamePtr { 31 | let demangledName = String(cString: demangledNamePtr) 32 | free(demangledNamePtr) 33 | return demangledName 34 | .replacingOccurrences(of: " Swift.", with: " ") 35 | .replacingOccurrences(of: "(Swift.", with: "(") 36 | .replacingOccurrences(of: " String? { 45 | let length = Int(readVarUInt32()) 46 | let bytes = read(length) 47 | return String(bytes: bytes, encoding: .utf8) 48 | } 49 | 50 | mutating func readNamesMapSubsection(_ dictionary: inout [Int: String]) { 51 | let count = readVarUInt32() 52 | for _ in 0.. Bool { 20 | lhs.bytes == rhs.bytes && lhs.offset == rhs.offset 21 | } 22 | } 23 | 24 | extension FuncSignature: Equatable { 25 | public static func ==(lhs: FuncSignature, rhs: FuncSignature) -> Bool { 26 | lhs.params == rhs.params && lhs.results == rhs.results 27 | } 28 | } 29 | 30 | extension FunctionBody: Equatable { 31 | public static func ==(lhs: FunctionBody, rhs: FunctionBody) -> Bool { 32 | lhs.input == rhs.input && lhs.size == rhs.size && lhs.endOffset == rhs.endOffset 33 | } 34 | } 35 | 36 | extension FuncSignature: Hashable { 37 | public func hash(into hasher: inout Hasher) { 38 | hasher.combine(params) 39 | hasher.combine(results) 40 | } 41 | } 42 | 43 | struct WasmDocument: FileDocument, Equatable { 44 | init( 45 | filename: String, 46 | data: Data 47 | ) throws { 48 | self.filename = filename 49 | totalSize = .init(value: Double(data.count), unit: .bytes) 50 | input = .init(bytes: [UInt8](data)) 51 | sections = try input.readSectionsInfo() 52 | input.seek(8) 53 | 54 | var moduleReader = ModuleReader(input: input) 55 | 56 | var maybeTypeSection: TypeSection? 57 | var maybeFuncSection: FuncSection? 58 | var maybeFunctionBodies: [FunctionBody]? 59 | 60 | var sectionIndex = 0 61 | while !moduleReader.isEOF { 62 | defer { 63 | sectionIndex += 1 64 | } 65 | 66 | switch try moduleReader.readSection() { 67 | case .type(let reader): 68 | maybeTypeSection = try TypeSection(signatures: reader.collect()) 69 | 70 | case .rawSection(type: .custom, content: let content): 71 | var input = InputByteStream(bytes: content) 72 | 73 | if let name = input.readName(), name == "name" { 74 | input.seek(sections[sectionIndex].contentStart) 75 | nameSection = try NameSection(&input) 76 | } 77 | 78 | case .function(let reader): 79 | maybeFuncSection = try FuncSection(typeIndices: reader.collect().map(\.value)) 80 | 81 | case .code(let reader): 82 | maybeFunctionBodies = try reader.collect() 83 | default: 84 | continue 85 | } 86 | } 87 | 88 | guard let typeSection = maybeTypeSection 89 | else { throw Error.requiredSectionAbsent(.type) } 90 | guard let funcSection = maybeFuncSection 91 | else { throw Error.requiredSectionAbsent(.function) } 92 | guard let functionBodies = maybeFunctionBodies 93 | else { throw Error.requiredSectionAbsent(.code) } 94 | 95 | self.typeSection = typeSection 96 | self.funcSection = funcSection 97 | if let nameSection = nameSection { 98 | self.codeSection = CodeSection( 99 | functions: functionBodies.enumerated().compactMap { 100 | guard let name = nameSection.functionNames[$0] else { return nil } 101 | 102 | return CodeSection.Item(id: $0, name: name, body: $1) 103 | } 104 | ) 105 | } else { 106 | codeSection = CodeSection(functions: []) 107 | } 108 | } 109 | 110 | enum Error: Swift.Error { 111 | case readFailure 112 | case requiredSectionAbsent(SectionType) 113 | } 114 | 115 | let filename: String 116 | let totalSize: Measurement 117 | var input: InputByteStream 118 | let sections: [SectionInfo] 119 | let typeSection: TypeSection 120 | let funcSection: FuncSection 121 | let codeSection: CodeSection 122 | 123 | private(set) var nameSection: NameSection? 124 | 125 | static let readableContentTypes = [UTType.wasm] 126 | 127 | init(configuration: ReadConfiguration) throws { 128 | guard 129 | configuration.contentType.identifier == UTType.wasm.identifier, 130 | let filename = configuration.file.filename, 131 | let data = configuration.file.regularFileContents 132 | else { 133 | throw Error.readFailure 134 | } 135 | 136 | try self.init(filename: filename, data: data) 137 | } 138 | 139 | func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { 140 | .init(regularFileWithContents: Data(input.bytes)) 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /macOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDocumentTypes 8 | 9 | 10 | CFBundleTypeIconSystemGenerated 11 | 1 12 | CFBundleTypeName 13 | WebAssembly 14 | CFBundleTypeRole 15 | Viewer 16 | LSHandlerRank 17 | Default 18 | LSItemContentTypes 19 | 20 | public.wasm 21 | 22 | 23 | 24 | CFBundleExecutable 25 | $(EXECUTABLE_NAME) 26 | CFBundleIconFile 27 | 28 | CFBundleIdentifier 29 | $(PRODUCT_BUNDLE_IDENTIFIER) 30 | CFBundleInfoDictionaryVersion 31 | 6.0 32 | CFBundleName 33 | $(PRODUCT_NAME) 34 | CFBundlePackageType 35 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 36 | CFBundleShortVersionString 37 | 1.0 38 | CFBundleVersion 39 | 1 40 | LSMinimumSystemVersion 41 | $(MACOSX_DEPLOYMENT_TARGET) 42 | UTImportedTypeDeclarations 43 | 44 | 45 | UTTypeConformsTo 46 | 47 | public.data 48 | 49 | UTTypeDescription 50 | WebAssembly 51 | UTTypeIcons 52 | 53 | UTTypeIdentifier 54 | public.wasm 55 | UTTypeTagSpecification 56 | 57 | public.filename-extension 58 | 59 | wasm 60 | 61 | public.mime-type 62 | 63 | application/wasm 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /macOS/macOS.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | --------------------------------------------------------------------------------