├── .gitignore ├── .swift-version ├── Config ├── app.json ├── crypto.json ├── droplet.json └── server.json ├── Package.pins ├── Package.resolved ├── Package.swift ├── Procfile ├── Public ├── images │ ├── Card.png │ ├── Icon_120x120.png │ ├── Icon_152x152.png │ ├── Icon_167x167.png │ ├── Icon_16x16.png │ ├── Icon_180x180.png │ ├── Icon_32x32.png │ ├── Icon_523x523.png │ ├── Icon_550x550.png │ ├── Icon_96x96.png │ └── wtf-logo.svg └── styles │ └── main.css ├── README.md ├── Resources └── Views │ ├── about.leaf │ ├── base.leaf │ ├── hero.leaf │ ├── input.leaf │ ├── output.leaf │ └── page.leaf ├── Sources ├── App │ ├── Controllers │ │ └── OutputController.swift │ ├── Models │ │ ├── Errors │ │ │ └── InvalidConstraintError.swift │ │ ├── ModelRepresentations │ │ │ ├── HtmlDescriptions.swift │ │ │ ├── LeafNodes.swift │ │ │ └── NumberFormatter.swift │ │ ├── Parser Models │ │ │ ├── Attribute.swift │ │ │ ├── Color.swift │ │ │ ├── Constant.swift │ │ │ ├── Constraint.swift │ │ │ ├── ConstraintGroup.swift │ │ │ ├── Footnote.swift │ │ │ ├── Instance.swift │ │ │ └── Multiplier.swift │ │ └── Requests │ │ │ └── ConstraintLogRequest.swift │ ├── Parsing │ │ ├── ConstraintsParser+AutoLayoutPrimitives.swift │ │ ├── ConstraintsParser+EquationConstraint.swift │ │ ├── ConstraintsParser+Examples.swift │ │ ├── ConstraintsParser+Info.swift │ │ ├── ConstraintsParser+Instances.swift │ │ ├── ConstraintsParser+Primitives.swift │ │ ├── ConstraintsParser+VFLConstraint.swift │ │ ├── ConstraintsParser.swift │ │ └── Partials │ │ │ ├── AnonymousConstraint.swift │ │ │ └── PartialInstance.swift │ ├── Routes.swift │ ├── SwiftExtensions │ │ ├── CharacterExtensions.swift │ │ ├── CharacterSetExtensions.swift │ │ └── StringExtensions.swift │ ├── app.swift │ ├── boot.swift │ └── configure.swift └── Run │ └── main.swift ├── TODO.md ├── Tests ├── AppTests │ ├── Application+Testing.swift │ ├── ColorTests.swift │ ├── Inputs │ │ ├── Input+Custom.swift │ │ ├── Input+Error.swift │ │ ├── Input+GitHubIssues.swift │ │ ├── Input+Papertrail.swift │ │ └── Input+StackOverflow.swift │ ├── ParserTests.swift │ ├── ViewTests.swift │ └── __Snapshots__ │ │ ├── ParserTests │ │ ├── testCustomInputs.1.json │ │ ├── testCustomInputs.2.json │ │ ├── testCustomInputs.3.json │ │ ├── testCustomInputs.4.json │ │ ├── testCustomInputs.5.json │ │ ├── testCustomInputs.6.json │ │ ├── testCustomInputs.7.json │ │ ├── testCustomInputs.8.json │ │ ├── testGitHubIssues.1.json │ │ ├── testGitHubIssues.2.json │ │ ├── testGitHubIssues.3.json │ │ ├── testGitHubIssues.4.json │ │ ├── testGitHubIssues.5.json │ │ ├── testGitHubIssues.6.json │ │ ├── testGitHubIssues.7.json │ │ ├── testGitHubIssues.8.json │ │ ├── testGitHubIssues.9.json │ │ ├── testStackOverflowInputs.1.json │ │ ├── testStackOverflowInputs.2.json │ │ ├── testStackOverflowInputs.3.json │ │ └── testStackOverflowInputs.4.json │ │ └── ViewTests │ │ ├── testAbout.1.txt │ │ ├── testHome.1.txt │ │ ├── testPostError.1.txt │ │ ├── testPostError.2.txt │ │ ├── testPostOutput.1.txt │ │ ├── testPostOutput.2.txt │ │ ├── testPostOutput.3.txt │ │ ├── testPostOutput.4.txt │ │ ├── testPostOutput.5.txt │ │ ├── testPostOutput.6.txt │ │ ├── testPostOutput.7.txt │ │ ├── testPostOutput.8.txt │ │ ├── testPostOutput.9.txt │ │ ├── testQueryOutput.1.txt │ │ ├── testQueryOutput.2.txt │ │ ├── testQueryOutput.3.txt │ │ ├── testQueryOutput.4.txt │ │ ├── testQueryOutput.5.txt │ │ ├── testQueryOutput.6.txt │ │ ├── testQueryOutput.7.txt │ │ └── testQueryOutput.8.txt └── LinuxMain.swift ├── circle.yml └── license /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ## MacOS ## 3 | .DS_Store 4 | 5 | ## Xcode ## 6 | DerivedData/ 7 | xcuserdata 8 | *.xcodeproj 9 | 10 | ## Swift Package Manager ## 11 | Packages 12 | .swiftpm 13 | .build 14 | 15 | ### Vapor ### 16 | Config/secrets 17 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.1 2 | -------------------------------------------------------------------------------- /Config/app.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /Config/crypto.json: -------------------------------------------------------------------------------- 1 | { 2 | "hash": { 3 | "method": "sha256", 4 | "encoding": "hex" 5 | }, 6 | 7 | "cipher": { 8 | "method": "aes256", 9 | "encoding": "base64", 10 | "key": "ACm9cvzBKVLbc3+yOhBoDnXIbPMGQ0M/GyvK/fAOmBQ=" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Config/droplet.json: -------------------------------------------------------------------------------- 1 | { 2 | "//": "The type of server to use for handling requests.", 3 | "//": "engine: Vapor's blazing fast Engine HTTP server.", 4 | "server": "engine", 5 | 6 | "//": "The type of client to use for requesting data from other services.", 7 | "//": "engine: Vapor's blazing fast Engine HTTP client.", 8 | "//": "foundation: A wrapper around Foundation's URLSession.", 9 | "client": "engine", 10 | 11 | "//": "The type of console to use for displaying information and prompting input.", 12 | "//": "terminal: Vapor's default terminal console.", 13 | "console": "terminal", 14 | 15 | "//": "The type of logger to use for recording logs, warnings, errors, etc.", 16 | "//": "console: Vapor's default logger sends logs directly to the chosen console.", 17 | "log": "console", 18 | 19 | "//": "The type of hasher to use for hashing messages.", 20 | "//": "crypto: Vapor's default hasher powered by OpenSSL (configure in crypto.json)", 21 | "//": "bcrypt: Performant BCrypt hashing implementation (configure in bcrypt.json)", 22 | "hash": "crypto", 23 | 24 | "//": "The type of cipher to use for encrypting and decrypting messages.", 25 | "//": "crypto: Vapor's default cipher powered by OpenSSL (configure in crypto.json)", 26 | "cipher": "crypto", 27 | 28 | "//": "The type of view renderer that drop.view will use", 29 | "//": "leaf: Pure Swift templating language created for Vapor.", 30 | "//": "static: Simply return the view at the supplied path", 31 | "view": "leaf", 32 | 33 | "//": "Choose which middleware are enabled (and in which order).", 34 | "//": "error: Catches errors thrown in your application and returns a nice response.", 35 | "//": "date: Adds the 'Date' header to HTTP requests.", 36 | "//": "file: Catches 404 errors and checks for files in the Public/ folder", 37 | "middleware": [ 38 | "error", 39 | "date", 40 | "file" 41 | ], 42 | 43 | "//": "Choose which commands this application can run", 44 | "commands": [] 45 | } 46 | -------------------------------------------------------------------------------- /Config/server.json: -------------------------------------------------------------------------------- 1 | { 2 | "//": "The $PORT:8080 call tells the json file to see if there", 3 | "//": "is any value at the 'PORT' environment variable.", 4 | "//": "If there is no value there, it will fallback to '8080'", 5 | "port": "$PORT:8080", 6 | 7 | "host": "0.0.0.0", 8 | 9 | "//": "It's very rare that a server manages its own TLS.", 10 | "//": "More commonly, vapor is served behind a proxy like nginx.", 11 | "securityLayer": "none" 12 | } 13 | -------------------------------------------------------------------------------- /Package.pins: -------------------------------------------------------------------------------- 1 | { 2 | "autoPin": true, 3 | "pins": [ 4 | { 5 | "package": "BCrypt", 6 | "reason": null, 7 | "repositoryURL": "https://github.com/vapor/bcrypt.git", 8 | "version": "1.1.0" 9 | }, 10 | { 11 | "package": "Bits", 12 | "reason": null, 13 | "repositoryURL": "https://github.com/vapor/bits.git", 14 | "version": "1.1.0" 15 | }, 16 | { 17 | "package": "CTLS", 18 | "reason": null, 19 | "repositoryURL": "https://github.com/vapor/ctls.git", 20 | "version": "1.1.1" 21 | }, 22 | { 23 | "package": "Console", 24 | "reason": null, 25 | "repositoryURL": "https://github.com/vapor/console.git", 26 | "version": "2.1.0" 27 | }, 28 | { 29 | "package": "Core", 30 | "reason": null, 31 | "repositoryURL": "https://github.com/vapor/core.git", 32 | "version": "2.1.2" 33 | }, 34 | { 35 | "package": "Crypto", 36 | "reason": null, 37 | "repositoryURL": "https://github.com/vapor/crypto.git", 38 | "version": "2.1.0" 39 | }, 40 | { 41 | "package": "Debugging", 42 | "reason": null, 43 | "repositoryURL": "https://github.com/vapor/debugging.git", 44 | "version": "1.1.0" 45 | }, 46 | { 47 | "package": "Engine", 48 | "reason": null, 49 | "repositoryURL": "https://github.com/vapor/engine.git", 50 | "version": "2.2.0" 51 | }, 52 | { 53 | "package": "JSON", 54 | "reason": null, 55 | "repositoryURL": "https://github.com/vapor/json.git", 56 | "version": "2.0.2" 57 | }, 58 | { 59 | "package": "Leaf", 60 | "reason": null, 61 | "repositoryURL": "https://github.com/vapor/leaf.git", 62 | "version": "2.0.1" 63 | }, 64 | { 65 | "package": "LeafProvider", 66 | "reason": null, 67 | "repositoryURL": "https://github.com/vapor/leaf-provider.git", 68 | "version": "1.1.0" 69 | }, 70 | { 71 | "package": "Multipart", 72 | "reason": null, 73 | "repositoryURL": "https://github.com/vapor/multipart.git", 74 | "version": "2.0.0" 75 | }, 76 | { 77 | "package": "Node", 78 | "reason": null, 79 | "repositoryURL": "https://github.com/vapor/node.git", 80 | "version": "2.0.4" 81 | }, 82 | { 83 | "package": "Random", 84 | "reason": null, 85 | "repositoryURL": "https://github.com/vapor/random.git", 86 | "version": "1.2.0" 87 | }, 88 | { 89 | "package": "Routing", 90 | "reason": null, 91 | "repositoryURL": "https://github.com/vapor/routing.git", 92 | "version": "2.0.1" 93 | }, 94 | { 95 | "package": "Sockets", 96 | "reason": null, 97 | "repositoryURL": "https://github.com/vapor/sockets.git", 98 | "version": "2.1.0" 99 | }, 100 | { 101 | "package": "Sparse", 102 | "reason": null, 103 | "repositoryURL": "https://github.com/johnpatrickmorgan/sparse.git", 104 | "version": "0.2.0" 105 | }, 106 | { 107 | "package": "TLS", 108 | "reason": null, 109 | "repositoryURL": "https://github.com/vapor/tls.git", 110 | "version": "2.1.0" 111 | }, 112 | { 113 | "package": "Vapor", 114 | "reason": null, 115 | "repositoryURL": "https://github.com/vapor/vapor.git", 116 | "version": "2.1.3" 117 | } 118 | ], 119 | "version": 1 120 | } -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "Console", 6 | "repositoryURL": "https://github.com/vapor/console.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "74cfbea629d4aac34a97cead2447a6870af1950b", 10 | "version": "3.1.1" 11 | } 12 | }, 13 | { 14 | "package": "Core", 15 | "repositoryURL": "https://github.com/vapor/core.git", 16 | "state": { 17 | "branch": null, 18 | "revision": "1782c550512dc5a43d0bca405e28fc386d932bbf", 19 | "version": "3.10.0" 20 | } 21 | }, 22 | { 23 | "package": "Crypto", 24 | "repositoryURL": "https://github.com/vapor/crypto.git", 25 | "state": { 26 | "branch": null, 27 | "revision": "105c2f875588bf40dd24c00cef3644bf8e327770", 28 | "version": "3.4.1" 29 | } 30 | }, 31 | { 32 | "package": "CwlCatchException", 33 | "repositoryURL": "https://github.com/mattgallagher/CwlCatchException.git", 34 | "state": { 35 | "branch": null, 36 | "revision": "7cd2f8cacc4d22f21bc0b2309c3b18acf7957b66", 37 | "version": "1.2.0" 38 | } 39 | }, 40 | { 41 | "package": "CwlPreconditionTesting", 42 | "repositoryURL": "https://github.com/mattgallagher/CwlPreconditionTesting.git", 43 | "state": { 44 | "branch": null, 45 | "revision": "c228db5d2ad1b01ebc84435e823e6cca4e3db98b", 46 | "version": "1.2.0" 47 | } 48 | }, 49 | { 50 | "package": "DatabaseKit", 51 | "repositoryURL": "https://github.com/vapor/database-kit.git", 52 | "state": { 53 | "branch": null, 54 | "revision": "8f352c8e66dab301ab9bfef912a01ce1361ba1e4", 55 | "version": "1.3.3" 56 | } 57 | }, 58 | { 59 | "package": "HTTP", 60 | "repositoryURL": "https://github.com/vapor/http.git", 61 | "state": { 62 | "branch": null, 63 | "revision": "0464b715a4b59f54078bcf7a4b424767b03db5a5", 64 | "version": "3.4.0" 65 | } 66 | }, 67 | { 68 | "package": "Leaf", 69 | "repositoryURL": "https://github.com/vapor/leaf.git", 70 | "state": { 71 | "branch": null, 72 | "revision": "d35f54cbac723e673f9bd5078361eea74049c8d7", 73 | "version": "3.0.2" 74 | } 75 | }, 76 | { 77 | "package": "Multipart", 78 | "repositoryURL": "https://github.com/vapor/multipart.git", 79 | "state": { 80 | "branch": null, 81 | "revision": "fb216c5a8ef07dcd90aec8a4155e86c831acce97", 82 | "version": "3.1.3" 83 | } 84 | }, 85 | { 86 | "package": "Nimble", 87 | "repositoryURL": "https://github.com/Quick/Nimble.git", 88 | "state": { 89 | "branch": null, 90 | "revision": "6abeb3f5c03beba2b9e4dbe20886e773b5b629b6", 91 | "version": "8.0.4" 92 | } 93 | }, 94 | { 95 | "package": "Quick", 96 | "repositoryURL": "https://github.com/Quick/Quick.git", 97 | "state": { 98 | "branch": null, 99 | "revision": "33682c2f6230c60614861dfc61df267e11a1602f", 100 | "version": "2.2.0" 101 | } 102 | }, 103 | { 104 | "package": "Routing", 105 | "repositoryURL": "https://github.com/vapor/routing.git", 106 | "state": { 107 | "branch": null, 108 | "revision": "d76f339c9716785e5079af9d7075d28ff7da3d92", 109 | "version": "3.1.0" 110 | } 111 | }, 112 | { 113 | "package": "Service", 114 | "repositoryURL": "https://github.com/vapor/service.git", 115 | "state": { 116 | "branch": null, 117 | "revision": "fa5b5de62bd68bcde9a69933f31319e46c7275fb", 118 | "version": "1.0.2" 119 | } 120 | }, 121 | { 122 | "package": "Sparse", 123 | "repositoryURL": "https://github.com/johnpatrickmorgan/sparse.git", 124 | "state": { 125 | "branch": "master", 126 | "revision": "7c360cc062cf14ee993c6de5b28e04f0892818ac", 127 | "version": null 128 | } 129 | }, 130 | { 131 | "package": "swift-nio", 132 | "repositoryURL": "https://github.com/apple/swift-nio.git", 133 | "state": { 134 | "branch": null, 135 | "revision": "8da5c5a4e6c5084c296b9f39dc54f00be146e0fa", 136 | "version": "1.14.2" 137 | } 138 | }, 139 | { 140 | "package": "swift-nio-ssl", 141 | "repositoryURL": "https://github.com/apple/swift-nio-ssl.git", 142 | "state": { 143 | "branch": null, 144 | "revision": "0f3999f3e3c359cc74480c292644c3419e44a12f", 145 | "version": "1.4.0" 146 | } 147 | }, 148 | { 149 | "package": "swift-nio-ssl-support", 150 | "repositoryURL": "https://github.com/apple/swift-nio-ssl-support.git", 151 | "state": { 152 | "branch": null, 153 | "revision": "c02eec4e0e6d351cd092938cf44195a8e669f555", 154 | "version": "1.0.0" 155 | } 156 | }, 157 | { 158 | "package": "swift-nio-zlib-support", 159 | "repositoryURL": "https://github.com/apple/swift-nio-zlib-support.git", 160 | "state": { 161 | "branch": null, 162 | "revision": "37760e9a52030bb9011972c5213c3350fa9d41fd", 163 | "version": "1.0.0" 164 | } 165 | }, 166 | { 167 | "package": "SnapshotTesting", 168 | "repositoryURL": "https://github.com/pointfreeco/swift-snapshot-testing.git", 169 | "state": { 170 | "branch": "master", 171 | "revision": "69d029ca721fed87c8a655377716c69ebe985e4f", 172 | "version": null 173 | } 174 | }, 175 | { 176 | "package": "TemplateKit", 177 | "repositoryURL": "https://github.com/vapor/template-kit.git", 178 | "state": { 179 | "branch": null, 180 | "revision": "4370aa99c01fc19cc8272b67bf7204b2d2063680", 181 | "version": "1.5.0" 182 | } 183 | }, 184 | { 185 | "package": "URLEncodedForm", 186 | "repositoryURL": "https://github.com/vapor/url-encoded-form.git", 187 | "state": { 188 | "branch": null, 189 | "revision": "20f68fbe7fac006d4d0617ea4edcba033227359e", 190 | "version": "1.1.0" 191 | } 192 | }, 193 | { 194 | "package": "Validation", 195 | "repositoryURL": "https://github.com/vapor/validation.git", 196 | "state": { 197 | "branch": null, 198 | "revision": "4de213cf319b694e4ce19e5339592601d4dd3ff6", 199 | "version": "2.1.1" 200 | } 201 | }, 202 | { 203 | "package": "Vapor", 204 | "repositoryURL": "https://github.com/vapor/vapor.git", 205 | "state": { 206 | "branch": null, 207 | "revision": "642f3d4d1f0eafad651c85524d0d1c698b55399f", 208 | "version": "3.3.3" 209 | } 210 | }, 211 | { 212 | "package": "WebSocket", 213 | "repositoryURL": "https://github.com/vapor/websocket.git", 214 | "state": { 215 | "branch": null, 216 | "revision": "d85e5b6dce4d04065865f77385fc3324f98178f6", 217 | "version": "1.1.2" 218 | } 219 | } 220 | ] 221 | }, 222 | "version": 1 223 | } 224 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "wtfautolayout", 6 | platforms: [ 7 | .macOS(.v10_13) 8 | ], 9 | dependencies: [ 10 | .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"), 11 | .package(url: "https://github.com/vapor/leaf.git", from: "3.0.0"), 12 | .package(url: "https://github.com/johnpatrickmorgan/sparse.git", .branch("master")), 13 | .package(url: "https://github.com/pointfreeco/swift-snapshot-testing.git", .branch("master")) 14 | ], 15 | targets: [ 16 | .target(name: "App", dependencies: ["Leaf", "Vapor", "Sparse"]), 17 | .target(name: "Run", dependencies: ["App"]), 18 | .testTarget(name: "AppTests", dependencies: ["App", "SnapshotTesting"]) 19 | ] 20 | ) 21 | 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: Run serve --env $ENVIRONMENT --hostname 0.0.0.0 --port $PORT 2 | -------------------------------------------------------------------------------- /Public/images/Card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnpatrickmorgan/wtfautolayout/d663a4ff425791f26ee972a1d794de6de307c409/Public/images/Card.png -------------------------------------------------------------------------------- /Public/images/Icon_120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnpatrickmorgan/wtfautolayout/d663a4ff425791f26ee972a1d794de6de307c409/Public/images/Icon_120x120.png -------------------------------------------------------------------------------- /Public/images/Icon_152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnpatrickmorgan/wtfautolayout/d663a4ff425791f26ee972a1d794de6de307c409/Public/images/Icon_152x152.png -------------------------------------------------------------------------------- /Public/images/Icon_167x167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnpatrickmorgan/wtfautolayout/d663a4ff425791f26ee972a1d794de6de307c409/Public/images/Icon_167x167.png -------------------------------------------------------------------------------- /Public/images/Icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnpatrickmorgan/wtfautolayout/d663a4ff425791f26ee972a1d794de6de307c409/Public/images/Icon_16x16.png -------------------------------------------------------------------------------- /Public/images/Icon_180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnpatrickmorgan/wtfautolayout/d663a4ff425791f26ee972a1d794de6de307c409/Public/images/Icon_180x180.png -------------------------------------------------------------------------------- /Public/images/Icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnpatrickmorgan/wtfautolayout/d663a4ff425791f26ee972a1d794de6de307c409/Public/images/Icon_32x32.png -------------------------------------------------------------------------------- /Public/images/Icon_523x523.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnpatrickmorgan/wtfautolayout/d663a4ff425791f26ee972a1d794de6de307c409/Public/images/Icon_523x523.png -------------------------------------------------------------------------------- /Public/images/Icon_550x550.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnpatrickmorgan/wtfautolayout/d663a4ff425791f26ee972a1d794de6de307c409/Public/images/Icon_550x550.png -------------------------------------------------------------------------------- /Public/images/Icon_96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnpatrickmorgan/wtfautolayout/d663a4ff425791f26ee972a1d794de6de307c409/Public/images/Icon_96x96.png -------------------------------------------------------------------------------- /Public/images/wtf-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Public/styles/main.css: -------------------------------------------------------------------------------- 1 | body, 2 | html { 3 | padding: 0; 4 | margin: 0; 5 | height: 100%; 6 | } 7 | 8 | body { 9 | background-color: #f0f0f0; 10 | } 11 | 12 | body, 13 | h1, 14 | h2, 15 | h3, 16 | h4, 17 | h5, 18 | p, 19 | a, 20 | .initial { 21 | font-family: 'Fira Sans', Helvetica, sans-serif; 22 | } 23 | 24 | h2 { 25 | font-size: 160%; 26 | font-weight: 200; 27 | line-height: 1.1; 28 | } 29 | 30 | h2 strong { 31 | font-weight: 300; 32 | } 33 | 34 | p { 35 | font-weight: 300; 36 | } 37 | 38 | p a { 39 | font-weight: 400; 40 | } 41 | 42 | code { 43 | font-family: 'Fira Mono', sans-serif; 44 | font-size: 90%; 45 | background: #F6F6F6; 46 | border-style: solid; 47 | border-color: #EEE; 48 | border-width: 1px; 49 | padding: 2px; 50 | font-weight: 300; 51 | } 52 | 53 | span { 54 | display: inline-block; 55 | vertical-align: middle; 56 | line-height: normal; 57 | } 58 | 59 | a { 60 | text-decoration: none; 61 | font-weight: 500; 62 | } 63 | 64 | a:hover { 65 | color: #777777; 66 | } 67 | 68 | textarea { 69 | width: 100%; 70 | resize: none; 71 | font-size: 85%; 72 | } 73 | 74 | footer { 75 | width: 100%; 76 | position: fixed; 77 | bottom: 0; 78 | } 79 | 80 | .mono { 81 | font-family: 'Fira Mono', sans-serif; 82 | } 83 | 84 | .main { 85 | max-width: 1024px; 86 | margin: auto; 87 | } 88 | 89 | .description { 90 | font-weight: 300; 91 | line-height: 1.75; 92 | margin: 8px; 93 | padding: 0px; 94 | flex-grow: 6; 95 | width: 320px; 96 | } 97 | 98 | .about { 99 | max-width: 800px; 100 | margin: auto; 101 | } 102 | 103 | .tab { 104 | font-weight: 400; 105 | } 106 | 107 | .logo { 108 | width: 100px; 109 | height: 100px; 110 | -webkit-transition: width 0.4s, height 0.4s, -webkit-transform 0.4s; 111 | -moz-transition: width 0.4s, height 0.4s, -moz-transform 0.4s; 112 | -o-transition: width 0.4s, height 0.4s, -o-transform 0.4s; 113 | -ms-transition: width 0.4s, height 0.4s, -ms-transform 0.4s; 114 | transition: width 0.4s, height 0.4s, transform 0.4s; 115 | } 116 | 117 | .logo:hover { 118 | width: 100px; 119 | height: 100px; 120 | -webkit-transform: rotate(-10deg); 121 | -moz-transform: rotate(-10deg); 122 | -o-transform: rotate(-10deg); 123 | -ms-transform: rotate(-10deg); 124 | transform: rotate(-10deg); 125 | } 126 | 127 | .flex-container { 128 | display: -webkit-flex; 129 | display: flex; 130 | -webkit-justify-content: center; 131 | justify-content: center; 132 | -webkit-align-items: center; 133 | align-items: center; 134 | } 135 | 136 | .bumf { 137 | font-size: 12px; 138 | margin-top: 0; 139 | margin: 0; 140 | padding: 0; 141 | -webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 1)), to(rgba(0, 0, 0, 0))); 142 | max-height: 150px; 143 | } 144 | 145 | .star-button { 146 | border-width: 0px; 147 | overflow: hidden; 148 | } 149 | 150 | .alert { 151 | white-space: nowrap; 152 | overflow: auto; 153 | } 154 | 155 | .row { 156 | background: #FF00FF; 157 | -webkit-justify-content: space-between; 158 | justify-content: space-between; 159 | -webkit-flex-wrap: wrap; 160 | flex-wrap: wrap; 161 | } 162 | 163 | .pictorial { 164 | flex-grow: 2; 165 | } 166 | 167 | .icon { 168 | margin: 0; 169 | padding: 0; 170 | } 171 | 172 | .diagram-line { 173 | stroke: #000000; 174 | stroke-linecap: square; 175 | stroke-width: 3px; 176 | } 177 | 178 | .initial { 179 | font-size: 55px; 180 | font-weight: 600; 181 | } 182 | 183 | .suffix { 184 | font-size: 18px; 185 | font-weight: 600; 186 | } 187 | 188 | .pictorial { 189 | min-width: 320px; 190 | } 191 | 192 | .relationship { 193 | font-size: 300%; 194 | font-weight: 600; 195 | } 196 | 197 | .constant, 198 | .multiplier { 199 | font-size: 200%; 200 | font-weight: 600; 201 | } 202 | 203 | .tooltip { 204 | position: absolute; 205 | left: 0; 206 | top: 65px; 207 | z-index: 12; 208 | text-align: left; 209 | background-color: #f4f9ff; 210 | } 211 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
19 | Auto Layout on iOS and macOS is awesome. But when it goes wrong, the error logs are a pain to decipher. 20 |
21 |22 | This site helps you visualize the conflicting constraints in the logs. It was built using Swift, Vapor and Sparse; and the source code is available on GitHub. If you found it useful, please give it a star. 23 |
24 | 25 |#(error)
#(footnote.marker) #get(footnote.text)
101 | } 102 | #if(permalink) { 103 | Permalink 104 | } 105 | } 106 | 107 | #embed("page") 108 | -------------------------------------------------------------------------------- /Resources/Views/page.leaf: -------------------------------------------------------------------------------- 1 | #set("body") { 2 | 3 | #get(definitions) 4 | 5 | 6 | 7 |\(layoutItem.prettyName)\(annotation?.uniquingSuffix ?? "")
's \(attribute.htmlDescription())"
30 | }
31 | }
32 |
33 | extension Attribute {
34 |
35 | func htmlDescription() -> String {
36 |
37 | switch self {
38 | case .leading: return "leading edge"
39 | case .trailing: return "trailing edge"
40 | case .top: return "top edge"
41 | case .bottom: return "bottom edge"
42 | case .centerX: return "horizontal center"
43 | case .centerY: return "vertical center"
44 | case .width: return "width"
45 | case .height: return "height"
46 | case .leadingMargin: return "leading margin"
47 | case .trailingMargin: return "trailing margin"
48 | case .topMargin: return "top margin"
49 | case .bottomMargin: return "bottom margin"
50 | case .centerXWithinMargins: return "horizontal center (within its margins)"
51 | case .centerYWithinMargins: return "vertical center (within its margins)"
52 | case .firstBaseline: return "first line of text's baseline"
53 | case .lastBaseline: return "last line of text's baseline"
54 | }
55 | }
56 | }
57 |
58 | extension Constraint.Relation {
59 |
60 | func htmlDescription() -> String {
61 | switch self {
62 | case .equal:
63 | return "should equal"
64 | case .lessThanOrEqual:
65 | return "should be at most"
66 | case .greaterThanOrEqual:
67 | return "should be at least"
68 | }
69 | }
70 | }
71 |
72 | extension Multiplier {
73 |
74 | func htmlDescription() -> String {
75 |
76 | return "multiplied by \(format(number: value, maximumFractionDigits: 3))"
77 | }
78 | }
79 |
80 | extension Constant {
81 |
82 | func htmlDescription(includePositivePrefix: Bool = false) -> String {
83 |
84 | let positivePrefix = includePositivePrefix ? "plus" : nil
85 | let prefix: String? = value == 0.0 ? nil : value > 0.0 ? positivePrefix : "minus"
86 | let number = format(number: abs(value))
87 |
88 | return [prefix, number].compactMap { $0 }.joined(separator: " ")
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Sources/App/Models/ModelRepresentations/LeafNodes.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Vapor
3 |
4 | private let maximumPermalinkLength = 2000
5 |
6 | extension ConstraintGroup {
7 |
8 | struct LeafNode: Codable {
9 | let constraints: [Constraint.LeafNode]
10 | let permalink: String?
11 | let footnotes: [Footnote.LeafNode]
12 | }
13 |
14 | func leafNode(includePermalink: Bool = false) -> LeafNode {
15 |
16 | var permalink: String? {
17 | let trimmed = raw.addingPercentEncoding(withAllowedCharacters: .urlQueryArgumentAllowed)
18 | return (trimmed?.count ?? 0) < maximumPermalinkLength ? trimmed : nil
19 | }
20 |
21 | return .init(
22 | constraints: constraints.map { $0.leafNode(annotations: annotations) },
23 | permalink: includePermalink ? permalink : nil,
24 | footnotes: footnotes.map { $0.leafNode() }
25 | )
26 | }
27 | }
28 |
29 | extension Constraint {
30 |
31 | struct LeafNode: Codable {
32 | let identity: Instance.LeafNode
33 | let first: LayoutItemAttribute.LeafNode
34 | let second: LayoutItemAttribute.LeafNode?
35 | let relation: Relation.LeafNode
36 | let constant: Constant.LeafNode?
37 | let multiplier: Multiplier.LeafNode
38 | let description: String
39 | let footnote: Footnote.LeafNode?
40 | }
41 |
42 | func leafNode(annotations: [Instance: Annotation]) -> LeafNode {
43 |
44 | let showConstant = constant.value != 0.0 || second == nil
45 | return .init(
46 | identity: identity.leafNode(),
47 | first: first.leafNode(annotation: annotations[first.layoutItem]),
48 | second: second?.leafNode(annotation: second.flatMap { annotations[$0.layoutItem] }),
49 | relation: relation.leafNode(),
50 | constant: showConstant ? constant.leafNode(includePositivePrefix: second != nil) : nil,
51 | multiplier: multiplier.leafNode(),
52 | description: htmlDescription(annotations: annotations),
53 | footnote: footnote?.leafNode()
54 | )
55 | }
56 | }
57 |
58 | extension LayoutItemAttribute {
59 |
60 | struct LeafNode: Codable {
61 | let instance: Instance.LeafNode
62 | let attribute: Attribute.LeafNode
63 | }
64 |
65 | func leafNode(annotation: Annotation?) -> LeafNode {
66 |
67 | return .init(
68 | instance: layoutItem.leafNode(annotation: annotation),
69 | attribute: attribute.leafNode()
70 | )
71 | }
72 | }
73 |
74 | extension Instance {
75 |
76 | struct LeafNode: Codable {
77 | let address: String
78 | let className: String
79 | let name: String
80 | let suffix: String?
81 | let color: Color.LeafNode
82 | let initial: String
83 | let identifier: String?
84 | }
85 |
86 | func leafNode(annotation: Annotation? = nil) -> LeafNode {
87 | let firstAlphanumeric = prettyName.unicodeScalars.first { CharacterSet.alphanumerics.contains($0) }
88 | let initial = firstAlphanumeric.map { String($0).uppercased() } ?? ""
89 | return .init(
90 | address: address,
91 | className: className,
92 | name: prettyName,
93 | suffix: annotation.map { $0.uniquingSuffix },
94 | color: (annotation?.color ?? .defaultColor).leafNode(),
95 | initial: initial,
96 | identifier: identifier
97 | )
98 | }
99 | }
100 |
101 | extension Attribute {
102 |
103 | struct LeafNode: Codable {
104 | let name: String
105 | let includesMargin: Bool
106 | }
107 |
108 | func leafNode() -> LeafNode {
109 |
110 | return .init(
111 | name: rawValue,
112 | includesMargin: includesMargin
113 | )
114 | }
115 | }
116 |
117 | extension Constraint.Relation {
118 |
119 | typealias LeafNode = String
120 |
121 | func leafNode() -> LeafNode {
122 | return rawValue
123 | }
124 | }
125 |
126 | extension Multiplier {
127 |
128 | typealias LeafNode = String?
129 |
130 | func leafNode() -> LeafNode {
131 | guard value != 1.0 else { return nil }
132 | return "* \(format(number: value, maximumFractionDigits: 3))"
133 | }
134 | }
135 |
136 | extension Constant {
137 |
138 | struct LeafNode: Codable {
139 | let value: String
140 | let prefix: String?
141 | }
142 |
143 | func leafNode(includePositivePrefix: Bool) -> LeafNode {
144 |
145 | return .init(
146 | value: format(number: abs(value)),
147 | prefix: value < 0 ? "- " : includePositivePrefix ? "+ " : nil
148 | )
149 | }
150 | }
151 |
152 | extension Color {
153 |
154 | typealias LeafNode = String
155 |
156 | func leafNode() -> LeafNode {
157 |
158 | return rgb
159 | }
160 | }
161 |
162 | extension Footnote {
163 |
164 | struct LeafNode: Codable {
165 | let marker: String
166 | let text: String
167 | }
168 |
169 | func leafNode() -> LeafNode {
170 |
171 | return .init(
172 | marker: marker,
173 | text: htmlText
174 | )
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/Sources/App/Models/ModelRepresentations/NumberFormatter.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | private let formatter = NumberFormatter()
4 |
5 | func format(number: Double, maximumFractionDigits: Int = 1) -> String {
6 |
7 | formatter.maximumFractionDigits = maximumFractionDigits
8 | formatter.minimumIntegerDigits = 1
9 | formatter.paddingPosition = .beforePrefix
10 | formatter.paddingCharacter = "0"
11 |
12 | return formatter.string(from: NSNumber(value: number)) ?? String(format: "%.1f", number)
13 | }
14 |
--------------------------------------------------------------------------------
/Sources/App/Models/Parser Models/Attribute.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | enum Attribute: String {
4 |
5 | enum Axis: String {
6 |
7 | case horizontal
8 | case vertical
9 | }
10 |
11 | enum PinPoint {
12 |
13 | case start
14 | case end
15 | case center
16 | case extent
17 | case firstBaseline
18 | case lastBaseline
19 | }
20 |
21 | case leading
22 | case trailing
23 | case top
24 | case bottom
25 | case centerX
26 | case centerY
27 | case width
28 | case height
29 | case leadingMargin
30 | case trailingMargin
31 | case topMargin
32 | case bottomMargin
33 | case centerXWithinMargins
34 | case centerYWithinMargins
35 | case firstBaseline
36 | case lastBaseline
37 |
38 | static let allCases: [Attribute] = [
39 | .leading,
40 | .trailing,
41 | .top,
42 | .bottom,
43 | .centerX,
44 | .centerY,
45 | .width,
46 | .height,
47 | .leadingMargin,
48 | .trailingMargin,
49 | .topMargin,
50 | .bottomMargin,
51 | .centerXWithinMargins,
52 | .centerYWithinMargins,
53 | .firstBaseline,
54 | .lastBaseline,
55 | ]
56 |
57 | var alternativeLabels: [String] {
58 | switch self {
59 | case .leading:
60 | return ["left", "minX"]
61 | case .trailing:
62 | return ["right", "maxX"]
63 | case .centerX:
64 | return ["midX"]
65 | case .centerY:
66 | return ["midY"]
67 | case .top:
68 | return ["minY"]
69 | case .bottom:
70 | return ["maxY"]
71 | case .leadingMargin:
72 | return ["leftMargin", "minXMargin"]
73 | case .trailingMargin:
74 | return ["rightMargin", "maxXMargin"]
75 | case .centerXWithinMargins:
76 | return ["midXWithinMargins"]
77 | case .centerYWithinMargins:
78 | return ["midYWithinMargins"]
79 | case .topMargin:
80 | return ["minYMargin"]
81 | case .bottomMargin:
82 | return ["maxYMargin"]
83 | case .lastBaseline:
84 | return ["baseline"]
85 | default:
86 | return []
87 | }
88 | }
89 |
90 | var labels: [String] {
91 | return [rawValue] + alternativeLabels
92 | }
93 |
94 | init(axis: Axis, pinPoint: PinPoint, includesMargin: Bool = false) throws {
95 |
96 | switch (pinPoint, axis, includesMargin) {
97 | case (.start, .horizontal, false): self = .leading
98 | case (.end, .horizontal, false): self = .trailing
99 | case (.start, .vertical, false): self = .top
100 | case (.end, .vertical, false): self = .bottom
101 | case (.center, .horizontal, false): self = .centerX
102 | case (.center, .vertical, false): self = .centerY
103 | case (.extent, .horizontal, _): self = .width
104 | case (.extent, .vertical, _): self = .height
105 | case (.start, .horizontal, true): self = .leadingMargin
106 | case (.end, .horizontal, true): self = .trailingMargin
107 | case (.start, .vertical, true): self = .topMargin
108 | case (.end, .vertical, true): self = .bottomMargin
109 | case (.center, .horizontal, true): self = .centerXWithinMargins
110 | case (.center, .vertical, true): self = .centerYWithinMargins
111 | case (.firstBaseline, .vertical, _): self = .firstBaseline
112 | case (.lastBaseline, .vertical, _): self = .lastBaseline
113 | default:
114 | throw InvalidConstraintError("\(axis) \(pinPoint)\(includesMargin ? "Margin" : "") is not a valid attribute")
115 | }
116 | }
117 |
118 | private var info: (pinPoint: PinPoint, axis: Axis, includesMargin: Bool) {
119 |
120 | switch self {
121 | case .leading: return (.start, .horizontal, false)
122 | case .trailing: return (.end, .horizontal, false)
123 | case .top: return (.start, .vertical, false)
124 | case .bottom: return (.end, .vertical, false)
125 | case .centerX: return (.center, .horizontal, false)
126 | case .centerY: return (.center, .vertical, false)
127 | case .width: return (.extent, .horizontal, false)
128 | case .height: return (.extent, .vertical, false)
129 | case .leadingMargin: return (.start, .horizontal, true)
130 | case .trailingMargin: return (.end, .horizontal, true)
131 | case .topMargin: return (.start, .vertical, true)
132 | case .bottomMargin: return (.end, .vertical, true)
133 | case .centerXWithinMargins: return (.center, .horizontal, true)
134 | case .centerYWithinMargins: return (.center, .vertical, true)
135 | case .firstBaseline: return (.firstBaseline, .vertical, false)
136 | case .lastBaseline: return (.lastBaseline, .vertical, false)
137 | }
138 | }
139 | var pinPoint: PinPoint {
140 | return info.pinPoint
141 | }
142 | var axis: Axis {
143 | return info.axis
144 | }
145 | var includesMargin: Bool {
146 | return info.includesMargin
147 | }
148 | }
149 |
150 |
--------------------------------------------------------------------------------
/Sources/App/Models/Parser Models/Color.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct Color {
4 |
5 | let r: Int
6 | let g: Int
7 | let b: Int
8 |
9 | init(r: Int, g: Int, b: Int) {
10 |
11 | self.r = r
12 | self.g = g
13 | self.b = b
14 | }
15 |
16 | init(hex: Int) {
17 |
18 | let r = (hex & 0xFF0000) >> 16
19 | let g = (hex & 0x00FF00) >> 8
20 | let b = hex & 0x0000FF
21 |
22 | self.init(r: r, g: g, b: b)
23 | }
24 |
25 | var hex: String {
26 |
27 | return String(format: "#%02X%02X%02X", r, g, b)
28 | }
29 |
30 | var rgb: String {
31 |
32 | return "rgb(\(r),\(g),\(b))"
33 | }
34 | }
35 |
36 | extension Color: ExpressibleByIntegerLiteral {
37 |
38 | init(integerLiteral value: Int) {
39 |
40 | self.init(hex: value)
41 | }
42 | }
43 |
44 | extension Color {
45 |
46 | static func flatColor(index: Int) -> Color {
47 |
48 | let colors = [
49 | turquoise,
50 | peterRiver,
51 | sunflower,
52 | alizarin,
53 | emerald,
54 | amethyst,
55 | carrot,
56 | creamCorn,
57 | greenSea,
58 | belizeHole,
59 | orange,
60 | pomegranate,
61 | dodgerBlue,
62 | nephritis,
63 | wysteria,
64 | pumpkin,
65 | ]
66 | return colors[abs(index) % colors.count]
67 | }
68 |
69 | static let defaultColor = turquoise
70 |
71 | static let turquoise: Color = 0x1abc9c
72 | static let greenSea: Color = 0x16a085
73 |
74 | static let emerald: Color = 0x2ecc71
75 | static let nephritis: Color = 0x27ae60
76 |
77 | static let peterRiver: Color = 0x3498db
78 | static let belizeHole: Color = 0x2980b9
79 | static let dodgerBlue: Color = 0x19b5fe
80 |
81 | static let amethyst: Color = 0x9b59b6
82 | static let wysteria: Color = 0x8e44ad
83 |
84 | static let creamCorn: Color = 0xf5d76e
85 | static let sunflower: Color = 0xf1c40f
86 | static let orange: Color = 0xf39c12
87 |
88 | static let carrot: Color = 0xe67e22
89 | static let pumpkin: Color = 0xd35400
90 |
91 | static let alizarin: Color = 0xe74c3c
92 | static let pomegranate: Color = 0xc0392b
93 | }
94 |
--------------------------------------------------------------------------------
/Sources/App/Models/Parser Models/Constant.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct Constant {
4 |
5 | let value: Double
6 |
7 | init(_ value: Double = 0.0) {
8 |
9 | self.value = value
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Sources/App/Models/Parser Models/Constraint.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct Constraint {
4 |
5 | enum Origin {
6 | case user
7 | case encapsulatedLayout
8 | case autoresizingMask
9 | case stackView
10 | }
11 |
12 | enum Relation: String {
13 |
14 | case equal = "=="
15 | case lessThanOrEqual = "<="
16 | case greaterThanOrEqual = ">="
17 |
18 | static let allCases: [Relation] = [
19 | .equal,
20 | .lessThanOrEqual,
21 | .greaterThanOrEqual
22 | ]
23 | }
24 |
25 | let identity: Instance
26 | let first: LayoutItemAttribute
27 | let second: LayoutItemAttribute?
28 | let relation: Relation
29 | let constant: Constant
30 | let multiplier: Multiplier
31 | let origin: Origin
32 | }
33 |
34 | extension Constraint {
35 |
36 | var layoutItemAttributes: [LayoutItemAttribute] {
37 | return [
38 | first,
39 | second
40 | ].compactMap { $0 }
41 | }
42 |
43 | var layoutItems: [Instance] {
44 | return layoutItemAttributes.map { $0.layoutItem }
45 | }
46 | }
47 |
48 | extension Constraint {
49 |
50 | var footnote: Footnote? {
51 | switch origin {
52 | case .autoresizingMask:
53 | return .autoresizingMask
54 | case .encapsulatedLayout:
55 | return .encapsulatedLayout
56 | case .stackView:
57 | return .stackView
58 | case .user:
59 | return nil
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Sources/App/Models/Parser Models/ConstraintGroup.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Random
3 |
4 | typealias Annotation = (color: Color, uniquingSuffix: String)
5 |
6 | struct ConstraintGroup {
7 |
8 | let raw: String
9 | let constraints: [Constraint]
10 | let annotations: [Instance : Annotation]
11 |
12 | private static func annotations(for layoutItems: [Instance], seed: Int) -> [Instance : Annotation] {
13 |
14 | let names = layoutItems.map { $0.prettyName }
15 |
16 | var uniquingSuffixes = [String]()
17 | var counts = [String : Int]()
18 |
19 | for name in names {
20 | let number = (counts[name] ?? 0) + 1
21 | counts[name] = number
22 | uniquingSuffixes.append(String(number))
23 | }
24 |
25 | var annotations = [Instance : Annotation]()
26 | for (i, item) in layoutItems.enumerated() {
27 | // Adding a seed value ensures the color scheme can differ per input while
28 | // remaining deterministic.
29 | let color = Color.flatColor(index: i + seed)
30 |
31 | let requiresUniquing = (counts[item.prettyName] ?? 0) > 1
32 | let uniquingSuffix = requiresUniquing ? uniquingSuffixes[i] : ""
33 |
34 | annotations[item] = (color: color, uniquingSuffix: uniquingSuffix)
35 | }
36 |
37 | return annotations
38 | }
39 |
40 | init(_ constraints: [Constraint], raw: String) {
41 |
42 | self.raw = raw
43 | self.constraints = constraints
44 | let layoutItems = constraints.flatMap { $0.layoutItems }.removingDuplicates()
45 | self.annotations = ConstraintGroup.annotations(for: Array(layoutItems), seed: raw.count)
46 | }
47 | }
48 |
49 | extension ConstraintGroup {
50 |
51 | var includesAutoResizingMaskConstraints: Bool {
52 | return constraints.contains(where: { $0.origin == .autoresizingMask })
53 | }
54 |
55 | var footnotes: [Footnote] {
56 | return constraints.compactMap { $0.footnote }.removingDuplicates()
57 | }
58 | }
59 |
60 | private extension Collection where Element: Hashable {
61 |
62 | func removingDuplicates() -> [Element] {
63 | var seen: SettranslatesAutoresizingMaskIntoConstraints
to false on this view."
27 | case .encapsulatedLayout:
28 | return "This constraint was added by a table or collection view to enforce its cell size."
29 | case .stackView:
30 | return "This constraint was added by a stack view to enforce its spacing, distribution or alignment."
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/App/Models/Parser Models/Instance.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct Instance {
4 |
5 | let className: String
6 | let address: String
7 | let identifier: String?
8 | }
9 |
10 | extension Instance: Equatable, Hashable {
11 |
12 | public static func ==(lhs: Instance, rhs: Instance) -> Bool {
13 |
14 | return lhs.address == rhs.address
15 | }
16 |
17 | public func hash(into hasher: inout Hasher) {
18 |
19 | address.hash(into: &hasher)
20 | }
21 | }
22 |
23 | extension Instance {
24 |
25 | var shortClassName: String {
26 | return className.components(separatedBy: ".").lazy.filter({ !$0.isEmpty }).last ?? className
27 | }
28 |
29 | var prettyTypeName: String {
30 |
31 | let prefixToTrim = "UI"
32 |
33 | guard shortClassName.hasPrefix(prefixToTrim) else {
34 | return shortClassName
35 | }
36 |
37 | return String(shortClassName[prefixToTrim.endIndex...])
38 | }
39 |
40 | var prettyName: String {
41 |
42 | return identifier ?? prettyTypeName
43 | }
44 | }
45 |
46 | struct LayoutItemAttribute {
47 |
48 | let layoutItem: Instance
49 | let attribute: Attribute
50 | }
51 |
--------------------------------------------------------------------------------
/Sources/App/Models/Parser Models/Multiplier.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct Multiplier {
4 |
5 | let value: Double
6 |
7 | init(_ value: Double = 1.0) {
8 |
9 | self.value = value
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Sources/App/Models/Requests/ConstraintLogRequest.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct ConstraintLogRequest: Codable {
4 |
5 | let constraintlog: String
6 | }
7 |
--------------------------------------------------------------------------------
/Sources/App/Parsing/ConstraintsParser+AutoLayoutPrimitives.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Sparse
3 |
4 | // MARK: - Auto Layout Primitives
5 |
6 | extension ConstraintsParser {
7 |
8 | static let identifierCharacter = characterNot(in: .newlines)
9 | .named("valid identifier character")
10 |
11 | static let relation = Constraint.Relation.allCases
12 | .map(parserForRelation)
13 | .reduce(pureError(), { $1.otherwise($0) })
14 | .named("relation")
15 |
16 | static let attribute: ParserStackView<\/code>'s height should equal 24.",
8 | "first" : {
9 | "attribute" : {
10 | "includesMargin" : false,
11 | "name" : "height"
12 | },
13 | "instance" : {
14 | "address" : "0x7fa4d0dece70",
15 | "className" : "UIStackView",
16 | "color" : "rgb(241,196,15)",
17 | "initial" : "S",
18 | "name" : "StackView",
19 | "suffix" : ""
20 | }
21 | },
22 | "identity" : {
23 | "address" : "0x6080004835c0",
24 | "className" : "NSLayoutConstraint",
25 | "color" : "rgb(26,188,156)",
26 | "initial" : "N",
27 | "name" : "NSLayoutConstraint"
28 | },
29 | "relation" : "=="
30 | },
31 | {
32 | "constant" : {
33 | "prefix" : "+ ",
34 | "value" : "21"
35 | },
36 | "description" : "StackView<\/code>'s top edge should equal HeaderView<\/code>'s top edge plus 21.",
37 | "first" : {
38 | "attribute" : {
39 | "includesMargin" : false,
40 | "name" : "top"
41 | },
42 | "instance" : {
43 | "address" : "0x7fa4d0dece70",
44 | "className" : "UIStackView",
45 | "color" : "rgb(241,196,15)",
46 | "initial" : "S",
47 | "name" : "StackView",
48 | "suffix" : ""
49 | }
50 | },
51 | "identity" : {
52 | "address" : "0x608000687440",
53 | "className" : "NSLayoutConstraint",
54 | "color" : "rgb(26,188,156)",
55 | "initial" : "N",
56 | "name" : "NSLayoutConstraint"
57 | },
58 | "relation" : "==",
59 | "second" : {
60 | "attribute" : {
61 | "includesMargin" : false,
62 | "name" : "top"
63 | },
64 | "instance" : {
65 | "address" : "0x7fa4d0df1370",
66 | "className" : "Proto.HeaderView",
67 | "color" : "rgb(231,76,60)",
68 | "initial" : "H",
69 | "name" : "HeaderView",
70 | "suffix" : ""
71 | }
72 | }
73 | },
74 | {
75 | "constant" : {
76 | "prefix" : "+ ",
77 | "value" : "9"
78 | },
79 | "description" : "HeaderView<\/code>'s bottom edge should equal StackView<\/code>'s bottom edge plus 9.",
80 | "first" : {
81 | "attribute" : {
82 | "includesMargin" : false,
83 | "name" : "bottom"
84 | },
85 | "instance" : {
86 | "address" : "0x7fa4d0df1370",
87 | "className" : "Proto.HeaderView",
88 | "color" : "rgb(231,76,60)",
89 | "initial" : "H",
90 | "name" : "HeaderView",
91 | "suffix" : ""
92 | }
93 | },
94 | "identity" : {
95 | "address" : "0x608000890860",
96 | "className" : "NSLayoutConstraint",
97 | "color" : "rgb(26,188,156)",
98 | "initial" : "N",
99 | "name" : "NSLayoutConstraint"
100 | },
101 | "relation" : "==",
102 | "second" : {
103 | "attribute" : {
104 | "includesMargin" : false,
105 | "name" : "bottom"
106 | },
107 | "instance" : {
108 | "address" : "0x7fa4d0dece70",
109 | "className" : "UIStackView",
110 | "color" : "rgb(241,196,15)",
111 | "initial" : "S",
112 | "name" : "StackView",
113 | "suffix" : ""
114 | }
115 | }
116 | },
117 | {
118 | "constant" : {
119 | "value" : "0"
120 | },
121 | "description" : "HeaderView<\/code>'s height should equal 0.",
122 | "first" : {
123 | "attribute" : {
124 | "includesMargin" : false,
125 | "name" : "height"
126 | },
127 | "instance" : {
128 | "address" : "0x7fa4d0df1370",
129 | "className" : "Proto.HeaderView",
130 | "color" : "rgb(231,76,60)",
131 | "initial" : "H",
132 | "name" : "HeaderView",
133 | "suffix" : ""
134 | }
135 | },
136 | "footnote" : {
137 | "marker" : "†",
138 | "text" : "This constraint was added by a table or collection view to enforce its cell size."
139 | },
140 | "identity" : {
141 | "address" : "0x600000a85d70",
142 | "className" : "NSLayoutConstraint",
143 | "color" : "rgb(26,188,156)",
144 | "identifier" : "UIView-Encapsulated-Layout-Height",
145 | "initial" : "U",
146 | "name" : "UIView-Encapsulated-Layout-Height"
147 | },
148 | "relation" : "=="
149 | }
150 | ],
151 | "footnotes" : [
152 | {
153 | "marker" : "†",
154 | "text" : "This constraint was added by a table or collection view to enforce its cell size."
155 | }
156 | ]
157 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testCustomInputs.2.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "description" : "MyCircleView<\/code>'s leading edge should equal name_label<\/code>'s leading edge.",
5 | "first" : {
6 | "attribute" : {
7 | "includesMargin" : false,
8 | "name" : "leading"
9 | },
10 | "instance" : {
11 | "address" : "0x7fa4d0e8b8e0",
12 | "className" : "MyCircleView",
13 | "color" : "rgb(241,196,15)",
14 | "initial" : "M",
15 | "name" : "MyCircleView",
16 | "suffix" : ""
17 | }
18 | },
19 | "identity" : {
20 | "address" : "0x600000685780",
21 | "className" : "NSLayoutConstraint",
22 | "color" : "rgb(26,188,156)",
23 | "initial" : "N",
24 | "name" : "NSLayoutConstraint"
25 | },
26 | "relation" : "==",
27 | "second" : {
28 | "attribute" : {
29 | "includesMargin" : false,
30 | "name" : "leading"
31 | },
32 | "instance" : {
33 | "address" : "0x7fa4d0e9e480",
34 | "className" : "name_label",
35 | "color" : "rgb(231,76,60)",
36 | "initial" : "N",
37 | "name" : "name_label",
38 | "suffix" : ""
39 | }
40 | }
41 | },
42 | {
43 | "constant" : {
44 | "prefix" : "+ ",
45 | "value" : "6"
46 | },
47 | "description" : "MyCircleView<\/code>'s leading edge should equal OverViewFactorLabel<\/code>'s leading edge plus 6.",
48 | "first" : {
49 | "attribute" : {
50 | "includesMargin" : false,
51 | "name" : "leading"
52 | },
53 | "instance" : {
54 | "address" : "0x7fa4d0e8b8e0",
55 | "className" : "MyCircleView",
56 | "color" : "rgb(241,196,15)",
57 | "initial" : "M",
58 | "name" : "MyCircleView",
59 | "suffix" : ""
60 | }
61 | },
62 | "identity" : {
63 | "address" : "0x6000006857d0",
64 | "className" : "NSLayoutConstraint",
65 | "color" : "rgb(26,188,156)",
66 | "initial" : "N",
67 | "name" : "NSLayoutConstraint"
68 | },
69 | "relation" : "==",
70 | "second" : {
71 | "attribute" : {
72 | "includesMargin" : false,
73 | "name" : "leading"
74 | },
75 | "instance" : {
76 | "address" : "0x7fa4d0e8b450",
77 | "className" : "OverViewFactorLabel",
78 | "color" : "rgb(46,204,113)",
79 | "initial" : "O",
80 | "name" : "OverViewFactorLabel",
81 | "suffix" : ""
82 | }
83 | }
84 | },
85 | {
86 | "description" : "name_label<\/code>'s leading edge should equal OverViewFactorLabel<\/code>'s leading edge.",
87 | "first" : {
88 | "attribute" : {
89 | "includesMargin" : false,
90 | "name" : "leading"
91 | },
92 | "instance" : {
93 | "address" : "0x7fa4d0e9e480",
94 | "className" : "name_label",
95 | "color" : "rgb(231,76,60)",
96 | "initial" : "N",
97 | "name" : "name_label",
98 | "suffix" : ""
99 | }
100 | },
101 | "identity" : {
102 | "address" : "0x600000482e90",
103 | "className" : "NSLayoutConstraint",
104 | "color" : "rgb(26,188,156)",
105 | "initial" : "N",
106 | "name" : "NSLayoutConstraint"
107 | },
108 | "relation" : "==",
109 | "second" : {
110 | "attribute" : {
111 | "includesMargin" : false,
112 | "name" : "leading"
113 | },
114 | "instance" : {
115 | "address" : "0x7fa4d0e8b450",
116 | "className" : "OverViewFactorLabel",
117 | "color" : "rgb(46,204,113)",
118 | "initial" : "O",
119 | "name" : "OverViewFactorLabel",
120 | "suffix" : ""
121 | }
122 | }
123 | }
124 | ],
125 | "footnotes" : [
126 |
127 | ]
128 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testCustomInputs.3.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "prefix" : "+ ",
6 | "value" : "3"
7 | },
8 | "description" : "View1<\/code>'s bottom edge should equal VeryLargeLabelWithBorder<\/code>'s bottom edge plus 3.",
9 | "first" : {
10 | "attribute" : {
11 | "includesMargin" : false,
12 | "name" : "bottom"
13 | },
14 | "instance" : {
15 | "address" : "0x7fa4d6079490",
16 | "className" : "UIView",
17 | "color" : "rgb(142,68,173)",
18 | "initial" : "V",
19 | "name" : "View",
20 | "suffix" : "1"
21 | }
22 | },
23 | "identity" : {
24 | "address" : "0x608000880dc0",
25 | "className" : "NSLayoutConstraint",
26 | "color" : "rgb(26,188,156)",
27 | "initial" : "N",
28 | "name" : "NSLayoutConstraint"
29 | },
30 | "relation" : "==",
31 | "second" : {
32 | "attribute" : {
33 | "includesMargin" : false,
34 | "name" : "bottom"
35 | },
36 | "instance" : {
37 | "address" : "0x7fa4d60764b0",
38 | "className" : "VeryLargeLabelWithBorder...",
39 | "color" : "rgb(211,84,0)",
40 | "initial" : "V",
41 | "name" : "VeryLargeLabelWithBorder",
42 | "suffix" : ""
43 | }
44 | }
45 | },
46 | {
47 | "constant" : {
48 | "prefix" : "+ ",
49 | "value" : "3"
50 | },
51 | "description" : "VeryLargeLabelWithBorder<\/code>'s top edge should equal View1<\/code>'s top edge plus 3.",
52 | "first" : {
53 | "attribute" : {
54 | "includesMargin" : false,
55 | "name" : "top"
56 | },
57 | "instance" : {
58 | "address" : "0x7fa4d60764b0",
59 | "className" : "VeryLargeLabelWithBorder...",
60 | "color" : "rgb(211,84,0)",
61 | "initial" : "V",
62 | "name" : "VeryLargeLabelWithBorder",
63 | "suffix" : ""
64 | }
65 | },
66 | "identity" : {
67 | "address" : "0x60800068f000",
68 | "className" : "NSLayoutConstraint",
69 | "color" : "rgb(26,188,156)",
70 | "initial" : "N",
71 | "name" : "NSLayoutConstraint"
72 | },
73 | "relation" : "==",
74 | "second" : {
75 | "attribute" : {
76 | "includesMargin" : false,
77 | "name" : "top"
78 | },
79 | "instance" : {
80 | "address" : "0x7fa4d6079490",
81 | "className" : "UIView",
82 | "color" : "rgb(142,68,173)",
83 | "initial" : "V",
84 | "name" : "View",
85 | "suffix" : "1"
86 | }
87 | }
88 | },
89 | {
90 | "constant" : {
91 | "value" : "0"
92 | },
93 | "description" : "View2<\/code>'s height should equal 0.",
94 | "first" : {
95 | "attribute" : {
96 | "includesMargin" : false,
97 | "name" : "height"
98 | },
99 | "instance" : {
100 | "address" : "0x7fa4d6079060",
101 | "className" : "UIView",
102 | "color" : "rgb(26,188,156)",
103 | "initial" : "V",
104 | "name" : "View",
105 | "suffix" : "2"
106 | }
107 | },
108 | "identity" : {
109 | "address" : "0x608000695130",
110 | "className" : "NSLayoutConstraint",
111 | "color" : "rgb(26,188,156)",
112 | "initial" : "N",
113 | "name" : "NSLayoutConstraint"
114 | },
115 | "relation" : "=="
116 | },
117 | {
118 | "description" : "View2<\/code>'s bottom edge should equal View1<\/code>'s bottom edge.",
119 | "first" : {
120 | "attribute" : {
121 | "includesMargin" : false,
122 | "name" : "bottom"
123 | },
124 | "instance" : {
125 | "address" : "0x7fa4d6079060",
126 | "className" : "UIView",
127 | "color" : "rgb(26,188,156)",
128 | "initial" : "V",
129 | "name" : "View",
130 | "suffix" : "2"
131 | }
132 | },
133 | "identity" : {
134 | "address" : "0x608000887620",
135 | "className" : "NSLayoutConstraint",
136 | "color" : "rgb(26,188,156)",
137 | "initial" : "N",
138 | "name" : "NSLayoutConstraint"
139 | },
140 | "relation" : "==",
141 | "second" : {
142 | "attribute" : {
143 | "includesMargin" : false,
144 | "name" : "bottom"
145 | },
146 | "instance" : {
147 | "address" : "0x7fa4d6079490",
148 | "className" : "UIView",
149 | "color" : "rgb(142,68,173)",
150 | "initial" : "V",
151 | "name" : "View",
152 | "suffix" : "1"
153 | }
154 | }
155 | },
156 | {
157 | "description" : "View1<\/code>'s top edge should equal View2<\/code>'s top edge.",
158 | "first" : {
159 | "attribute" : {
160 | "includesMargin" : false,
161 | "name" : "top"
162 | },
163 | "instance" : {
164 | "address" : "0x7fa4d6079490",
165 | "className" : "UIView",
166 | "color" : "rgb(142,68,173)",
167 | "initial" : "V",
168 | "name" : "View",
169 | "suffix" : "1"
170 | }
171 | },
172 | "identity" : {
173 | "address" : "0x608000699be0",
174 | "className" : "NSLayoutConstraint",
175 | "color" : "rgb(26,188,156)",
176 | "initial" : "N",
177 | "name" : "NSLayoutConstraint"
178 | },
179 | "relation" : "==",
180 | "second" : {
181 | "attribute" : {
182 | "includesMargin" : false,
183 | "name" : "top"
184 | },
185 | "instance" : {
186 | "address" : "0x7fa4d6079060",
187 | "className" : "UIView",
188 | "color" : "rgb(26,188,156)",
189 | "initial" : "V",
190 | "name" : "View",
191 | "suffix" : "2"
192 | }
193 | }
194 | }
195 | ],
196 | "footnotes" : [
197 |
198 | ]
199 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testCustomInputs.4.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "value" : "0"
6 | },
7 | "description" : "_UILayoutGuide<\/code>'s height should equal 0.",
8 | "first" : {
9 | "attribute" : {
10 | "includesMargin" : false,
11 | "name" : "height"
12 | },
13 | "instance" : {
14 | "address" : "0x1271a5500",
15 | "className" : "_UILayoutGuide",
16 | "color" : "rgb(22,160,133)",
17 | "initial" : "U",
18 | "name" : "_UILayoutGuide",
19 | "suffix" : ""
20 | }
21 | },
22 | "identity" : {
23 | "address" : "0x1272e5820",
24 | "className" : "_UILayoutSupportConstraint",
25 | "color" : "rgb(26,188,156)",
26 | "initial" : "U",
27 | "name" : "_UILayoutSupportConstraint"
28 | },
29 | "relation" : "=="
30 | },
31 | {
32 | "description" : "_UILayoutGuide<\/code>'s bottom edge should equal View<\/code>'s bottom edge.",
33 | "first" : {
34 | "attribute" : {
35 | "includesMargin" : false,
36 | "name" : "bottom"
37 | },
38 | "instance" : {
39 | "address" : "0x1271a5500",
40 | "className" : "_UILayoutGuide",
41 | "color" : "rgb(22,160,133)",
42 | "initial" : "U",
43 | "name" : "_UILayoutGuide",
44 | "suffix" : ""
45 | }
46 | },
47 | "identity" : {
48 | "address" : "0x1272cd510",
49 | "className" : "_UILayoutSupportConstraint",
50 | "color" : "rgb(26,188,156)",
51 | "initial" : "U",
52 | "name" : "_UILayoutSupportConstraint"
53 | },
54 | "relation" : "==",
55 | "second" : {
56 | "attribute" : {
57 | "includesMargin" : false,
58 | "name" : "bottom"
59 | },
60 | "instance" : {
61 | "address" : "0x128321830",
62 | "className" : "UIView",
63 | "color" : "rgb(41,128,185)",
64 | "initial" : "V",
65 | "name" : "View",
66 | "suffix" : ""
67 | }
68 | }
69 | },
70 | {
71 | "constant" : {
72 | "value" : "230"
73 | },
74 | "description" : "CollectionView<\/code>'s height should equal 230.",
75 | "first" : {
76 | "attribute" : {
77 | "includesMargin" : false,
78 | "name" : "height"
79 | },
80 | "instance" : {
81 | "address" : "0x126963e00",
82 | "className" : "UICollectionView",
83 | "color" : "rgb(243,156,18)",
84 | "initial" : "C",
85 | "name" : "CollectionView",
86 | "suffix" : ""
87 | }
88 | },
89 | "identity" : {
90 | "address" : "0x127225340",
91 | "className" : "NSLayoutConstraint",
92 | "color" : "rgb(26,188,156)",
93 | "initial" : "N",
94 | "name" : "NSLayoutConstraint"
95 | },
96 | "relation" : "=="
97 | },
98 | {
99 | "constant" : {
100 | "prefix" : "+ ",
101 | "value" : "87"
102 | },
103 | "description" : "_UILayoutGuide<\/code>'s top edge should equal CollectionView<\/code>'s bottom edge plus 87.",
104 | "first" : {
105 | "attribute" : {
106 | "includesMargin" : false,
107 | "name" : "top"
108 | },
109 | "instance" : {
110 | "address" : "0x1271a5500",
111 | "className" : "_UILayoutGuide",
112 | "color" : "rgb(22,160,133)",
113 | "initial" : "U",
114 | "name" : "_UILayoutGuide",
115 | "suffix" : ""
116 | }
117 | },
118 | "identity" : {
119 | "address" : "0x128325fd0",
120 | "className" : "NSLayoutConstraint",
121 | "color" : "rgb(26,188,156)",
122 | "initial" : "N",
123 | "name" : "NSLayoutConstraint"
124 | },
125 | "relation" : "==",
126 | "second" : {
127 | "attribute" : {
128 | "includesMargin" : false,
129 | "name" : "bottom"
130 | },
131 | "instance" : {
132 | "address" : "0x126963e00",
133 | "className" : "UICollectionView",
134 | "color" : "rgb(243,156,18)",
135 | "initial" : "C",
136 | "name" : "CollectionView",
137 | "suffix" : ""
138 | }
139 | }
140 | },
141 | {
142 | "constant" : {
143 | "value" : "568"
144 | },
145 | "description" : "View<\/code>'s height should equal 568.",
146 | "first" : {
147 | "attribute" : {
148 | "includesMargin" : false,
149 | "name" : "height"
150 | },
151 | "instance" : {
152 | "address" : "0x128321830",
153 | "className" : "UIView",
154 | "color" : "rgb(41,128,185)",
155 | "initial" : "V",
156 | "name" : "View",
157 | "suffix" : ""
158 | }
159 | },
160 | "footnote" : {
161 | "marker" : "†",
162 | "text" : "This constraint was added by a table or collection view to enforce its cell size."
163 | },
164 | "identity" : {
165 | "address" : "0x1272e51f0",
166 | "className" : "NSLayoutConstraint",
167 | "color" : "rgb(26,188,156)",
168 | "identifier" : "UIView-Encapsulated-Layout-Height",
169 | "initial" : "U",
170 | "name" : "UIView-Encapsulated-Layout-Height"
171 | },
172 | "relation" : "=="
173 | },
174 | {
175 | "description" : "CollectionView<\/code>'s bottom edge should equal View<\/code>'s bottom edge.",
176 | "first" : {
177 | "attribute" : {
178 | "includesMargin" : false,
179 | "name" : "bottom"
180 | },
181 | "instance" : {
182 | "address" : "0x126963e00",
183 | "className" : "UICollectionView",
184 | "color" : "rgb(243,156,18)",
185 | "initial" : "C",
186 | "name" : "CollectionView",
187 | "suffix" : ""
188 | }
189 | },
190 | "footnote" : {
191 | "marker" : "*",
192 | "text" : "This constraint was translated from an autoresizing mask. If this was not intended, try setting translatesAutoresizingMaskIntoConstraints<\/code> to false on this view."
193 | },
194 | "identity" : {
195 | "address" : "0x1272ed5f0",
196 | "className" : "NSAutoresizingMaskLayoutConstraint",
197 | "color" : "rgb(26,188,156)",
198 | "identifier" : "UIView-Encapsulated-Layout-Top",
199 | "initial" : "U",
200 | "name" : "UIView-Encapsulated-Layout-Top"
201 | },
202 | "relation" : "==",
203 | "second" : {
204 | "attribute" : {
205 | "includesMargin" : false,
206 | "name" : "bottom"
207 | },
208 | "instance" : {
209 | "address" : "0x128321830",
210 | "className" : "UIView",
211 | "color" : "rgb(41,128,185)",
212 | "initial" : "V",
213 | "name" : "View",
214 | "suffix" : ""
215 | }
216 | }
217 | }
218 | ],
219 | "footnotes" : [
220 | {
221 | "marker" : "†",
222 | "text" : "This constraint was added by a table or collection view to enforce its cell size."
223 | },
224 | {
225 | "marker" : "*",
226 | "text" : "This constraint was translated from an autoresizing mask. If this was not intended, try setting translatesAutoresizingMaskIntoConstraints<\/code> to false on this view."
227 | }
228 | ]
229 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testCustomInputs.5.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "value" : "70"
6 | },
7 | "description" : "View<\/code>'s width should equal 70.",
8 | "first" : {
9 | "attribute" : {
10 | "includesMargin" : false,
11 | "name" : "width"
12 | },
13 | "instance" : {
14 | "address" : "0x7f95000e5ac0",
15 | "className" : "UIView",
16 | "color" : "rgb(41,128,185)",
17 | "initial" : "V",
18 | "name" : "View",
19 | "suffix" : ""
20 | }
21 | },
22 | "footnote" : {
23 | "marker" : "*",
24 | "text" : "This constraint was translated from an autoresizing mask. If this was not intended, try setting translatesAutoresizingMaskIntoConstraints<\/code> to false on this view."
25 | },
26 | "identity" : {
27 | "address" : "0x60000089a130",
28 | "className" : "NSAutoresizingMaskLayoutConstraint",
29 | "color" : "rgb(26,188,156)",
30 | "initial" : "N",
31 | "name" : "NSAutoresizingMaskLayoutConstraint"
32 | },
33 | "relation" : "=="
34 | },
35 | {
36 | "constant" : {
37 | "value" : "54"
38 | },
39 | "description" : "DetailViewFeatureItemCell<\/code>'s width should equal 54.",
40 | "first" : {
41 | "attribute" : {
42 | "includesMargin" : false,
43 | "name" : "width"
44 | },
45 | "instance" : {
46 | "address" : "0x7f95000e5e50",
47 | "className" : "DetailViewFeatureItemCell...",
48 | "color" : "rgb(243,156,18)",
49 | "initial" : "D",
50 | "name" : "DetailViewFeatureItemCell",
51 | "suffix" : ""
52 | }
53 | },
54 | "identity" : {
55 | "address" : "0x6000008989c0",
56 | "className" : "NSLayoutConstraint",
57 | "color" : "rgb(26,188,156)",
58 | "initial" : "N",
59 | "name" : "NSLayoutConstraint"
60 | },
61 | "relation" : "=="
62 | },
63 | {
64 | "description" : "DetailViewFeatureItemCell<\/code>'s horizontal center should equal View<\/code>'s horizontal center.",
65 | "first" : {
66 | "attribute" : {
67 | "includesMargin" : false,
68 | "name" : "centerX"
69 | },
70 | "instance" : {
71 | "address" : "0x7f95000e5e50",
72 | "className" : "DetailViewFeatureItemCell...",
73 | "color" : "rgb(243,156,18)",
74 | "initial" : "D",
75 | "name" : "DetailViewFeatureItemCell",
76 | "suffix" : ""
77 | }
78 | },
79 | "identity" : {
80 | "address" : "0x600000898b50",
81 | "className" : "NSLayoutConstraint",
82 | "color" : "rgb(26,188,156)",
83 | "initial" : "N",
84 | "name" : "NSLayoutConstraint"
85 | },
86 | "relation" : "==",
87 | "second" : {
88 | "attribute" : {
89 | "includesMargin" : false,
90 | "name" : "centerX"
91 | },
92 | "instance" : {
93 | "address" : "0x7f95000e5ac0",
94 | "className" : "UIView",
95 | "color" : "rgb(41,128,185)",
96 | "initial" : "V",
97 | "name" : "View",
98 | "suffix" : ""
99 | }
100 | }
101 | },
102 | {
103 | "constant" : {
104 | "prefix" : "- ",
105 | "value" : "2"
106 | },
107 | "description" : "View<\/code>'s trailing edge should equal DetailViewFeatureItemCell<\/code>'s trailing edge minus 2.",
108 | "first" : {
109 | "attribute" : {
110 | "includesMargin" : false,
111 | "name" : "trailing"
112 | },
113 | "instance" : {
114 | "address" : "0x7f95000e5ac0",
115 | "className" : "UIView",
116 | "color" : "rgb(41,128,185)",
117 | "initial" : "V",
118 | "name" : "View",
119 | "suffix" : ""
120 | }
121 | },
122 | "identity" : {
123 | "address" : "0x600000898c90",
124 | "className" : "NSLayoutConstraint",
125 | "color" : "rgb(26,188,156)",
126 | "initial" : "N",
127 | "name" : "NSLayoutConstraint"
128 | },
129 | "relation" : "==",
130 | "second" : {
131 | "attribute" : {
132 | "includesMargin" : false,
133 | "name" : "trailing"
134 | },
135 | "instance" : {
136 | "address" : "0x7f95000e5e50",
137 | "className" : "DetailViewFeatureItemCell...",
138 | "color" : "rgb(243,156,18)",
139 | "initial" : "D",
140 | "name" : "DetailViewFeatureItemCell",
141 | "suffix" : ""
142 | }
143 | }
144 | }
145 | ],
146 | "footnotes" : [
147 | {
148 | "marker" : "*",
149 | "text" : "This constraint was translated from an autoresizing mask. If this was not intended, try setting translatesAutoresizingMaskIntoConstraints<\/code> to false on this view."
150 | }
151 | ]
152 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testCustomInputs.7.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "value" : "60"
6 | },
7 | "description" : "ImageView<\/code>'s height should equal 60.",
8 | "first" : {
9 | "attribute" : {
10 | "includesMargin" : false,
11 | "name" : "height"
12 | },
13 | "instance" : {
14 | "address" : "0x7fd382f50",
15 | "className" : "UIImageView",
16 | "color" : "rgb(41,128,185)",
17 | "initial" : "I",
18 | "name" : "ImageView",
19 | "suffix" : ""
20 | }
21 | },
22 | "identity" : {
23 | "address" : "0x69c2f0",
24 | "className" : "NSLayoutConstraint",
25 | "color" : "rgb(26,188,156)",
26 | "initial" : "N",
27 | "name" : "NSLayoutConstraint"
28 | },
29 | "relation" : "=="
30 | },
31 | {
32 | "description" : "ImageView<\/code>'s top edge should equal TableViewCell<\/code>'s top edge.",
33 | "first" : {
34 | "attribute" : {
35 | "includesMargin" : false,
36 | "name" : "top"
37 | },
38 | "instance" : {
39 | "address" : "0x7fd382f50",
40 | "className" : "UIImageView",
41 | "color" : "rgb(41,128,185)",
42 | "initial" : "I",
43 | "name" : "ImageView",
44 | "suffix" : ""
45 | }
46 | },
47 | "identity" : {
48 | "address" : "0x69a8b0",
49 | "className" : "NSLayoutConstraint",
50 | "color" : "rgb(26,188,156)",
51 | "initial" : "N",
52 | "name" : "NSLayoutConstraint"
53 | },
54 | "relation" : "==",
55 | "second" : {
56 | "attribute" : {
57 | "includesMargin" : false,
58 | "name" : "top"
59 | },
60 | "instance" : {
61 | "address" : "0x7fd39b20",
62 | "className" : "UITableViewCell",
63 | "color" : "rgb(243,156,18)",
64 | "initial" : "T",
65 | "name" : "TableViewCell",
66 | "suffix" : ""
67 | }
68 | }
69 | },
70 | {
71 | "description" : "TableViewCell<\/code>'s bottom edge should equal ImageView<\/code>'s bottom edge.",
72 | "first" : {
73 | "attribute" : {
74 | "includesMargin" : false,
75 | "name" : "bottom"
76 | },
77 | "instance" : {
78 | "address" : "0x7fd39b20",
79 | "className" : "UITableViewCell",
80 | "color" : "rgb(243,156,18)",
81 | "initial" : "T",
82 | "name" : "TableViewCell",
83 | "suffix" : ""
84 | }
85 | },
86 | "identity" : {
87 | "address" : "0x697ca0",
88 | "className" : "NSLayoutConstraint",
89 | "color" : "rgb(26,188,156)",
90 | "initial" : "N",
91 | "name" : "NSLayoutConstraint"
92 | },
93 | "relation" : "==",
94 | "second" : {
95 | "attribute" : {
96 | "includesMargin" : false,
97 | "name" : "bottom"
98 | },
99 | "instance" : {
100 | "address" : "0x7fd382f50",
101 | "className" : "UIImageView",
102 | "color" : "rgb(41,128,185)",
103 | "initial" : "I",
104 | "name" : "ImageView",
105 | "suffix" : ""
106 | }
107 | }
108 | },
109 | {
110 | "constant" : {
111 | "value" : "80"
112 | },
113 | "description" : "TableViewCell<\/code>'s height should equal 80.",
114 | "first" : {
115 | "attribute" : {
116 | "includesMargin" : false,
117 | "name" : "height"
118 | },
119 | "instance" : {
120 | "address" : "0x7fd39b20",
121 | "className" : "UITableViewCell",
122 | "color" : "rgb(243,156,18)",
123 | "initial" : "T",
124 | "name" : "TableViewCell",
125 | "suffix" : ""
126 | }
127 | },
128 | "footnote" : {
129 | "marker" : "†",
130 | "text" : "This constraint was added by a table or collection view to enforce its cell size."
131 | },
132 | "identity" : {
133 | "address" : "0x697d40",
134 | "className" : "NSLayoutConstraint",
135 | "color" : "rgb(26,188,156)",
136 | "identifier" : "UIView-Encapsulated-Layout-Height",
137 | "initial" : "U",
138 | "name" : "UIView-Encapsulated-Layout-Height"
139 | },
140 | "relation" : "=="
141 | }
142 | ],
143 | "footnotes" : [
144 | {
145 | "marker" : "†",
146 | "text" : "This constraint was added by a table or collection view to enforce its cell size."
147 | }
148 | ]
149 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testCustomInputs.8.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "prefix" : "+ ",
6 | "value" : "7"
7 | },
8 | "description" : "ListViewItemLabel<\/code>'s top edge should equal ListViewItemLabel<\/code>'s bottom edge plus 7.",
9 | "first" : {
10 | "attribute" : {
11 | "includesMargin" : false,
12 | "name" : "top"
13 | },
14 | "instance" : {
15 | "address" : "0x7f950028e5b0",
16 | "className" : "ListViewItemLabel...",
17 | "color" : "rgb(243,156,18)",
18 | "initial" : "L",
19 | "name" : "ListViewItemLabel",
20 | "suffix" : ""
21 | }
22 | },
23 | "identity" : {
24 | "address" : "0x608000696990",
25 | "className" : "NSLayoutConstraint",
26 | "color" : "rgb(26,188,156)",
27 | "initial" : "N",
28 | "name" : "NSLayoutConstraint"
29 | },
30 | "relation" : "==",
31 | "second" : {
32 | "attribute" : {
33 | "includesMargin" : false,
34 | "name" : "bottom"
35 | },
36 | "instance" : {
37 | "address" : "0x7f950028e5b0",
38 | "className" : "ListViewItemLabel...",
39 | "color" : "rgb(243,156,18)",
40 | "initial" : "L",
41 | "name" : "ListViewItemLabel",
42 | "suffix" : ""
43 | }
44 | }
45 | }
46 | ],
47 | "footnotes" : [
48 |
49 | ]
50 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testGitHubIssues.1.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "value" : "5"
6 | },
7 | "description" : "progress background<\/code>'s height should equal 5.",
8 | "first" : {
9 | "attribute" : {
10 | "includesMargin" : false,
11 | "name" : "height"
12 | },
13 | "instance" : {
14 | "address" : "0x1089a5290",
15 | "className" : "progress background",
16 | "color" : "rgb(243,156,18)",
17 | "initial" : "P",
18 | "name" : "progress background",
19 | "suffix" : ""
20 | }
21 | },
22 | "identity" : {
23 | "address" : "0x17468b860",
24 | "className" : "NSLayoutConstraint",
25 | "color" : "rgb(26,188,156)",
26 | "initial" : "N",
27 | "name" : "NSLayoutConstraint"
28 | },
29 | "relation" : "=="
30 | }
31 | ],
32 | "footnotes" : [
33 |
34 | ]
35 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testGitHubIssues.2.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "value" : "234"
6 | },
7 | "description" : "AWPProductOnMapView<\/code>'s height should equal 234.",
8 | "first" : {
9 | "attribute" : {
10 | "includesMargin" : false,
11 | "name" : "height"
12 | },
13 | "instance" : {
14 | "address" : "0x4dbb090",
15 | "className" : "AWPProductOnMapView",
16 | "color" : "rgb(155,89,182)",
17 | "initial" : "A",
18 | "name" : "AWPProductOnMapView",
19 | "suffix" : ""
20 | }
21 | },
22 | "identity" : {
23 | "address" : "0x181af7c0",
24 | "className" : "NSAutoresizingMaskLayoutConstraint",
25 | "color" : "rgb(26,188,156)",
26 | "initial" : "N",
27 | "name" : "NSAutoresizingMaskLayoutConstraint"
28 | },
29 | "relation" : "=="
30 | },
31 | {
32 | "description" : "ImageView<\/code>'s width should equal ImageView<\/code>'s height multiplied by 0.385.",
33 | "first" : {
34 | "attribute" : {
35 | "includesMargin" : false,
36 | "name" : "width"
37 | },
38 | "instance" : {
39 | "address" : "0x4db3270",
40 | "className" : "UIImageView",
41 | "color" : "rgb(230,126,34)",
42 | "initial" : "I",
43 | "name" : "ImageView",
44 | "suffix" : ""
45 | }
46 | },
47 | "identity" : {
48 | "address" : "0x181cef70",
49 | "className" : "NSLayoutConstraint",
50 | "color" : "rgb(26,188,156)",
51 | "initial" : "N",
52 | "name" : "NSLayoutConstraint"
53 | },
54 | "multiplier" : "* 0.385",
55 | "relation" : "==",
56 | "second" : {
57 | "attribute" : {
58 | "includesMargin" : false,
59 | "name" : "height"
60 | },
61 | "instance" : {
62 | "address" : "0x4db3270",
63 | "className" : "UIImageView",
64 | "color" : "rgb(230,126,34)",
65 | "initial" : "I",
66 | "name" : "ImageView",
67 | "suffix" : ""
68 | }
69 | }
70 | },
71 | {
72 | "constant" : {
73 | "value" : "85"
74 | },
75 | "description" : "ImageView<\/code>'s width should equal 85.",
76 | "first" : {
77 | "attribute" : {
78 | "includesMargin" : false,
79 | "name" : "width"
80 | },
81 | "instance" : {
82 | "address" : "0x4db3270",
83 | "className" : "UIImageView",
84 | "color" : "rgb(230,126,34)",
85 | "initial" : "I",
86 | "name" : "ImageView",
87 | "suffix" : ""
88 | }
89 | },
90 | "identity" : {
91 | "address" : "0x181d2d20",
92 | "className" : "NSLayoutConstraint",
93 | "color" : "rgb(26,188,156)",
94 | "initial" : "N",
95 | "name" : "NSLayoutConstraint"
96 | },
97 | "relation" : "=="
98 | },
99 | {
100 | "constant" : {
101 | "prefix" : "+ ",
102 | "value" : "25"
103 | },
104 | "description" : "View<\/code>'s bottom edge should equal ImageView<\/code>'s bottom edge plus 25.",
105 | "first" : {
106 | "attribute" : {
107 | "includesMargin" : false,
108 | "name" : "bottom"
109 | },
110 | "instance" : {
111 | "address" : "0x4db5710",
112 | "className" : "UIView",
113 | "color" : "rgb(245,215,110)",
114 | "initial" : "V",
115 | "name" : "View",
116 | "suffix" : ""
117 | }
118 | },
119 | "identity" : {
120 | "address" : "0x4dc7b00",
121 | "className" : "NSLayoutConstraint",
122 | "color" : "rgb(26,188,156)",
123 | "initial" : "N",
124 | "name" : "NSLayoutConstraint"
125 | },
126 | "relation" : "==",
127 | "second" : {
128 | "attribute" : {
129 | "includesMargin" : false,
130 | "name" : "bottom"
131 | },
132 | "instance" : {
133 | "address" : "0x4db3270",
134 | "className" : "UIImageView",
135 | "color" : "rgb(230,126,34)",
136 | "initial" : "I",
137 | "name" : "ImageView",
138 | "suffix" : ""
139 | }
140 | }
141 | },
142 | {
143 | "constant" : {
144 | "prefix" : "+ ",
145 | "value" : "2"
146 | },
147 | "description" : "ImageView<\/code>'s top edge should equal View<\/code>'s top edge plus 2.",
148 | "first" : {
149 | "attribute" : {
150 | "includesMargin" : false,
151 | "name" : "top"
152 | },
153 | "instance" : {
154 | "address" : "0x4db3270",
155 | "className" : "UIImageView",
156 | "color" : "rgb(230,126,34)",
157 | "initial" : "I",
158 | "name" : "ImageView",
159 | "suffix" : ""
160 | }
161 | },
162 | "identity" : {
163 | "address" : "0x4dc7bd0",
164 | "className" : "NSLayoutConstraint",
165 | "color" : "rgb(26,188,156)",
166 | "initial" : "N",
167 | "name" : "NSLayoutConstraint"
168 | },
169 | "relation" : "==",
170 | "second" : {
171 | "attribute" : {
172 | "includesMargin" : false,
173 | "name" : "top"
174 | },
175 | "instance" : {
176 | "address" : "0x4db5710",
177 | "className" : "UIView",
178 | "color" : "rgb(245,215,110)",
179 | "initial" : "V",
180 | "name" : "View",
181 | "suffix" : ""
182 | }
183 | }
184 | },
185 | {
186 | "description" : "AWPProductOnMapView<\/code>'s bottom edge should equal View<\/code>'s bottom edge.",
187 | "first" : {
188 | "attribute" : {
189 | "includesMargin" : false,
190 | "name" : "bottom"
191 | },
192 | "instance" : {
193 | "address" : "0x4dbb090",
194 | "className" : "AWPProductOnMapView",
195 | "color" : "rgb(155,89,182)",
196 | "initial" : "A",
197 | "name" : "AWPProductOnMapView",
198 | "suffix" : ""
199 | }
200 | },
201 | "identity" : {
202 | "address" : "0x4dc85a0",
203 | "className" : "NSLayoutConstraint",
204 | "color" : "rgb(26,188,156)",
205 | "initial" : "N",
206 | "name" : "NSLayoutConstraint"
207 | },
208 | "relation" : "==",
209 | "second" : {
210 | "attribute" : {
211 | "includesMargin" : false,
212 | "name" : "bottom"
213 | },
214 | "instance" : {
215 | "address" : "0x4db5710",
216 | "className" : "UIView",
217 | "color" : "rgb(245,215,110)",
218 | "initial" : "V",
219 | "name" : "View",
220 | "suffix" : ""
221 | }
222 | }
223 | },
224 | {
225 | "description" : "View<\/code>'s top edge should equal AWPProductOnMapView<\/code>'s top edge.",
226 | "first" : {
227 | "attribute" : {
228 | "includesMargin" : false,
229 | "name" : "top"
230 | },
231 | "instance" : {
232 | "address" : "0x4db5710",
233 | "className" : "UIView",
234 | "color" : "rgb(245,215,110)",
235 | "initial" : "V",
236 | "name" : "View",
237 | "suffix" : ""
238 | }
239 | },
240 | "identity" : {
241 | "address" : "0x4dc8630",
242 | "className" : "NSLayoutConstraint",
243 | "color" : "rgb(26,188,156)",
244 | "initial" : "N",
245 | "name" : "NSLayoutConstraint"
246 | },
247 | "relation" : "==",
248 | "second" : {
249 | "attribute" : {
250 | "includesMargin" : false,
251 | "name" : "top"
252 | },
253 | "instance" : {
254 | "address" : "0x4dbb090",
255 | "className" : "AWPProductOnMapView",
256 | "color" : "rgb(155,89,182)",
257 | "initial" : "A",
258 | "name" : "AWPProductOnMapView",
259 | "suffix" : ""
260 | }
261 | }
262 | }
263 | ],
264 | "footnotes" : [
265 |
266 | ]
267 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testGitHubIssues.6.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "value" : "86"
6 | },
7 | "description" : "View<\/code>'s height should equal 86.",
8 | "first" : {
9 | "attribute" : {
10 | "includesMargin" : false,
11 | "name" : "height"
12 | },
13 | "instance" : {
14 | "address" : "0x10f754f20",
15 | "className" : "UIView",
16 | "color" : "rgb(39,174,96)",
17 | "initial" : "V",
18 | "name" : "View",
19 | "suffix" : ""
20 | }
21 | },
22 | "footnote" : {
23 | "marker" : "*",
24 | "text" : "This constraint was translated from an autoresizing mask. If this was not intended, try setting translatesAutoresizingMaskIntoConstraints<\/code> to false on this view."
25 | },
26 | "identity" : {
27 | "address" : "0x283c8f570",
28 | "className" : "NSAutoresizingMaskLayoutConstraint",
29 | "color" : "rgb(26,188,156)",
30 | "initial" : "N",
31 | "name" : "NSAutoresizingMaskLayoutConstraint"
32 | },
33 | "relation" : "=="
34 | },
35 | {
36 | "description" : "Cancel<\/code>'s top edge should equal View<\/code>'s top edge.",
37 | "first" : {
38 | "attribute" : {
39 | "includesMargin" : false,
40 | "name" : "top"
41 | },
42 | "instance" : {
43 | "address" : "0x10f755100",
44 | "className" : "UIButton",
45 | "color" : "rgb(142,68,173)",
46 | "identifier" : "Cancel",
47 | "initial" : "C",
48 | "name" : "Cancel",
49 | "suffix" : ""
50 | }
51 | },
52 | "identity" : {
53 | "address" : "0x283c8c820",
54 | "className" : "NSLayoutConstraint",
55 | "color" : "rgb(26,188,156)",
56 | "initial" : "N",
57 | "name" : "NSLayoutConstraint"
58 | },
59 | "relation" : "==",
60 | "second" : {
61 | "attribute" : {
62 | "includesMargin" : false,
63 | "name" : "top"
64 | },
65 | "instance" : {
66 | "address" : "0x10f754f20",
67 | "className" : "UIView",
68 | "color" : "rgb(39,174,96)",
69 | "initial" : "V",
70 | "name" : "View",
71 | "suffix" : ""
72 | }
73 | }
74 | },
75 | {
76 | "constant" : {
77 | "value" : "52"
78 | },
79 | "description" : "Cancel<\/code>'s height should equal 52.",
80 | "first" : {
81 | "attribute" : {
82 | "includesMargin" : false,
83 | "name" : "height"
84 | },
85 | "instance" : {
86 | "address" : "0x10f755100",
87 | "className" : "UIButton",
88 | "color" : "rgb(142,68,173)",
89 | "identifier" : "Cancel",
90 | "initial" : "C",
91 | "name" : "Cancel",
92 | "suffix" : ""
93 | }
94 | },
95 | "identity" : {
96 | "address" : "0x283c8c870",
97 | "className" : "NSLayoutConstraint",
98 | "color" : "rgb(26,188,156)",
99 | "initial" : "N",
100 | "name" : "NSLayoutConstraint"
101 | },
102 | "relation" : "=="
103 | },
104 | {
105 | "description" : "UIViewLayoutMarginsGuide<\/code>'s bottom edge should equal Cancel<\/code>'s bottom edge.",
106 | "first" : {
107 | "attribute" : {
108 | "includesMargin" : false,
109 | "name" : "bottom"
110 | },
111 | "instance" : {
112 | "address" : "0x2826f9880",
113 | "className" : "UILayoutGuide",
114 | "color" : "rgb(211,84,0)",
115 | "identifier" : "UIViewLayoutMarginsGuide",
116 | "initial" : "U",
117 | "name" : "UIViewLayoutMarginsGuide",
118 | "suffix" : ""
119 | }
120 | },
121 | "identity" : {
122 | "address" : "0x283c8c8c0",
123 | "className" : "NSLayoutConstraint",
124 | "color" : "rgb(26,188,156)",
125 | "initial" : "N",
126 | "name" : "NSLayoutConstraint"
127 | },
128 | "relation" : "==",
129 | "second" : {
130 | "attribute" : {
131 | "includesMargin" : false,
132 | "name" : "bottom"
133 | },
134 | "instance" : {
135 | "address" : "0x10f755100",
136 | "className" : "UIButton",
137 | "color" : "rgb(142,68,173)",
138 | "identifier" : "Cancel",
139 | "initial" : "C",
140 | "name" : "Cancel",
141 | "suffix" : ""
142 | }
143 | }
144 | },
145 | {
146 | "constant" : {
147 | "prefix" : "+ ",
148 | "value" : "42"
149 | },
150 | "description" : "View<\/code>'s bottom edge should equal UIViewLayoutMarginsGuide<\/code>'s bottom edge plus 42.",
151 | "first" : {
152 | "attribute" : {
153 | "includesMargin" : false,
154 | "name" : "bottom"
155 | },
156 | "instance" : {
157 | "address" : "0x10f754f20",
158 | "className" : "UIView",
159 | "color" : "rgb(39,174,96)",
160 | "initial" : "V",
161 | "name" : "View",
162 | "suffix" : ""
163 | }
164 | },
165 | "identity" : {
166 | "address" : "0x283c8c730",
167 | "className" : "NSLayoutConstraint",
168 | "color" : "rgb(26,188,156)",
169 | "identifier" : "UIView-bottomMargin-guide-constraint",
170 | "initial" : "U",
171 | "name" : "UIView-bottomMargin-guide-constraint"
172 | },
173 | "relation" : "==",
174 | "second" : {
175 | "attribute" : {
176 | "includesMargin" : false,
177 | "name" : "bottom"
178 | },
179 | "instance" : {
180 | "address" : "0x2826f9880",
181 | "className" : "UILayoutGuide",
182 | "color" : "rgb(211,84,0)",
183 | "identifier" : "UIViewLayoutMarginsGuide",
184 | "initial" : "U",
185 | "name" : "UIViewLayoutMarginsGuide",
186 | "suffix" : ""
187 | }
188 | }
189 | }
190 | ],
191 | "footnotes" : [
192 | {
193 | "marker" : "*",
194 | "text" : "This constraint was translated from an autoresizing mask. If this was not intended, try setting translatesAutoresizingMaskIntoConstraints<\/code> to false on this view."
195 | }
196 | ]
197 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testGitHubIssues.7.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "prefix" : "+ ",
6 | "value" : "10"
7 | },
8 | "description" : "StackView<\/code>'s leading edge should equal LayoutGuide<\/code>'s leading edge plus 10.",
9 | "first" : {
10 | "attribute" : {
11 | "includesMargin" : false,
12 | "name" : "leading"
13 | },
14 | "instance" : {
15 | "address" : "0x7feb4e8d58b0",
16 | "className" : "App_Debug.StackView",
17 | "color" : "rgb(230,126,34)",
18 | "initial" : "S",
19 | "name" : "StackView",
20 | "suffix" : ""
21 | }
22 | },
23 | "identity" : {
24 | "address" : "0x7feb4e8fa260",
25 | "className" : "SnapKit.LayoutConstraint",
26 | "color" : "rgb(26,188,156)",
27 | "initial" : "L",
28 | "name" : "LayoutConstraint"
29 | },
30 | "relation" : "==",
31 | "second" : {
32 | "attribute" : {
33 | "includesMargin" : false,
34 | "name" : "leading"
35 | },
36 | "instance" : {
37 | "address" : "0x7feb50d2aa70",
38 | "className" : "UILayoutGuide",
39 | "color" : "rgb(245,215,110)",
40 | "initial" : "L",
41 | "name" : "LayoutGuide",
42 | "suffix" : ""
43 | }
44 | }
45 | }
46 | ],
47 | "footnotes" : [
48 |
49 | ]
50 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testGitHubIssues.9.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "prefix" : "+ ",
6 | "value" : "8"
7 | },
8 | "description" : "Label<\/code>'s top edge should be at least ClassName<\/code>'s top edge plus 8.",
9 | "first" : {
10 | "attribute" : {
11 | "includesMargin" : false,
12 | "name" : "top"
13 | },
14 | "instance" : {
15 | "address" : "0x111b35c20",
16 | "className" : "UILabel",
17 | "color" : "rgb(243,156,18)",
18 | "initial" : "L",
19 | "name" : "Label",
20 | "suffix" : ""
21 | }
22 | },
23 | "identity" : {
24 | "address" : "0x2828051d0",
25 | "className" : "_UISystemBaselineConstraint",
26 | "color" : "rgb(26,188,156)",
27 | "initial" : "U",
28 | "name" : "_UISystemBaselineConstraint"
29 | },
30 | "relation" : ">=",
31 | "second" : {
32 | "attribute" : {
33 | "includesMargin" : false,
34 | "name" : "top"
35 | },
36 | "instance" : {
37 | "address" : "0x111b35a60",
38 | "className" : "ModuleName.ClassName",
39 | "color" : "rgb(192,57,43)",
40 | "initial" : "C",
41 | "name" : "ClassName",
42 | "suffix" : ""
43 | }
44 | }
45 | },
46 | {
47 | "description" : "Label<\/code>'s vertical center should equal ClassName<\/code>'s vertical center.",
48 | "first" : {
49 | "attribute" : {
50 | "includesMargin" : false,
51 | "name" : "centerY"
52 | },
53 | "instance" : {
54 | "address" : "0x111b35c20",
55 | "className" : "UILabel",
56 | "color" : "rgb(243,156,18)",
57 | "initial" : "L",
58 | "name" : "Label",
59 | "suffix" : ""
60 | }
61 | },
62 | "identity" : {
63 | "address" : "0x282805130",
64 | "className" : "NSLayoutConstraint",
65 | "color" : "rgb(26,188,156)",
66 | "initial" : "N",
67 | "name" : "NSLayoutConstraint"
68 | },
69 | "relation" : "==",
70 | "second" : {
71 | "attribute" : {
72 | "includesMargin" : false,
73 | "name" : "centerY"
74 | },
75 | "instance" : {
76 | "address" : "0x111b35a60",
77 | "className" : "ModuleName.ClassName",
78 | "color" : "rgb(192,57,43)",
79 | "initial" : "C",
80 | "name" : "ClassName",
81 | "suffix" : ""
82 | }
83 | }
84 | },
85 | {
86 | "constant" : {
87 | "value" : "0"
88 | },
89 | "description" : "ClassName<\/code>'s height should equal 0.",
90 | "first" : {
91 | "attribute" : {
92 | "includesMargin" : false,
93 | "name" : "height"
94 | },
95 | "instance" : {
96 | "address" : "0x111b35a60",
97 | "className" : "ModuleName.ClassName",
98 | "color" : "rgb(192,57,43)",
99 | "initial" : "C",
100 | "name" : "ClassName",
101 | "suffix" : ""
102 | }
103 | },
104 | "footnote" : {
105 | "marker" : "†",
106 | "text" : "This constraint was added by a table or collection view to enforce its cell size."
107 | },
108 | "identity" : {
109 | "address" : "0x282803ed0",
110 | "className" : "NSLayoutConstraint",
111 | "color" : "rgb(26,188,156)",
112 | "identifier" : "UIView-Encapsulated-Layout-Height",
113 | "initial" : "U",
114 | "name" : "UIView-Encapsulated-Layout-Height"
115 | },
116 | "relation" : "=="
117 | }
118 | ],
119 | "footnotes" : [
120 | {
121 | "marker" : "†",
122 | "text" : "This constraint was added by a table or collection view to enforce its cell size."
123 | }
124 | ]
125 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testStackOverflowInputs.1.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "value" : "0"
6 | },
7 | "description" : "_UIButtonBarStackView<\/code>'s width should be at most 0.",
8 | "first" : {
9 | "attribute" : {
10 | "includesMargin" : false,
11 | "name" : "width"
12 | },
13 | "instance" : {
14 | "address" : "0x7fb573cebf90",
15 | "className" : "_UIButtonBarStackView",
16 | "color" : "rgb(155,89,182)",
17 | "initial" : "U",
18 | "name" : "_UIButtonBarStackView",
19 | "suffix" : ""
20 | }
21 | },
22 | "identity" : {
23 | "address" : "0x610000099cd0",
24 | "className" : "NSLayoutConstraint",
25 | "color" : "rgb(26,188,156)",
26 | "initial" : "N",
27 | "name" : "NSLayoutConstraint"
28 | },
29 | "relation" : "<="
30 | },
31 | {
32 | "constant" : {
33 | "prefix" : "+ ",
34 | "value" : "15"
35 | },
36 | "description" : "UIViewLayoutMarginsGuide<\/code>'s leading edge should equal _UIButtonBarStackView<\/code>'s leading edge plus 15.",
37 | "first" : {
38 | "attribute" : {
39 | "includesMargin" : false,
40 | "name" : "leading"
41 | },
42 | "instance" : {
43 | "address" : "0x61000038ce60",
44 | "className" : "UILayoutGuide",
45 | "color" : "rgb(230,126,34)",
46 | "identifier" : "UIViewLayoutMarginsGuide",
47 | "initial" : "U",
48 | "name" : "UIViewLayoutMarginsGuide",
49 | "suffix" : ""
50 | }
51 | },
52 | "identity" : {
53 | "address" : "0x610000098ec0",
54 | "className" : "NSLayoutConstraint",
55 | "color" : "rgb(26,188,156)",
56 | "identifier" : "UIView-leftMargin-guide-constraint",
57 | "initial" : "U",
58 | "name" : "UIView-leftMargin-guide-constraint"
59 | },
60 | "relation" : "==",
61 | "second" : {
62 | "attribute" : {
63 | "includesMargin" : false,
64 | "name" : "leading"
65 | },
66 | "instance" : {
67 | "address" : "0x7fb573cebf90",
68 | "className" : "_UIButtonBarStackView",
69 | "color" : "rgb(155,89,182)",
70 | "initial" : "U",
71 | "name" : "_UIButtonBarStackView",
72 | "suffix" : ""
73 | }
74 | }
75 | },
76 | {
77 | "constant" : {
78 | "prefix" : "+ ",
79 | "value" : "15"
80 | },
81 | "description" : "_UIButtonBarStackView<\/code>'s trailing edge should equal UIViewLayoutMarginsGuide<\/code>'s trailing edge plus 15.",
82 | "first" : {
83 | "attribute" : {
84 | "includesMargin" : false,
85 | "name" : "trailing"
86 | },
87 | "instance" : {
88 | "address" : "0x7fb573cebf90",
89 | "className" : "_UIButtonBarStackView",
90 | "color" : "rgb(155,89,182)",
91 | "initial" : "U",
92 | "name" : "_UIButtonBarStackView",
93 | "suffix" : ""
94 | }
95 | },
96 | "identity" : {
97 | "address" : "0x610000099000",
98 | "className" : "NSLayoutConstraint",
99 | "color" : "rgb(26,188,156)",
100 | "identifier" : "UIView-rightMargin-guide-constraint",
101 | "initial" : "U",
102 | "name" : "UIView-rightMargin-guide-constraint"
103 | },
104 | "relation" : "==",
105 | "second" : {
106 | "attribute" : {
107 | "includesMargin" : false,
108 | "name" : "trailing"
109 | },
110 | "instance" : {
111 | "address" : "0x61000038ce60",
112 | "className" : "UILayoutGuide",
113 | "color" : "rgb(230,126,34)",
114 | "identifier" : "UIViewLayoutMarginsGuide",
115 | "initial" : "U",
116 | "name" : "UIViewLayoutMarginsGuide",
117 | "suffix" : ""
118 | }
119 | }
120 | }
121 | ],
122 | "footnotes" : [
123 |
124 | ]
125 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testStackOverflowInputs.2.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "prefix" : "+ ",
6 | "value" : "13"
7 | },
8 | "description" : "TagView<\/code>'s leading edge should equal QuestionDetailHearderView<\/code>'s leading edge plus 13.",
9 | "first" : {
10 | "attribute" : {
11 | "includesMargin" : false,
12 | "name" : "leading"
13 | },
14 | "instance" : {
15 | "address" : "0x103850290",
16 | "className" : "ZhiMa_iOS.TagView",
17 | "color" : "rgb(211,84,0)",
18 | "initial" : "T",
19 | "name" : "TagView",
20 | "suffix" : ""
21 | }
22 | },
23 | "identity" : {
24 | "address" : "0x1740b5ae0",
25 | "className" : "SnapKit.LayoutConstraint",
26 | "color" : "rgb(26,188,156)",
27 | "initial" : "L",
28 | "name" : "LayoutConstraint"
29 | },
30 | "relation" : "==",
31 | "second" : {
32 | "attribute" : {
33 | "includesMargin" : false,
34 | "name" : "leading"
35 | },
36 | "instance" : {
37 | "address" : "0x10384fed0",
38 | "className" : "ZhiMa_iOS.QuestionDetailHearderView",
39 | "color" : "rgb(26,188,156)",
40 | "initial" : "Q",
41 | "name" : "QuestionDetailHearderView",
42 | "suffix" : ""
43 | }
44 | }
45 | },
46 | {
47 | "constant" : {
48 | "prefix" : "- ",
49 | "value" : "13"
50 | },
51 | "description" : "TagView<\/code>'s trailing edge should equal QuestionDetailHearderView<\/code>'s trailing edge minus 13.",
52 | "first" : {
53 | "attribute" : {
54 | "includesMargin" : false,
55 | "name" : "trailing"
56 | },
57 | "instance" : {
58 | "address" : "0x103850290",
59 | "className" : "ZhiMa_iOS.TagView",
60 | "color" : "rgb(211,84,0)",
61 | "initial" : "T",
62 | "name" : "TagView",
63 | "suffix" : ""
64 | }
65 | },
66 | "identity" : {
67 | "address" : "0x1740b7e20",
68 | "className" : "SnapKit.LayoutConstraint",
69 | "color" : "rgb(26,188,156)",
70 | "initial" : "L",
71 | "name" : "LayoutConstraint"
72 | },
73 | "relation" : "==",
74 | "second" : {
75 | "attribute" : {
76 | "includesMargin" : false,
77 | "name" : "trailing"
78 | },
79 | "instance" : {
80 | "address" : "0x10384fed0",
81 | "className" : "ZhiMa_iOS.QuestionDetailHearderView",
82 | "color" : "rgb(26,188,156)",
83 | "initial" : "Q",
84 | "name" : "QuestionDetailHearderView",
85 | "suffix" : ""
86 | }
87 | }
88 | },
89 | {
90 | "constant" : {
91 | "value" : "0"
92 | },
93 | "description" : "QuestionDetailHearderView<\/code>'s width should equal 0.",
94 | "first" : {
95 | "attribute" : {
96 | "includesMargin" : false,
97 | "name" : "width"
98 | },
99 | "instance" : {
100 | "address" : "0x10384fed0",
101 | "className" : "ZhiMa_iOS.QuestionDetailHearderView",
102 | "color" : "rgb(26,188,156)",
103 | "initial" : "Q",
104 | "name" : "QuestionDetailHearderView",
105 | "suffix" : ""
106 | }
107 | },
108 | "footnote" : {
109 | "marker" : "†",
110 | "text" : "This constraint was added by a table or collection view to enforce its cell size."
111 | },
112 | "identity" : {
113 | "address" : "0x17009fcc0",
114 | "className" : "NSLayoutConstraint",
115 | "color" : "rgb(26,188,156)",
116 | "identifier" : "UIView-Encapsulated-Layout-Width",
117 | "initial" : "U",
118 | "name" : "UIView-Encapsulated-Layout-Width"
119 | },
120 | "relation" : "=="
121 | }
122 | ],
123 | "footnotes" : [
124 | {
125 | "marker" : "†",
126 | "text" : "This constraint was added by a table or collection view to enforce its cell size."
127 | }
128 | ]
129 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ParserTests/testStackOverflowInputs.4.json:
--------------------------------------------------------------------------------
1 | {
2 | "constraints" : [
3 | {
4 | "constant" : {
5 | "value" : "0"
6 | },
7 | "description" : "_UIButtonBarStackView<\/code>'s width should be at most 0.",
8 | "first" : {
9 | "attribute" : {
10 | "includesMargin" : false,
11 | "name" : "width"
12 | },
13 | "instance" : {
14 | "address" : "0x7fb573cebf90",
15 | "className" : "_UIButtonBarStackView",
16 | "color" : "rgb(155,89,182)",
17 | "initial" : "U",
18 | "name" : "_UIButtonBarStackView",
19 | "suffix" : ""
20 | }
21 | },
22 | "identity" : {
23 | "address" : "0x610000099cd0",
24 | "className" : "NSLayoutConstraint",
25 | "color" : "rgb(26,188,156)",
26 | "initial" : "N",
27 | "name" : "NSLayoutConstraint"
28 | },
29 | "relation" : "<="
30 | },
31 | {
32 | "constant" : {
33 | "prefix" : "+ ",
34 | "value" : "15"
35 | },
36 | "description" : "UIViewLayoutMarginsGuide<\/code>'s leading edge should equal _UIButtonBarStackView<\/code>'s leading edge plus 15.",
37 | "first" : {
38 | "attribute" : {
39 | "includesMargin" : false,
40 | "name" : "leading"
41 | },
42 | "instance" : {
43 | "address" : "0x61000038ce60",
44 | "className" : "UILayoutGuide",
45 | "color" : "rgb(230,126,34)",
46 | "identifier" : "UIViewLayoutMarginsGuide",
47 | "initial" : "U",
48 | "name" : "UIViewLayoutMarginsGuide",
49 | "suffix" : ""
50 | }
51 | },
52 | "identity" : {
53 | "address" : "0x610000098ec0",
54 | "className" : "NSLayoutConstraint",
55 | "color" : "rgb(26,188,156)",
56 | "identifier" : "UIView-leftMargin-guide-constraint",
57 | "initial" : "U",
58 | "name" : "UIView-leftMargin-guide-constraint"
59 | },
60 | "relation" : "==",
61 | "second" : {
62 | "attribute" : {
63 | "includesMargin" : false,
64 | "name" : "leading"
65 | },
66 | "instance" : {
67 | "address" : "0x7fb573cebf90",
68 | "className" : "_UIButtonBarStackView",
69 | "color" : "rgb(155,89,182)",
70 | "initial" : "U",
71 | "name" : "_UIButtonBarStackView",
72 | "suffix" : ""
73 | }
74 | }
75 | },
76 | {
77 | "constant" : {
78 | "prefix" : "+ ",
79 | "value" : "15"
80 | },
81 | "description" : "_UIButtonBarStackView<\/code>'s trailing edge should equal UIViewLayoutMarginsGuide<\/code>'s trailing edge plus 15.",
82 | "first" : {
83 | "attribute" : {
84 | "includesMargin" : false,
85 | "name" : "trailing"
86 | },
87 | "instance" : {
88 | "address" : "0x7fb573cebf90",
89 | "className" : "_UIButtonBarStackView",
90 | "color" : "rgb(155,89,182)",
91 | "initial" : "U",
92 | "name" : "_UIButtonBarStackView",
93 | "suffix" : ""
94 | }
95 | },
96 | "identity" : {
97 | "address" : "0x610000099000",
98 | "className" : "NSLayoutConstraint",
99 | "color" : "rgb(26,188,156)",
100 | "identifier" : "UIView-rightMargin-guide-constraint",
101 | "initial" : "U",
102 | "name" : "UIView-rightMargin-guide-constraint"
103 | },
104 | "relation" : "==",
105 | "second" : {
106 | "attribute" : {
107 | "includesMargin" : false,
108 | "name" : "trailing"
109 | },
110 | "instance" : {
111 | "address" : "0x61000038ce60",
112 | "className" : "UILayoutGuide",
113 | "color" : "rgb(230,126,34)",
114 | "identifier" : "UIViewLayoutMarginsGuide",
115 | "initial" : "U",
116 | "name" : "UIViewLayoutMarginsGuide",
117 | "suffix" : ""
118 | }
119 | }
120 | }
121 | ],
122 | "footnotes" : [
123 |
124 | ]
125 | }
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ViewTests/testAbout.1.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | content-type: text/html; charset=utf-8
3 | content-length: 5475
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | WTF Auto Layout?
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
71 |
72 |
73 |
74 |
75 |
76 |
70 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | Why The Failure,
Auto Layout?
86 |
87 |
88 |
89 |
90 |
91 |
92 |
102 | Auto Layout on iOS and macOS is awesome. But when it goes wrong, the error logs are a pain to decipher.
103 |
104 |
105 | This site helps you visualize the conflicting constraints in the logs. It was built using Swift, Vapor and Sparse; and the source code is available on GitHub. If you found it useful, please give it a star.
106 |
107 |
108 |
109 |
110 |
101 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ViewTests/testHome.1.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | content-type: text/html; charset=utf-8
3 | content-length: 4417
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | WTF Auto Layout?
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
71 |
72 |
73 |
74 |
75 |
76 |
70 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | Why The Failure,
Auto Layout?
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ViewTests/testPostError.1.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | content-type: text/html; charset=utf-8
3 | content-length: 4926
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | WTF Auto Layout?
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
71 |
72 |
73 |
74 |
75 |
76 |
70 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | Why The Failure,
Auto Layout?
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
100 |
101 | Line 2, Column 26
102 | "<NSLayoutConstraint:0x61h00099cd0 _UIButtonBarStackView:0x7fb573cxbf90.width <= 0 (active)>"
103 | ~~~~~~~~~~~~~~~~~~~~~~~~~^
104 | Expected: hexit in constraint instance.memory address
105 | Expected: '@' in constraint instance.file location
106 | Expected: whitespace in constraint instance
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/Tests/AppTests/__Snapshots__/ViewTests/testPostError.2.txt:
--------------------------------------------------------------------------------
1 | HTTP/1.1 200 OK
2 | content-type: text/html; charset=utf-8
3 | content-length: 4749
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | WTF Auto Layout?
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
71 |
72 |
73 |
74 |
75 |
76 |
70 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | Why The Failure,
Auto Layout?
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
100 |
101 | INVALID CONSTRAINT:
102 | Missing info for ListViewImage-a....
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | #if os(Linux)
2 |
3 | import XCTest
4 | @testable import AppTests
5 |
6 | XCTMain([
7 | testCase(ParserTests.allTests),
8 | testCase(ViewTests.allTests),
9 | testCase(ColorTests.allTests)
10 | ])
11 |
12 | #endif
13 |
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | jobs:
4 | linux:
5 | docker:
6 | - image: swift:4.1
7 | steps:
8 | - checkout
9 | - run:
10 | name: Compile code
11 | command: swift build
12 | - run:
13 | name: Run unit tests
14 | command: swift test
15 |
16 | linux-release:
17 | docker:
18 | - image: swift:4.1
19 | steps:
20 | - checkout
21 | - run:
22 | name: Compile code with optimizations
23 | command: swift build -c release
24 |
25 | workflows:
26 | version: 2
27 | tests:
28 | jobs:
29 | - linux
30 | - linux-release
31 |
32 | nightly:
33 | triggers:
34 | - schedule:
35 | cron: "0 0 * * *"
36 | filters:
37 | branches:
38 | only:
39 | - master
40 | jobs:
41 | - linux
42 | - linux-release
43 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Qutheory, LLC
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------